Skip to content

Commit 170ba44

Browse files
committed
Improve hashJSObj to work around IE8 bugs by exploiting IE8. This now allows DOM nodes to be used as keys without leaking memory and ensures the hash key is never enumerable so it doesnt mess up serializing to JSON
1 parent d5e57c3 commit 170ba44

File tree

3 files changed

+126
-45
lines changed

3 files changed

+126
-45
lines changed

dist/Immutable.js

+46-13
Original file line numberDiff line numberDiff line change
@@ -144,33 +144,66 @@ function hashString(string) {
144144
return hash;
145145
}
146146
function hashJSObj(obj) {
147-
if (obj[UID_HASH_KEY]) {
148-
return obj[UID_HASH_KEY];
149-
}
150-
var uid = ++UID_HASH_COUNT & HASH_MAX_VAL;
151-
if (!isIE8) {
152-
try {
147+
var hash = obj[UID_HASH_KEY];
148+
if (hash)
149+
return hash;
150+
if (!canDefineProperty) {
151+
hash = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
152+
if (hash)
153+
return hash;
154+
hash = getIENodeHash(obj);
155+
if (hash)
156+
return hash;
157+
}
158+
if (!canDefineProperty || Object.isExtensible(obj)) {
159+
hash = ++UID_HASH_COUNT & HASH_MAX_VAL;
160+
if (canDefineProperty) {
153161
Object.defineProperty(obj, UID_HASH_KEY, {
154162
'enumerable': false,
155163
'configurable': false,
156164
'writable': false,
157-
'value': uid
165+
'value': hash
158166
});
159-
return uid;
160-
} catch (e) {
161-
isIE8 = true;
167+
} else if (obj.propertyIsEnumerable === propertyIsEnumerable) {
168+
obj.propertyIsEnumerable = function() {
169+
return Object.prototype.propertyIsEnumerable.apply(this, arguments);
170+
};
171+
obj.propertyIsEnumerable[UID_HASH_KEY] = hash;
172+
} else if (obj.nodeType) {
173+
obj[UID_HASH_KEY] = hash;
174+
} else {
175+
throw new Error('Unable to set a non-enumerable property on object.');
176+
}
177+
return hash;
178+
} else {
179+
throw new Error('Non-extensible objects are not allowed as keys.');
180+
}
181+
}
182+
var propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
183+
var canDefineProperty = (function() {
184+
try {
185+
Object.defineProperty({}, 'x', {});
186+
return true;
187+
} catch (e) {
188+
return false;
189+
}
190+
}());
191+
function getIENodeHash(node) {
192+
if (node && node.nodeType > 0) {
193+
switch (node.nodeType) {
194+
case 1:
195+
return node.uniqueID;
196+
case 9:
197+
return node.documentElement && node.documentElement.uniqueID;
162198
}
163199
}
164-
obj[UID_HASH_KEY] = uid;
165-
return uid;
166200
}
167201
var HASH_MAX_VAL = 0x7FFFFFFF;
168202
var UID_HASH_COUNT = 0;
169203
var UID_HASH_KEY = '__immutablehash__';
170204
if (typeof Symbol !== 'undefined') {
171205
UID_HASH_KEY = Symbol(UID_HASH_KEY);
172206
}
173-
var isIE8 = false;
174207
var STRING_HASH_CACHE_MIN_STRLEN = 16;
175208
var STRING_HASH_CACHE_MAX_SIZE = 255;
176209
var STRING_HASH_CACHE_SIZE = 0;

0 commit comments

Comments
 (0)