123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // Production steps of ECMA-262, Edition 6, 22.1.2.1
- // Reference: http://www.ecma-international.org/ecma-262/6.0/#sec-array.from
- module.exports = (function() {
- var isCallable = function(fn) {
- return typeof fn === 'function';
- };
- var toInteger = function (value) {
- var number = Number(value);
- if (isNaN(number)) { return 0; }
- if (number === 0 || !isFinite(number)) { return number; }
- return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
- };
- var maxSafeInteger = Math.pow(2, 53) - 1;
- var toLength = function (value) {
- var len = toInteger(value);
- return Math.min(Math.max(len, 0), maxSafeInteger);
- };
- var iteratorProp = function(value) {
- if(value != null) {
- if(['string','number','boolean','symbol'].indexOf(typeof value) > -1){
- return Symbol.iterator;
- } else if (
- (typeof Symbol !== 'undefined') &&
- ('iterator' in Symbol) &&
- (Symbol.iterator in value)
- ) {
- return Symbol.iterator;
- }
- // Support "@@iterator" placeholder, Gecko 27 to Gecko 35
- else if ('@@iterator' in value) {
- return '@@iterator';
- }
- }
- };
- var getMethod = function(O, P) {
- // Assert: IsPropertyKey(P) is true.
- if (O != null && P != null) {
- // Let func be GetV(O, P).
- var func = O[P];
- // ReturnIfAbrupt(func).
- // If func is either undefined or null, return undefined.
- if(func == null) {
- return void 0;
- }
- // If IsCallable(func) is false, throw a TypeError exception.
- if (!isCallable(func)) {
- throw new TypeError(func + ' is not a function');
- }
- return func;
- }
- };
- var iteratorStep = function(iterator) {
- // Let result be IteratorNext(iterator).
- // ReturnIfAbrupt(result).
- var result = iterator.next();
- // Let done be IteratorComplete(result).
- // ReturnIfAbrupt(done).
- var done = Boolean(result.done);
- // If done is true, return false.
- if(done) {
- return false;
- }
- // Return result.
- return result;
- };
- // The length property of the from method is 1.
- return function from(items /*, mapFn, thisArg */ ) {
- 'use strict';
- // 1. Let C be the this value.
- var C = this;
- // 2. If mapfn is undefined, let mapping be false.
- var mapFn = arguments.length > 1 ? arguments[1] : void 0;
- var T;
- if (typeof mapFn !== 'undefined') {
- // 3. else
- // a. If IsCallable(mapfn) is false, throw a TypeError exception.
- if (!isCallable(mapFn)) {
- throw new TypeError(
- 'Array.from: when provided, the second argument must be a function'
- );
- }
- // b. If thisArg was supplied, let T be thisArg; else let T
- // be undefined.
- if (arguments.length > 2) {
- T = arguments[2];
- }
- // c. Let mapping be true (implied by mapFn)
- }
- var A, k;
- // 4. Let usingIterator be GetMethod(items, @@iterator).
- // 5. ReturnIfAbrupt(usingIterator).
- var usingIterator = getMethod(items, iteratorProp(items));
- // 6. If usingIterator is not undefined, then
- if (usingIterator !== void 0) {
- // a. If IsConstructor(C) is true, then
- // i. Let A be the result of calling the [[Construct]]
- // internal method of C with an empty argument list.
- // b. Else,
- // i. Let A be the result of the abstract operation ArrayCreate
- // with argument 0.
- // c. ReturnIfAbrupt(A).
- A = isCallable(C) ? Object(new C()) : [];
- // d. Let iterator be GetIterator(items, usingIterator).
- var iterator = usingIterator.call(items);
- // e. ReturnIfAbrupt(iterator).
- if (iterator == null) {
- throw new TypeError(
- 'Array.from requires an array-like or iterable object'
- );
- }
- // f. Let k be 0.
- k = 0;
- // g. Repeat
- var next, nextValue;
- while (true) {
- // i. Let Pk be ToString(k).
- // ii. Let next be IteratorStep(iterator).
- // iii. ReturnIfAbrupt(next).
- next = iteratorStep(iterator);
- // iv. If next is false, then
- if (!next) {
- // 1. Let setStatus be Set(A, "length", k, true).
- // 2. ReturnIfAbrupt(setStatus).
- A.length = k;
- // 3. Return A.
- return A;
- }
- // v. Let nextValue be IteratorValue(next).
- // vi. ReturnIfAbrupt(nextValue)
- nextValue = next.value;
- // vii. If mapping is true, then
- // 1. Let mappedValue be Call(mapfn, T, «nextValue, k»).
- // 2. If mappedValue is an abrupt completion, return
- // IteratorClose(iterator, mappedValue).
- // 3. Let mappedValue be mappedValue.[[value]].
- // viii. Else, let mappedValue be nextValue.
- // ix. Let defineStatus be the result of
- // CreateDataPropertyOrThrow(A, Pk, mappedValue).
- // x. [TODO] If defineStatus is an abrupt completion, return
- // IteratorClose(iterator, defineStatus).
- if (mapFn) {
- A[k] = mapFn.call(T, nextValue, k);
- }
- else {
- A[k] = nextValue;
- }
- // xi. Increase k by 1.
- k++;
- }
- // 7. Assert: items is not an Iterable so assume it is
- // an array-like object.
- } else {
- // 8. Let arrayLike be ToObject(items).
- var arrayLike = Object(items);
- // 9. ReturnIfAbrupt(items).
- if (items == null) {
- throw new TypeError(
- 'Array.from requires an array-like object - not null or undefined'
- );
- }
- // 10. Let len be ToLength(Get(arrayLike, "length")).
- // 11. ReturnIfAbrupt(len).
- var len = toLength(arrayLike.length);
- // 12. If IsConstructor(C) is true, then
- // a. Let A be Construct(C, «len»).
- // 13. Else
- // a. Let A be ArrayCreate(len).
- // 14. ReturnIfAbrupt(A).
- A = isCallable(C) ? Object(new C(len)) : new Array(len);
- // 15. Let k be 0.
- k = 0;
- // 16. Repeat, while k < len… (also steps a - h)
- var kValue;
- while (k < len) {
- kValue = arrayLike[k];
- if (mapFn) {
- A[k] = mapFn.call(T, kValue, k);
- }
- else {
- A[k] = kValue;
- }
- k++;
- }
- // 17. Let setStatus be Set(A, "length", len, true).
- // 18. ReturnIfAbrupt(setStatus).
- A.length = len;
- // 19. Return A.
- }
- return A;
- };
- })();
|