Avoid a hasOwnProperty bug in IE 10-11 where objects with a [[Prototype]] of null incorrectly report false for own index properties.

This commit is contained in:
John-David Dalton
2015-10-01 22:16:13 -07:00
parent b3f6426d36
commit 9558048906
2 changed files with 39 additions and 20 deletions

View File

@@ -2322,7 +2322,13 @@
* @returns {boolean} Returns `true` if `key` exists, else `false`. * @returns {boolean} Returns `true` if `key` exists, else `false`.
*/ */
function baseHas(object, key) { function baseHas(object, key) {
return object != null && hasOwnProperty.call(object, key); if (object == null) {
return false;
}
// Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`
// incorrectly report `false` for own index properties.
return hasOwnProperty.call(object, key) ||
(typeof object == 'object' && key in object && getPrototypeOf(object) === null);
} }
/** /**
@@ -3984,7 +3990,7 @@
var index = objLength; var index = objLength;
while (index--) { while (index--) {
var key = objProps[index]; var key = objProps[index];
if (!(isPartial ? key in other : hasOwnProperty.call(other, key)) || if (!(isPartial ? key in other : baseHas(other, key)) ||
!(isUnordered || key == othProps[index])) { !(isUnordered || key == othProps[index])) {
return false; return false;
} }
@@ -9941,7 +9947,7 @@
skipIndexes = !!length; skipIndexes = !!length;
for (var key in object) { for (var key in object) {
if (hasOwnProperty.call(object, key) && if (baseHas(object, key) &&
!(skipIndexes && isIndex(key, length)) && !(skipIndexes && isIndex(key, length)) &&
!(isProto && key == 'constructor')) { !(isProto && key == 'constructor')) {
result.push(key); result.push(key);

View File

@@ -6341,17 +6341,7 @@
}); });
}); });
QUnit.test('`_.' + methodName + '` should work with non-string `path` arguments', function(assert) { QUnit.test('`_.' + methodName + '` should coerce `path` to a string', function(assert) {
assert.expect(2);
var array = [1, 2, 3];
_.each([1, [1]], function(path) {
assert.strictEqual(func(array, path), true);
});
});
QUnit.test('`_.' + methodName + '` should coerce key to a string', function(assert) {
assert.expect(1); assert.expect(1);
function fn() {} function fn() {}
@@ -6389,12 +6379,6 @@
assert.strictEqual(func(Array(1), 0), true); assert.strictEqual(func(Array(1), 0), true);
}); });
QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) {
assert.expect(1);
assert.strictEqual(func(args, 1), true);
});
QUnit.test('`_.' + methodName + '` should check for a key over a path', function(assert) { QUnit.test('`_.' + methodName + '` should check for a key over a path', function(assert) {
assert.expect(2); assert.expect(2);
@@ -6444,6 +6428,35 @@
assert.strictEqual(func(object, path), false); assert.strictEqual(func(object, path), false);
}); });
}); });
QUnit.test('`_.' + methodName + '` should work with non-string `path` arguments', function(assert) {
assert.expect(2);
var array = [1, 2, 3];
_.each([1, [1]], function(path) {
assert.strictEqual(func(array, path), true);
});
});
QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) {
assert.expect(1);
assert.strictEqual(func(args, 1), true);
});
QUnit.test('`_.' + methodName + '` should work for objects with a `[[Prototype]]` of `null`', function(assert) {
assert.expect(1);
if (create) {
var object = create(null);
object[1] = 'a';
assert.strictEqual(func(object, 1), true);
}
else {
skipTest(assert);
}
});
}); });
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/