Created
October 30, 2015 16:09
-
-
Save ShirtlessKirk/f425d2764e82d8fc0d74 to your computer and use it in GitHub Desktop.
Object methods polyfill (partial)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global define: false, module: false */ | |
/*jslint forin: true, nomen: true, unparam: true */ | |
(function objectModule(definition) { // non-exporting module magic dance | |
'use strict'; | |
var | |
amd = 'amd', | |
exports = 'exports'; // keeps the method names for CommonJS / AMD from being compiled to single character variable | |
if (typeof define === 'function' && define[amd]) { | |
define(function definer() { | |
return definition(); | |
}); | |
} else if (typeof module === 'function' && module[exports]) { | |
module[exports] = definition(); | |
} else { | |
definition(); | |
} | |
}(function objectPolyfill() { | |
'use strict'; | |
var | |
definePropertyFn, | |
hasEnumBug = !({ toString: null}).propertyIsEnumerable('toString'), | |
hasOwnProperty, | |
notEnumerable = [ | |
'constructor', | |
'hasOwnProperty', | |
'isPrototypeOf', | |
'propertyIsEnumerable', | |
'toLocaleString', | |
'toString', | |
'valueOf' | |
], | |
propertyDefiners = [ | |
'get', | |
'set' | |
], | |
proto, | |
O = Object, | |
T; | |
function verifyObject(object, errorString) { | |
if (!object || ({}).valueOf.call(object) !== object) { | |
throw new T(errorString); | |
} | |
} | |
function createDescriptor(raw) { | |
var | |
counter, | |
descriptor, | |
key, | |
length; | |
verifyObject(raw, 'Descriptor is not an object'); | |
descriptor = {}; | |
for (counter = 0, length = propertyDefiners.length; counter < length; counter += 1) { | |
key = propertyDefiners[counter]; | |
if (hasOwnProperty.call(raw, key)) { | |
if (raw[key] === undefined || typeof raw[key] !== 'function') { | |
throw new T(key + ' is not a function'); | |
} | |
descriptor[key] = raw[key]; | |
descriptor.enumerable = false; // enumerable must be specifically set false (defaults to true) for accessor descriptors | |
} | |
} | |
if (hasOwnProperty.call(raw, 'value')) { | |
if (descriptor.get || descriptor.set) { | |
throw new T('Descriptor contains invalid properties'); | |
} | |
descriptor.value = raw.value; | |
} | |
return descriptor; | |
} | |
function defineProperty(object, name, property) { | |
if (arguments.length !== 3) { | |
throw new T('Object.defineProperty called with invalid number of arguments'); | |
} | |
var | |
descriptor; | |
verifyObject(object, 'Object.defineProperty called on non-object'); | |
verifyObject(property, 'Object.defineProperty called with invalid property descriptor'); | |
descriptor = createDescriptor(property); // clean up property descriptor | |
return definePropertyFn(object, name, descriptor); // run underlying defineProperty function | |
} | |
function preventExtensions(object) { | |
return object; | |
} | |
function isExtensible(object) { | |
return true; | |
} | |
function freeze(object) { | |
return object; | |
} | |
function isFrozen(object) { | |
return false; | |
} | |
function seal(object) { | |
return object; | |
} | |
function isSealed(object) { | |
return false; | |
} | |
function keysWrapper(returnNonEnumerables) { | |
var | |
length = notEnumerable.length; | |
function addEnumerables(array) { | |
var | |
key; | |
for (key in this) { | |
if (hasOwnProperty.call(this, key)) { | |
array.push(key); | |
} | |
} | |
} | |
function addNonEnumerables(array) { | |
var | |
counter, | |
key; | |
for (counter = 0; counter < length; counter += 1) { | |
key = notEnumerable[counter]; | |
if (hasOwnProperty.call(this, key)) { | |
array.push(key); | |
} | |
} | |
} | |
/** | |
* Returns an array of enumerable keys of an object | |
* @param {Object} object Object to enumerate | |
* @return {Array} Array containing keys of enumerable properties | |
*/ | |
function keys(object) { | |
var | |
array; | |
verifyObject(object, 'Object.keys called on non-object'); | |
array = []; | |
addEnumerables.call(object, array); | |
if (hasEnumBug) { | |
addNonEnumerables.call(object, array); | |
} | |
return array; | |
} | |
/** | |
* Returns an array of keys of an object | |
* @param {Object} object Object to enumerate | |
* @return {Array} Array containing keys of properties | |
*/ | |
function getOwnPropertyNames(object) { | |
var | |
array; | |
verifyObject(object, 'Object.getOwnPropertyNames called on non-object'); | |
array = keys(object); | |
if (O.prototype.toString.call(object) === '[object Array]') { | |
array.push('length'); | |
} | |
return array; | |
} | |
return returnNonEnumerables ? getOwnPropertyNames : keys; | |
} | |
function defineProperties(object, properties) { | |
var | |
counter, | |
descriptors, | |
key, | |
keys, | |
length; | |
verifyObject(object, 'Object.defineProperties called on non-object'); | |
verifyObject(properties, 'Object.defineProperties called with invalid property descriptors'); | |
descriptors = []; | |
keys = O.keys(properties); | |
for (counter = 0, length = keys.length; counter < length; counter += 1) { | |
key = keys[counter]; | |
descriptors.push([key, createDescriptor(properties[key])]); | |
} | |
for (counter = 0, length = descriptors.length; counter < length; counter += 1) { | |
key = descriptors[counter]; | |
O.defineProperty(object, key[0], key[1]); | |
} | |
return object; | |
} | |
function getPrototypeOfWrapper() { | |
return ''[proto] === String.prototype | |
? function getPrototypeOf(object) { | |
return object[proto]; | |
} : function getPrototypeOf(object) { | |
return object.constructor.prototype; // fragile | |
}; | |
} | |
hasOwnProperty = O.prototype.hasOwnProperty; | |
proto = '__proto__'; | |
T = TypeError; | |
if (!O.defineProperties) { | |
definePropertyFn = O.defineProperty; // save original function | |
O.defineProperty = defineProperty; | |
} | |
(function (wrappedStatics, statics) { | |
var | |
key; | |
for (key in wrappedStatics) { | |
if (hasOwnProperty.call(wrappedStatics, key) && !hasOwnProperty.call(O, key)) { | |
O[key] = wrappedStatics[key](key === 'getOwnPropertyNames'); | |
} | |
} | |
for (key in statics) { | |
if (hasOwnProperty.call(statics, key) && !hasOwnProperty.call(O, key)) { | |
O[key] = statics[key]; | |
} | |
} | |
}({ // wrapped static functions | |
'getOwnPropertyNames': keysWrapper, | |
'getPrototypeOf': getPrototypeOfWrapper, | |
'keys': keysWrapper | |
}, { // static functions | |
'defineProperties': defineProperties, | |
'preventExtensions': preventExtensions, | |
'isExtensible': isExtensible, | |
'freeze': freeze, | |
'isFrozen': isFrozen, | |
'seal': seal, | |
'isSealed': isSealed | |
})); | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment