Skip to content

Instantly share code, notes, and snippets.

@ShirtlessKirk
Created October 30, 2015 16:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ShirtlessKirk/f425d2764e82d8fc0d74 to your computer and use it in GitHub Desktop.
Save ShirtlessKirk/f425d2764e82d8fc0d74 to your computer and use it in GitHub Desktop.
Object methods polyfill (partial)
/*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