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