Correct implementation of Array.from and Array.of as they are currently spec'ed. Includes "isConstructor"
(function( global ) { | |
"use strict"; | |
function isConstructor( C ) { | |
try { | |
new C(); | |
return true; | |
} catch ( e ) { | |
return false; | |
} | |
} | |
Array.from = function( arrayLike ) { | |
var items, len, C, A, k, Pk, kPresent, kValue; | |
// 1. Let items be ToObject(arrayLike). | |
items = Object(arrayLike); | |
// 3. Let lenValue be the result of calling the [[Get]] | |
// internal method of items with the argument "length". | |
// 4. Let len be ToInteger(lenValue). | |
len = +items.length; | |
// 6. Let C be the |this| value. | |
C = this; | |
// 7. If isConstructor(C) is true, then | |
if ( isConstructor(C) ) { | |
// a. Let newObj be the result of calling the | |
// [[Construct]] internal method of C with an argument | |
// list containing the single item len. | |
// b. Let A be ToObject(newObj). | |
A = Object(new C(len)); | |
} else { | |
A = new Array(len); | |
} | |
// 10. Let k be 0. | |
k = 0; | |
// 11. Repeat, while k < len | |
while ( k < len ) { | |
// a. Let Pk be ToString(k). | |
Pk = String(k); | |
// b. Let kPresent be the result of calling the [[HasProperty]] | |
// internal method of items with argument Pk. | |
kPresent = items.hasOwnProperty(Pk); | |
// c. If kPresent is true, then... | |
if ( kPresent ) { | |
// i. Let kValue be the result of calling the [[Get]] | |
// internal method of items with argument Pk. | |
kValue = items[ Pk ]; | |
// ii. ReturnIfAbrupt(kValue). | |
// iii. Let defineStatus be the result of calling the | |
// [[DefineOwnProperty]] internal method of A with | |
// arguments Pk, Property Descriptor | |
// {[[Value]]: kValue.[[value]], | |
// [[Writable]]: true, | |
// [[Enumerable]]: true, | |
// [[Configurable]]: true}, and true. | |
A[ k ] = kValue; | |
} | |
// d. Increase k by 1. | |
k++; | |
} | |
// 14. Return A. | |
return A; | |
}; | |
Array.of = function() { | |
var items, len, C, A, k, Pk, kPresent, kValue; | |
// X. Let items be ToObject(arrayLike). | |
items = Object(arguments); | |
// 1. Let lenValue be the result of calling the [[Get]] | |
// internal method of items with the argument "length". | |
// 2. Let len be ToInteger(lenValue). | |
len = +items.length; | |
// 3. Let C be the |this| value. | |
C = this; | |
// 4. If isConstructor(C) is true, then | |
if ( isConstructor(C) ) { | |
// a, b. | |
A = Object(new C(len)); | |
} else { | |
// 5. Else, a. | |
A = new Array(len); | |
} | |
// 6. omitted | |
// 7. Let k be 0. | |
k = 0; | |
// 8. Repeat, while k < len | |
while ( k < len ) { | |
// a. Let Pk be ToString(k). | |
Pk = String(k); | |
// b. Let kValue be the result of calling the [[Get]] | |
// internal method of items with argument Pk. | |
kValue = items[ Pk ]; | |
// c. Let defineStatus be the result of calling the | |
// [[DefineOwnProperty]] internal method of A with | |
// arguments Pk, Property Descriptor | |
// {[[Value]]: kValue.[[value]], | |
// [[Writable]]: true, | |
// [[Enumerable]]: true, | |
// [[Configurable]]: true}, and true. | |
A[ k ] = kValue; | |
// d. omitted | |
// e. Increase k by 1. | |
k++; | |
} | |
// 9, 10. omitted | |
// 11. Return A. | |
return A; | |
}; | |
global.Array.from = Array.from; | |
global.Array.of = Array.of; | |
})( global ); | |
{ | |
// tests | |
var arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 }; | |
console.log( Array.from(arrayLike) ); | |
console.log( Array.of(0) ); | |
console.log( Array.of(1, null, undefined, false, 2) ); | |
console.log( Array.of() ); | |
var other = { | |
from: Array.from, | |
of: Array.of | |
}; | |
console.log( other.from(arrayLike) ); | |
console.log( other.of(1, null, undefined, false, 2) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment