Optimize _.clone.

This commit is contained in:
John-David Dalton
2014-07-01 09:09:35 -07:00
parent caf31eb6d3
commit 6622922468
2 changed files with 74 additions and 50 deletions

114
lodash.js
View File

@@ -1353,46 +1353,80 @@
if (typeof result != 'undefined') { if (typeof result != 'undefined') {
return result; return result;
} }
var isObj = isObject(value); var isArr = isArray(value),
if (isObj) { isShallow = !isDeep;
if (isArr) {
result = isDeep ? value.constructor(value.length) : slice(value);
// add array properties assigned by `RegExp#exec`
if (typeof value[0] == 'string' && hasOwnProperty.call(value, 'index')) {
result.index = value.index;
result.input = value.input;
}
if (isShallow) {
return result;
}
}
else {
if (!isObject(value)) {
return value;
}
var className = toString.call(value); var className = toString.call(value);
if (!cloneableClasses[className] || (!support.nodeClass && isNode(value))) { if (!cloneableClasses[className] || (!support.nodeClass && isNode(value))) {
return value; return value;
} }
var isArgs = className == argsClass || (!support.argsClass && isArguments(value)),
isObj = !isArgs && className == objectClass;
if (isShallow && (isArgs || isObj)) {
result = baseAssign({}, value);
}
if (isShallow && isObj) {
return result;
}
var Ctor = value.constructor; var Ctor = value.constructor;
if (className == objectClass && !(isFunction(Ctor) && (Ctor instanceof Ctor))) { if (className == objectClass && !(isFunction(Ctor) && (Ctor instanceof Ctor))) {
Ctor = Object; Ctor = Object;
} }
switch (className) { if (isDeep && (isArgs || isObj)) {
case arrayBufferClass: result = new Ctor;
return cloneBuffer(value); }
else {
case boolClass: switch (className) {
case dateClass: case arrayBufferClass:
return new Ctor(+value); return cloneBuffer(value);
case float32Class: case float64Class: case boolClass:
case int8Class: case int16Class: case int32Class: case dateClass:
case uint8Class: case uint8ClampedClass: case uint16Class: case uint32Class: return new Ctor(+value);
// Safari 5 mobile incorrectly has `Object` as the constructor
if (Ctor instanceof Ctor) { case float32Class: case float64Class:
Ctor = ctorByClass[className]; case int8Class: case int16Class: case int32Class:
} case uint8Class: case uint8ClampedClass: case uint16Class: case uint32Class:
return new Ctor(cloneBuffer(value.buffer)); // Safari 5 mobile incorrectly has `Object` as the constructor
if (Ctor instanceof Ctor) {
case numberClass: Ctor = ctorByClass[className];
case stringClass: }
return new Ctor(value); return new Ctor(cloneBuffer(value.buffer));
case regexpClass: case numberClass:
result = Ctor(value.source, reFlags.exec(value)); case stringClass:
result.lastIndex = value.lastIndex; return new Ctor(value);
return result;
case regexpClass:
result = Ctor(value.source, reFlags.exec(value));
result.lastIndex = value.lastIndex;
return result;
}
} }
} else {
return value;
} }
var isArr = isArray(value); if (isArgs) {
result.length = value.length;
}
if (isShallow) {
return result;
}
if (isDeep) { if (isDeep) {
// check for circular references and return corresponding clone // check for circular references and return corresponding clone
stackA || (stackA = []); stackA || (stackA = []);
@@ -1404,26 +1438,6 @@
return stackB[length]; return stackB[length];
} }
} }
result = isArr ? Ctor(value.length) : new Ctor;
}
else {
result = isArr ? slice(value) : baseAssign({}, value);
}
if (className == argsClass || (!support.argsClass && isArguments(value))) {
result.length = value.length;
}
// add array properties assigned by `RegExp#exec`
else if (isArr) {
if (hasOwnProperty.call(value, 'index')) {
result.index = value.index;
}
if (hasOwnProperty.call(value, 'input')) {
result.input = value.input;
}
}
// exit for shallow clone
if (!isDeep) {
return result;
} }
// add the source value to the stack of traversed objects // add the source value to the stack of traversed objects
// and associate it with its clone // and associate it with its clone

View File

@@ -655,6 +655,16 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.clone` with an array')
.add(buildName, '\
lodash.clone(numbers)'
)
.add(otherName, '\
_.clone(numbers)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.clone` with an object') Benchmark.Suite('`_.clone` with an object')
.add(buildName, '\ .add(buildName, '\