Skip to content

Instantly share code, notes, and snippets.

@rwaldron
Created July 27, 2012 07:01
Show Gist options
  • Save rwaldron/3186576 to your computer and use it in GitHub Desktop.
Save rwaldron/3186576 to your computer and use it in GitHub Desktop.
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