forked from plotly/plotly.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextend.js
103 lines (84 loc) · 3.1 KB
/
extend.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
'use strict';
var isPlainObject = require('./is_plain_object.js');
var isArray = Array.isArray;
function primitivesLoopSplice(source, target) {
var i, value;
for(i = 0; i < source.length; i++) {
value = source[i];
if(value !== null && typeof(value) === 'object') {
return false;
}
if(value !== void(0)) {
target[i] = value;
}
}
return true;
}
exports.extendFlat = function() {
return _extend(arguments, false, false, false);
};
exports.extendDeep = function() {
return _extend(arguments, true, false, false);
};
exports.extendDeepAll = function() {
return _extend(arguments, true, true, false);
};
exports.extendDeepNoArrays = function() {
return _extend(arguments, true, false, true);
};
/*
* Inspired by https://github.com/justmoon/node-extend/blob/master/index.js
* All credit to the jQuery authors for perfecting this amazing utility.
*
* API difference with jQuery version:
* - No optional boolean (true -> deep extend) first argument,
* use `extendFlat` for first-level only extend and
* use `extendDeep` for a deep extend.
*
* Other differences with jQuery version:
* - Uses a modern (and faster) isPlainObject routine.
* - Expected to work with object {} and array [] arguments only.
* - Does not check for circular structure.
* FYI: jQuery only does a check across one level.
* Warning: this might result in infinite loops.
*
*/
function _extend(inputs, isDeep, keepAllKeys, noArrayCopies) {
var target = inputs[0];
var length = inputs.length;
var input, key, src, copy, copyIsArray, clone, allPrimitives;
// TODO does this do the right thing for typed arrays?
if(length === 2 && isArray(target) && isArray(inputs[1]) && target.length === 0) {
allPrimitives = primitivesLoopSplice(inputs[1], target);
if(allPrimitives) {
return target;
} else {
target.splice(0, target.length); // reset target and continue to next block
}
}
for(var i = 1; i < length; i++) {
input = inputs[i];
for(key in input) {
src = target[key];
copy = input[key];
if(noArrayCopies && isArray(copy)) {
// Stop early and just transfer the array if array copies are disallowed:
target[key] = copy;
} else if(isDeep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
// recurse if we're merging plain objects or arrays
if(copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
// never move original objects, clone them
target[key] = _extend([clone, copy], isDeep, keepAllKeys, noArrayCopies);
} else if(typeof copy !== 'undefined' || keepAllKeys) {
// don't bring in undefined values, except for extendDeepAll
target[key] = copy;
}
}
}
return target;
}