mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-09 02:17:50 +00:00
Ensure _.keys and _.keysIn always skip the constructor property on prototype objects.
This commit is contained in:
15
lodash.js
15
lodash.js
@@ -6572,8 +6572,11 @@
|
|||||||
* // => ['x', 'y'] (property order is not guaranteed across environments)
|
* // => ['x', 'y'] (property order is not guaranteed across environments)
|
||||||
*/
|
*/
|
||||||
var keys = !nativeKeys ? shimKeys : function(object) {
|
var keys = !nativeKeys ? shimKeys : function(object) {
|
||||||
var length = object ? object.length : 0;
|
var ctor = object && object.constructor,
|
||||||
if (typeof length == 'number' && length > 0) {
|
length = object ? object.length : 0;
|
||||||
|
|
||||||
|
if (typeof length == 'number' && length > 0 ||
|
||||||
|
(ctor && object === ctor.prototype)) {
|
||||||
return shimKeys(object);
|
return shimKeys(object);
|
||||||
}
|
}
|
||||||
return isObject(object) ? nativeKeys(object) : [];
|
return isObject(object) ? nativeKeys(object) : [];
|
||||||
@@ -6609,7 +6612,9 @@
|
|||||||
(support.nonEnumArgs && isArguments(object))) && length) >>> 0;
|
(support.nonEnumArgs && isArguments(object))) && length) >>> 0;
|
||||||
|
|
||||||
var keyIndex,
|
var keyIndex,
|
||||||
|
ctor = object.constructor,
|
||||||
index = -1,
|
index = -1,
|
||||||
|
isProto = ctor && object === ctor.prototype,
|
||||||
maxIndex = length - 1,
|
maxIndex = length - 1,
|
||||||
result = Array(length),
|
result = Array(length),
|
||||||
skipIndexes = length > 0,
|
skipIndexes = length > 0,
|
||||||
@@ -6620,7 +6625,8 @@
|
|||||||
result[index] = String(index);
|
result[index] = String(index);
|
||||||
}
|
}
|
||||||
for (var key in object) {
|
for (var key in object) {
|
||||||
if (!(skipProto && key == 'prototype') &&
|
if (!(isProto && key == 'constructor') &&
|
||||||
|
!(skipProto && key == 'prototype') &&
|
||||||
!(skipErrorProps && (key == 'message' || key == 'name')) &&
|
!(skipErrorProps && (key == 'message' || key == 'name')) &&
|
||||||
!(skipIndexes && (keyIndex = +key, keyIndex > -1 && keyIndex <= maxIndex && keyIndex % 1 == 0))) {
|
!(skipIndexes && (keyIndex = +key, keyIndex > -1 && keyIndex <= maxIndex && keyIndex % 1 == 0))) {
|
||||||
result.push(key);
|
result.push(key);
|
||||||
@@ -6631,11 +6637,10 @@
|
|||||||
// attribute of an existing property and the `constructor` property of a
|
// attribute of an existing property and the `constructor` property of a
|
||||||
// prototype defaults to non-enumerable.
|
// prototype defaults to non-enumerable.
|
||||||
if (support.nonEnumShadows && object !== objectProto) {
|
if (support.nonEnumShadows && object !== objectProto) {
|
||||||
var ctor = object.constructor;
|
|
||||||
index = -1;
|
index = -1;
|
||||||
length = shadowedProps.length;
|
length = shadowedProps.length;
|
||||||
|
|
||||||
if (object === (ctor && ctor.prototype)) {
|
if (isProto) {
|
||||||
var className = object === stringProto ? stringClass : object === errorProto ? errorClass : toString.call(object),
|
var className = object === stringProto ? stringClass : object === errorProto ? errorClass : toString.call(object),
|
||||||
nonEnum = nonEnumProps[className];
|
nonEnum = nonEnumProps[className];
|
||||||
}
|
}
|
||||||
|
|||||||
25
test/test.js
25
test/test.js
@@ -5493,23 +5493,16 @@
|
|||||||
delete String.prototype.a;
|
delete String.prototype.a;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('`_.' + methodName + '` fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 2, function() {
|
test('`_.' + methodName + '` fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() {
|
||||||
function Foo() {}
|
var actual = func(shadowedObject);
|
||||||
Foo.prototype.a = 1;
|
|
||||||
|
|
||||||
var actual = func(Foo.prototype);
|
|
||||||
deepEqual(actual, ['a']);
|
|
||||||
|
|
||||||
actual = func(shadowedObject);
|
|
||||||
deepEqual(actual.sort(), shadowedProps);
|
deepEqual(actual.sort(), shadowedProps);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
|
test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
|
||||||
function Foo() {}
|
function Foo() {}
|
||||||
Foo.prototype.c = 3;
|
|
||||||
|
|
||||||
Foo.a = 1;
|
Foo.a = 1;
|
||||||
Foo.b = 2;
|
Foo.b = 2;
|
||||||
|
Foo.prototype.c = 3;
|
||||||
|
|
||||||
var expected = ['a', 'b'],
|
var expected = ['a', 'b'],
|
||||||
actual = func(Foo);
|
actual = func(Foo);
|
||||||
@@ -5518,10 +5511,20 @@
|
|||||||
|
|
||||||
Foo.prototype = { 'c': 3 };
|
Foo.prototype = { 'c': 3 };
|
||||||
actual = func(Foo);
|
actual = func(Foo);
|
||||||
|
|
||||||
deepEqual(actual.sort(), expected);
|
deepEqual(actual.sort(), expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('`_.' + methodName + '` skips the `constructor` property on prototype objects', 2, function() {
|
||||||
|
function Foo() {}
|
||||||
|
Foo.prototype.a = 1;
|
||||||
|
|
||||||
|
var expected = ['a'];
|
||||||
|
deepEqual(func(Foo.prototype), ['a']);
|
||||||
|
|
||||||
|
Foo.prototype = { 'constructor': Foo, 'a': 1 };
|
||||||
|
deepEqual(func(Foo.prototype), ['a']);
|
||||||
|
});
|
||||||
|
|
||||||
test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties', 1, function() {
|
test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties', 1, function() {
|
||||||
function Foo() {
|
function Foo() {
|
||||||
this.a = 1;
|
this.a = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user