Skip to content

Commit d9aeeed

Browse files
Use Object.prototype.hasOwnProperty within Object.keys; also manually check for properties like toString to work around IE's DontEnum bug. (Andy Earnshaw, kangax, Andrew Dupont)
1 parent cc5752e commit d9aeeed

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/prototype/lang/object.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
(function() {
2323

2424
var _toString = Object.prototype.toString,
25+
_hasOwnProperty = Object.prototype.hasOwnProperty,
2526
NULL_TYPE = 'Null',
2627
UNDEFINED_TYPE = 'Undefined',
2728
BOOLEAN_TYPE = 'Boolean',
@@ -39,6 +40,21 @@
3940
JSON.stringify(0) === '0' &&
4041
typeof JSON.stringify(Prototype.K) === 'undefined';
4142

43+
44+
45+
var DONT_ENUMS = ['toString', 'toLocaleString', 'valueOf',
46+
'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
47+
48+
// Some versions of JScript fail to enumerate over properties, names of which
49+
// correspond to non-enumerable properties in the prototype chain
50+
var IS_DONTENUM_BUGGY = (function(){
51+
for (var p in { toString: 1 }) {
52+
// check actual property name, so that it works with augmented Object.prototype
53+
if (p === 'toString') return false;
54+
}
55+
return true;
56+
})();
57+
4258
function Type(o) {
4359
switch(o) {
4460
case null: return NULL_TYPE;
@@ -52,7 +68,7 @@
5268
}
5369
return OBJECT_TYPE;
5470
}
55-
71+
5672
/**
5773
* Object.extend(destination, source) -> Object
5874
* - destination (Object): The object to receive the new properties.
@@ -309,10 +325,18 @@
309325
if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
310326
var results = [];
311327
for (var property in object) {
312-
if (object.hasOwnProperty(property)) {
328+
if (_hasOwnProperty.call(object, property))
313329
results.push(property);
330+
}
331+
332+
// Account for the DontEnum properties in affected browsers.
333+
if (IS_DONTENUM_BUGGY) {
334+
for (var i = 0; property = DONT_ENUMS[i]; i++) {
335+
if (_hasOwnProperty.call(object, property))
336+
results.push(property);
314337
}
315338
}
339+
316340
return results;
317341
}
318342

test/unit/object_test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ new Test.Unit.Runner({
3131
Foo.prototype.foo = 'foo';
3232
this.assertEnumEqual(['bar'], Object.keys(new Foo()));
3333
this.assertRaise('TypeError', function(){ Object.keys() });
34+
35+
var obj = {
36+
foo: 'bar',
37+
baz: 'thud',
38+
toString: function() { return '1'; },
39+
valueOf: function() { return 1; }
40+
};
41+
42+
this.assertEqual(4, Object.keys(obj).length, 'DontEnum properties should be included in Object.keys');
3443
},
3544

3645
testObjectInspect: function() {

0 commit comments

Comments
 (0)