You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
6.3 KiB
212 lines
6.3 KiB
// 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;
|
|
};
|
|
})();
|