|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 module.metadata = { |
|
8 "stability": "unstable" |
|
9 }; |
|
10 |
|
11 const { flatten } = require('./array'); |
|
12 |
|
13 /** |
|
14 * Merges all the properties of all arguments into first argument. If two or |
|
15 * more argument objects have own properties with the same name, the property |
|
16 * is overridden, with precedence from right to left, implying, that properties |
|
17 * of the object on the left are overridden by a same named property of the |
|
18 * object on the right. |
|
19 * |
|
20 * Any argument given with "falsy" value - commonly `null` and `undefined` in |
|
21 * case of objects - are skipped. |
|
22 * |
|
23 * @examples |
|
24 * var a = { bar: 0, a: 'a' } |
|
25 * var b = merge(a, { foo: 'foo', bar: 1 }, { foo: 'bar', name: 'b' }); |
|
26 * b === a // true |
|
27 * b.a // 'a' |
|
28 * b.foo // 'bar' |
|
29 * b.bar // 1 |
|
30 * b.name // 'b' |
|
31 */ |
|
32 function merge(source) { |
|
33 let descriptor = {}; |
|
34 |
|
35 // `Boolean` converts the first parameter to a boolean value. Any object is |
|
36 // converted to `true` where `null` and `undefined` becames `false`. Therefore |
|
37 // the `filter` method will keep only objects that are defined and not null. |
|
38 Array.slice(arguments, 1).filter(Boolean).forEach(function onEach(properties) { |
|
39 Object.getOwnPropertyNames(properties).forEach(function(name) { |
|
40 descriptor[name] = Object.getOwnPropertyDescriptor(properties, name); |
|
41 }); |
|
42 }); |
|
43 return Object.defineProperties(source, descriptor); |
|
44 } |
|
45 exports.merge = merge; |
|
46 |
|
47 /** |
|
48 * Returns an object that inherits from the first argument and contains all the |
|
49 * properties from all following arguments. |
|
50 * `extend(source1, source2, source3)` is equivalent of |
|
51 * `merge(Object.create(source1), source2, source3)`. |
|
52 */ |
|
53 function extend(source) { |
|
54 let rest = Array.slice(arguments, 1); |
|
55 rest.unshift(Object.create(source)); |
|
56 return merge.apply(null, rest); |
|
57 } |
|
58 exports.extend = extend; |
|
59 |
|
60 function has(obj, key) obj.hasOwnProperty(key); |
|
61 exports.has = has; |
|
62 |
|
63 function each(obj, fn) { |
|
64 for (let key in obj) has(obj, key) && fn(obj[key], key, obj); |
|
65 } |
|
66 exports.each = each; |
|
67 |
|
68 /** |
|
69 * Like `merge`, except no property descriptors are manipulated, for use |
|
70 * with platform objects. Identical to underscore's `extend`. Useful for |
|
71 * merging XPCOM objects |
|
72 */ |
|
73 function safeMerge(source) { |
|
74 Array.slice(arguments, 1).forEach(function onEach (obj) { |
|
75 for (let prop in obj) source[prop] = obj[prop]; |
|
76 }); |
|
77 return source; |
|
78 } |
|
79 exports.safeMerge = safeMerge; |
|
80 |
|
81 /* |
|
82 * Returns a copy of the object without blacklisted properties |
|
83 */ |
|
84 function omit(source, ...values) { |
|
85 let copy = {}; |
|
86 let keys = flatten(values); |
|
87 for (let prop in source) |
|
88 if (!~keys.indexOf(prop)) |
|
89 copy[prop] = source[prop]; |
|
90 return copy; |
|
91 } |
|
92 exports.omit = omit; |