1'use strict'; 2var LIBRARY = require('./_library'); 3var $export = require('./_export'); 4var redefine = require('./_redefine'); 5var hide = require('./_hide'); 6var Iterators = require('./_iterators'); 7var $iterCreate = require('./_iter-create'); 8var setToStringTag = require('./_set-to-string-tag'); 9var getPrototypeOf = require('./_object-gpo'); 10var ITERATOR = require('./_wks')('iterator'); 11var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next` 12var FF_ITERATOR = '@@iterator'; 13var KEYS = 'keys'; 14var VALUES = 'values'; 15 16var returnThis = function () { return this; }; 17 18module.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) { 19 $iterCreate(Constructor, NAME, next); 20 var getMethod = function (kind) { 21 if (!BUGGY && kind in proto) return proto[kind]; 22 switch (kind) { 23 case KEYS: return function keys() { return new Constructor(this, kind); }; 24 case VALUES: return function values() { return new Constructor(this, kind); }; 25 } return function entries() { return new Constructor(this, kind); }; 26 }; 27 var TAG = NAME + ' Iterator'; 28 var DEF_VALUES = DEFAULT == VALUES; 29 var VALUES_BUG = false; 30 var proto = Base.prototype; 31 var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; 32 var $default = $native || getMethod(DEFAULT); 33 var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined; 34 var $anyNative = NAME == 'Array' ? proto.entries || $native : $native; 35 var methods, key, IteratorPrototype; 36 // Fix native 37 if ($anyNative) { 38 IteratorPrototype = getPrototypeOf($anyNative.call(new Base())); 39 if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) { 40 // Set @@toStringTag to native iterators 41 setToStringTag(IteratorPrototype, TAG, true); 42 // fix for some old engines 43 if (!LIBRARY && typeof IteratorPrototype[ITERATOR] != 'function') hide(IteratorPrototype, ITERATOR, returnThis); 44 } 45 } 46 // fix Array#{values, @@iterator}.name in V8 / FF 47 if (DEF_VALUES && $native && $native.name !== VALUES) { 48 VALUES_BUG = true; 49 $default = function values() { return $native.call(this); }; 50 } 51 // Define iterator 52 if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) { 53 hide(proto, ITERATOR, $default); 54 } 55 // Plug for library 56 Iterators[NAME] = $default; 57 Iterators[TAG] = returnThis; 58 if (DEFAULT) { 59 methods = { 60 values: DEF_VALUES ? $default : getMethod(VALUES), 61 keys: IS_SET ? $default : getMethod(KEYS), 62 entries: $entries 63 }; 64 if (FORCED) for (key in methods) { 65 if (!(key in proto)) redefine(proto, key, methods[key]); 66 } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); 67 } 68 return methods; 69}; 70