Skip to content

Instantly share code, notes, and snippets.

@unscriptable
Last active February 12, 2024 00:35
Show Gist options
  • Save unscriptable/6089437 to your computer and use it in GitHub Desktop.
Save unscriptable/6089437 to your computer and use it in GitHub Desktop.
ES6 WTF Array.from(). We can't do some seemingly simple things with the generic Array.from() as it is specified today.
// IIUC, the proposed spec for Array.from at http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.4.2.4
// is generic, which means the function can be applied to other constructors. Like this, for instance:
//
// var myString = Array.from.call(String, arrayOfChars);
//
// It does this by calling the constructor of `this` and passing the length of the argument (arg.length).
// I tried shimming it here: https://github.com/cujojs/poly/blob/dev/array-es6.js#L44-L54
// Unfortunately, this yields some interesting results...
// Convert an array of bytes or characters to a string:
var arrayOfChars = ['f', 'o', 'o'];
console.log(Array.from.call(String, arrayOfChars));
// > TypeError: Cannot assign to read only property 'length' of [object String]
// If we place a try-catch around the line in the shim that assigns length, we get this:
var arrayOfChars = ['f', 'o', 'o'];
console.log(Array.from.call(String, arrayOfChars));
// > String {0: "3", 1: "o", 2: "o", 0: "3"}
// What is that? It's a `new String('3')` with some integer property turds on it.
// Why '3'? Because that's the length of the input, arrayOfChars.
// The line of code that constructs the new String passes the length of arrayOfChars, and
// the String constructor converts that to a string and uses it as the value.
// Sure, we could achieve `Array.from.call(String, arrayOfChars)` by doing this:
arrayOfChars.join('');
// but Array.from sure feels like a more direct solution.
// So, what if want to create an Array-like object? Maybe something we can use as a "sparse array".
// Here's my first inkling about how we could do it. Just use the Object constructor:
var someItems = [1, 2, 3];
console.log(Array.from.call(Object, someItems));
// > Number {0: 1, 1: 2, 2: 3, length: 3}
// Whaaaaa???? Dang. That's not what I wanted. :( It's a `new Object(3)` with some more integer turds.
// Again, this happens because the spec says to pass length of the input to the Object constructor.
// Also, `Array.from.call(Object, someItems)` could be done like this:
someItems.reduce(function (alo, item, i) { alo[i] = item; return alo; }, { length: someItems.length });
// but `Array.from.call(Object, someItems)` seems so much more elegant.
// Can we change the spec to allow generic (and useful) behavior for String and Object, too?
// Of course, it's quite possible I'm doing it wrong, too. :)
@igl
Copy link

igl commented Oct 15, 2015

Array.from exists to convert the arguments object into a array. It's more duct tape than a feature.

It might be put to use on Set's and Typed Arrays too to justify its existence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment