Skip to content

Instantly share code, notes, and snippets.

@brettz9
Created August 28, 2013 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brettz9/6367532 to your computer and use it in GitHub Desktop.
Save brettz9/6367532 to your computer and use it in GitHub Desktop.
// Based on work by John-David Dalton, Juriy Zaytsev, and Asen Bozhilov.
Object.forEach = (function () {
// Convenience aliases.
var toString = {}.toString, hasOwnProperty = {}.hasOwnProperty ||
// Simulate `Object#hasOwnProperty` in Safari 2.
function (property) {
// Save the original prototype chain.
var original = this.__proto__, result;
// Break the prototype chain.
this.__proto__ = null;
result = property in this;
// Restore the prototype chain.
this.__proto__ = original;
return result;
}, forEach;
// The `Properties` constructor tests for bugs in the `for...in` algorithm.
function Properties() {
this.toString = 1;
}
Properties.prototype.toString = 1;
// Create and iterate over a new instance of the `Properties` constructor.
var properties = new Properties, property, length = 0;
for (property in properties) {
if (hasOwnProperty.call(properties, property)) {
length++;
}
}
if (!length) {
// JScript ignores shadowed non-enumerable properties.
properties = ['constructor', 'toString', 'valueOf', 'isPrototypeOf',
'hasOwnProperty', 'propertyIsEnumerable', 'toLocaleString'];
forEach = function forEach(object, iterator, context) {
var index = 0, property;
for (property in object) {
if (hasOwnProperty.call(object, property) && iterator.call(context,
object[property], property, object) === false) {
break;
}
}
// Provide a workaround for the JScript bug.
while ((property = properties[index++])) {
if (hasOwnProperty.call(object, property) && iterator.call(context,
object[property], property, object) === false) {
break;
}
}
};
} else if (length == 2) {
// Safari 2 enumerates all shadowed and inherited properties.
forEach = function forEach(object, iterator, context) {
// The `prototype` property is handled inconsistently across browsers.
var isFunction = toString.call(object) == '[object Function]',
// Create a cache of iterated properties.
properties = {}, property;
for (property in object) {
// Skip the `prototype` property of functions.
if (!(isFunction && property == 'prototype') && !hasOwnProperty.call(
// Cache each property to prevent enumeration of inherited and shadowed
// properties.
properties, property) && (properties[property] = 1) &&
hasOwnProperty.call(object, property) && iterator.call(context,
object[property], property, object) === false) {
break;
}
}
};
} else {
forEach = function forEach(object, iterator, context) {
var isFunction = toString.call(object) == '[object Function]', property;
for (property in object) {
if (!(isFunction && property == 'prototype') && hasOwnProperty.call(
object, property) && iterator.call(context, object[property], property,
object) === false) {
break;
}
}
};
}
return forEach;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment