1'use strict'; 2 3// modified from https://github.com/es-shims/es5-shim 4var has = Object.prototype.hasOwnProperty; 5var toStr = Object.prototype.toString; 6var slice = Array.prototype.slice; 7var isArgs = require('./isArguments'); 8var isEnumerable = Object.prototype.propertyIsEnumerable; 9var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); 10var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); 11var dontEnums = [ 12 'toString', 13 'toLocaleString', 14 'valueOf', 15 'hasOwnProperty', 16 'isPrototypeOf', 17 'propertyIsEnumerable', 18 'constructor' 19]; 20var equalsConstructorPrototype = function (o) { 21 var ctor = o.constructor; 22 return ctor && ctor.prototype === o; 23}; 24var excludedKeys = { 25 $applicationCache: true, 26 $console: true, 27 $external: true, 28 $frame: true, 29 $frameElement: true, 30 $frames: true, 31 $innerHeight: true, 32 $innerWidth: true, 33 $outerHeight: true, 34 $outerWidth: true, 35 $pageXOffset: true, 36 $pageYOffset: true, 37 $parent: true, 38 $scrollLeft: true, 39 $scrollTop: true, 40 $scrollX: true, 41 $scrollY: true, 42 $self: true, 43 $webkitIndexedDB: true, 44 $webkitStorageInfo: true, 45 $window: true 46}; 47var hasAutomationEqualityBug = (function () { 48 /* global window */ 49 if (typeof window === 'undefined') { return false; } 50 for (var k in window) { 51 try { 52 if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { 53 try { 54 equalsConstructorPrototype(window[k]); 55 } catch (e) { 56 return true; 57 } 58 } 59 } catch (e) { 60 return true; 61 } 62 } 63 return false; 64}()); 65var equalsConstructorPrototypeIfNotBuggy = function (o) { 66 /* global window */ 67 if (typeof window === 'undefined' || !hasAutomationEqualityBug) { 68 return equalsConstructorPrototype(o); 69 } 70 try { 71 return equalsConstructorPrototype(o); 72 } catch (e) { 73 return false; 74 } 75}; 76 77var keysShim = function keys(object) { 78 var isObject = object !== null && typeof object === 'object'; 79 var isFunction = toStr.call(object) === '[object Function]'; 80 var isArguments = isArgs(object); 81 var isString = isObject && toStr.call(object) === '[object String]'; 82 var theKeys = []; 83 84 if (!isObject && !isFunction && !isArguments) { 85 throw new TypeError('Object.keys called on a non-object'); 86 } 87 88 var skipProto = hasProtoEnumBug && isFunction; 89 if (isString && object.length > 0 && !has.call(object, 0)) { 90 for (var i = 0; i < object.length; ++i) { 91 theKeys.push(String(i)); 92 } 93 } 94 95 if (isArguments && object.length > 0) { 96 for (var j = 0; j < object.length; ++j) { 97 theKeys.push(String(j)); 98 } 99 } else { 100 for (var name in object) { 101 if (!(skipProto && name === 'prototype') && has.call(object, name)) { 102 theKeys.push(String(name)); 103 } 104 } 105 } 106 107 if (hasDontEnumBug) { 108 var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); 109 110 for (var k = 0; k < dontEnums.length; ++k) { 111 if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { 112 theKeys.push(dontEnums[k]); 113 } 114 } 115 } 116 return theKeys; 117}; 118 119keysShim.shim = function shimObjectKeys() { 120 if (Object.keys) { 121 var keysWorksWithArguments = (function () { 122 // Safari 5.0 bug 123 return (Object.keys(arguments) || '').length === 2; 124 }(1, 2)); 125 if (!keysWorksWithArguments) { 126 var originalKeys = Object.keys; 127 Object.keys = function keys(object) { // eslint-disable-line func-name-matching 128 if (isArgs(object)) { 129 return originalKeys(slice.call(object)); 130 } else { 131 return originalKeys(object); 132 } 133 }; 134 } 135 } else { 136 Object.keys = keysShim; 137 } 138 return Object.keys || keysShim; 139}; 140 141module.exports = keysShim; 142