Array.of vs “[ ]”. When to use Array.of over “[ ]”?

后端 未结 3 1416
滥情空心
滥情空心 2020-11-30 08:48

I was doing a bit of reading when I found Array.of.

As per MDN,

The Array.of() method creates a new Array instance with a variable number of argum

相关标签:
3条回答
  • 2020-11-30 09:09

    Although this method might have been standardized, it does appear to be unsupported in a number of browsers, so using it seems risky and, as you note, pretty much pointless.

    The utility of this function seems to be for cases where you need to declare an array but don't want to assemble it out of parts. That is, you want to be able to pass a number of arguments to some function that then returns an Array.

    If you follow the links to the justification of that method you get this:

    The use-case is when you can't write a literal, because you are passing a function-that-constructs as a funarg, and the eventual caller may pass only one number arg, or several args. In that case, Array will not do the right thing in the one-number-arg case.

    That's basically a way of saying "this function can receive variable length argument lists and will consistently return arrays populated with the correct values", but as in practice that converts an array to...an array, I'm not entirely convinced this thing needs to exist and apparently many browser implementors are of a similar mindset.

    The push for Array.of largely a response to the fact that new Array() behaves inconsistently:

    new Array(2);
    // [ , ] 2-element array that's unpopulated
    
    new Array(1,2);
    // [1,2] 2-element array populated with the provided values
    

    Array.of will always operate like the latter version.

    0 讨论(0)
  • 2020-11-30 09:18

    Iterating off of Redu's answer, you could use ArraySubclass.of to create instances of an array subclass. For example, you could create an Array-subclass wrapper around lodash's Array methods.

    For example:

    _.Array = class extends Array {
      uniq() {
        return _.Array.from(_.uniq(this));
      }
      last() {
        return _.last(this);
      }
      flatten() {
        return _.Array.from(_.flatten(this));
      }
      // ... more methods
    }
    
    _.Array.of([1,2,3], [3,4,5]) // <_.Array> [[1,2,3],[3,4,5]]
      .flatten()                 // <_.Array> [1,2,3,3,4,5]
      .uniq()                    // <_.Array> [1,2,3,4,5]
      .last()                    // <number> 5
    

    JSFiddle


    Edit

    I ended up extending this example to use ES Proxies.

    _.Array = class extends Array { }
    _.Array.prototype = new Proxy(Array.prototype, {
      get(proto, name) {
        if (name in _) return function (...args) {
            const ret = _[name](this, ...args);
            return Array.isArray(ret) ? _.Array.from(ret) : ret;
        }
        return proto[name];
      }
    });
    

    Now every lodash function is available, and those returning arrays are wrapped in the _.Array class, similar to _(array) implicit chaining.

    0 讨论(0)
  • 2020-11-30 09:34

    There is one subtle difference between Array.of() and Array() / [] constructor. Normally just like Array(), the this in Array.of() will be the Array object and it will use the Array.constructor which is function Array() to construct it's result.

    However Array.of can behave differently by changing it's bound context. If the bound context can be used as a constructor (if the bound object is a function) it will use that function to construct. So let's bind the Array.of() to a function and see what happens.

    function Test(n){console.log(n)}
    Test.prototype.last = function(){return this[this.length-1]};
    
    var what = Array.of.call(Test, [5,6,7], {a:0,b:1}, 42, null, "this is last");
    console.log(JSON.stringify(what,null,2));
    console.log(what.last());

    So we got an array like thingy with access to all function methods plus the ones at our constructor's prototype.

    It's best to remember it's definition;

    NOTE 2 The of function is an intentionally generic factory method; it does not require that its this value be the Array constructor. Therefore it can be transferred to or inherited by other constructors that may be called with a single numeric argument.

    OK this can be very handy for array sub-classing. I know array sub-classing is possible by involving Object.setPrototypeOf() or __proto__ but they are somewhat discouraged operations and we can still do a similar job with the help of Array.of(). So .. once known to be useless Array.of() here becomes a hero; may be one of the most useful Array methods. How come..? let's see...

    function SubArr(){}
    SubArr.prototype = Object.create(Array.prototype); // make SubArr.prototype's prototype Array.prototype
    SubArr.prototype.last = function(){return this[this.length-1]}; // add prototype methods to SubArr
    
    var what = Array.of.call(SubArr, 1, 2, 3, 4, "this is last");
    console.log(JSON.stringify(what,null,2));
    console.log(what.last());
    console.log(what.map(e => e));
    console.log(what instanceof Array);
    console.log(Array.isArray(what));
    console.log(Object.prototype.toString.call(what));

    I have also tried making SubArr.prototype.constructor = Array; but Array.isArray(what) still resulted false though.

    0 讨论(0)
提交回复
热议问题