Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // 12 September 2018
- // possible blog post
- // Array.from() and Array.prototype.slice.call() can take objects with
- // coercibly numeric keys and a length property to produce a new array.
- // if length is inaccurate (2 instead of 1, e.g.), you get empty slots
- console.log(Array.from({ 0: 'first', length: 2 })); // Array [ "first", undefined ]
- console.log([].slice.call({ 0: 'first', length: 2 })); // Array [ "first", <1 empty slot> ]
- // if length is accurate but an index is missing, you get empty slots
- console.log(Array.from({ 0: 'first', '': 'next', 2: 'last', length: 3 })); // Array [ "first", undefined, "last" ]
- console.log([].slice.call({ 0: 'first', '': 'next', 2: 'last', length: 3 })); // Array [ "first", <1 empty slot>, "last" ]
- // if length is floating point, you get the integer value
- console.log(Array.from({ 0: 'first', length: 1.9999999999999 })); // Array [ "first" ]
- console.log([].slice.call({ 0: 'first', length: 1.999999999999 })); // Array [ "first" ]
- // if length is boolean, you get 1 or 0
- console.log(Array.from({ 0: 'first', 1: 'next', length: false })); // Array []
- console.log([].slice.call({ 0: 'first', length: false })); // Array []
- console.log(Array.from({ 0: 'first', '1': 'next', length: true })); // Array [ "first" ]
- console.log([].slice.call({ 0: 'first', 1: 'next', length: true })); // Array [ "first" ]
- // if length is missing or not coercibly numeric, you get nothing
- console.log(Array.from({ 0: 'first' })); // Array []
- console.log([].slice.call({ 0: 'first' })); // Array []
- // if length is an array that toString() turns into a coercible number, that's what you get
- console.log(Array.from({ 0: 'ok', length: ['1'] })); // Array [ "ok" ]
- console.log([].slice.call({ 0: 'wow', length: ['2']})); // Array [ "wow", <1 empty slot> ]
- // if the object has both numeric and string versions of a key, you'll get the last-defined entry
- console.warn(Array.from({ 0: 'first', length: 1, '0': 'more' })); // Array [ "more" ]
- console.warn(Array.from({ '0': 'first', length: 1, 0: 'more' })); // Array [ "more" ]
- // if a key is a floating point, it is ignored
- console.warn(Array.from({ length: 1, '1.1': 'more' })); // Array [ undefined ]
- // Now that we know all that, we can look at the standard usages and derive a
- // convertible length-less object with numeric keys and run that through from and slice
- var test = Array.from({ 0: 'first', length: 1 });
- console.log(test); // Array [ "first" ]
- var test2 = [].slice.call({ 0: 'first', 2: 'last', length: 3 });
- console.log(test2); // Array(3) [ "first", <1 empty slot>, "last" ]
- var test3 = Array.from({ 0: 'first', '1': 'next', length: 2 });
- console.log(test3); // Array [ "first", "next" ]
- // Now let's make an array out of an object without a length property
- var source = { 0: 'first', '1': 'next', 2: 'last', NaN: 'not a number', null: 'null', undefined: void 0, '-1': 'negative 1', '1.1': '1.1', '2.0': 'dupe' };
- // get all 0-based integer keys
- var keys = Object.keys(source).filter((key) => {
- var v = Number.parseInt(''+key, 10);
- // not NaN, integer, 0-based
- return v === v && ''+ Number.parseInt(key) === key && v >= 0;
- });
- console.info('our keys');
- console.log(keys);
- // walk the keys and insert matching source key entries onto the target
- var length = keys.length;
- var target = keys.reduce((target, key) => {
- target[key] = source[key];
- return target;
- }, { length });
- console.info('our target');
- console.log(target);
- // test it out
- console.log('our tests');
- var test4 = Array.from(target);
- console.log(test4); // Array(3) [ "first", "next", "last" ]
- var test5 = [].slice.call(target);
- console.log(test5); // Array(3) [ "first", "next", "last" ]
Add Comment
Please, Sign In to add comment