【问题标题】:Using [].push.call() to modify an object's length使用 [].push.call() 修改对象的长度
【发布时间】:2017-10-08 11:06:26
【问题描述】:

无法重现MDN's example(«以类似数组的方式使用对象»)。

  let obj = {
    length: 0,
    addEl: function (element) {
       [].push.call(this, element);
    };
  };
  // Node REPL still expect me to do something, so there's an error. Why?

你们能解释一下这里出了什么问题吗?此外,我似乎不明白这里的机制:

// from the example:
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2

如果我们用一些不同的参数调用函数,而不是{},它会起作用吗?如果它不会,那我们为什么要准确地使用{}?这里的this 上下文是什么:addEl 方法或对象本身?如果是第二个,为什么不使用 addEl 函数:它不是数组函数,所以它应该有自己的 this (而且,我想,我会使用类似 objThis = this; 的属性)。

另一个相关问题是here

【问题讨论】:

    标签: javascript call


    【解决方案1】:

    您帖子中的代码有一些拼写错误:

      let obj = {
        length: 0,
        addEl: function (element) {
           [].push.call(this, element);
        };
         ^ syntax error
      };
      // Node REPL still expect me to do something, so there's an error. Why?
    

    正如您在代码中的评论中所怀疑的那样, 有一个语法错误,我为你标记了。 删除那个分号。

    然后,在尝试您编写的示例 obj.addElem 时, 但在上面的对象文字中你有addEl

    如果您只是复制粘贴,该示例应该可以正常工作。

    var obj = {
        length: 0,
    
        addElem: function addElem(elem) {
            // obj.length is automatically incremented 
            // every time an element is added.
            [].push.call(this, elem);
        }
    };
    
    // Let's add some empty objects just to illustrate.
    obj.addElem({});
    obj.addElem({});
    console.log(obj.length);
    // → 2
    

    如果我们用一些不同的参数调用函数,而不是{},它会起作用吗?

    肯定会的。为什么不呢? JavaScript 中的数组可以包含不同类型的值。 它不需要是同质的, 所以是的,您可以插入除{} 之外的其他内容。

    这里的this 上下文是什么:addEl 方法还是对象本身?

    它是调用方法的对象。所以它是obj。 这就是方法调用的工作方式。 当您调用obj.something() 时,something 中的this 将是obj


    如果您对此示例仍有疑问,请随时发表评论。

    【讨论】:

    • 也许这很傻,但是为什么这里不需要分号呢?我想,每个语句都需要它(撇开事实不谈,JS 引擎可以自己预测它们的位置)。
    • @JulyMorning 这不是一个语句,而是一个对象文字。 { a: 1, b: 2;} 是您可能看得更清楚的一个类似示例,这是不正确的,; 不应该在那里。在对象字面量之后,要终止语句,当然应该放一个分号,例如var obj = { a: 1, b: 2 };
    • 能否请您看一下@我在问题中的编辑?
    • @JulyMorning 请不要在这个问题中提出新问题。你原来的问题已经回答了。如果您有新问题,请发布新问题,不要再更改此问题。
    • 好吧,我不会,但它们之间的关系如此密切……抱歉。只是想知道这种模式是如何工作的。
    【解决方案2】:

    由于对象不是数组,但可以表现得像数组,因此您需要从 Array 对象中借用 push

    但在这种情况下,this 指的是使用简写 [] 创建的数组对象。所以我们需要使用call 将其更改为obj 的范围。

    因为定义了length属性,所以推送会更新这个值。

    一个空对象作为元素 {} 传递,但其他任何对象都可以:

    let obj = {
      length: 0,
      addEl: function(element) {
        Array.prototype.push.call(this, element); //also borrowing push from the array.prototype prevents an extra array to be made in memory every time we call upon this function.
      } //« fixed the typo here
    };
    
    obj.addEl({});
    obj.addEl(1);
    obj.addEl('a');
    obj.addEl(true);
    console.log(obj);

    【讨论】:

    • [] 是为每种情况缩短 «Arryay.prototype» 的正确方法吗?或者,可能是每个调用/绑定函数?
    • []new Array() 的简写。当您使用类似对象的数组时,例如节点列表或具有属性的对象,您有时希望在它们上使用数组函数。但是 Object 没有像 forEach 和 push 这样的功能。所以我们转向主对象Array 并使用它的原型来借用它的功能。但是,如果我们只是简单地执行Array.prototype.push(element),它将尝试将元素添加到 Array 主对象并失败。所以我们必须链接我们的对象以使用调用或绑定来推送它的引用。
    【解决方案3】:
    var array = {
        length: 0,
        push: function(obj){
            this[this.length] = obj;
            this.length++;
        }
    }
    
    array.push(23);
    

    你可以试试这个,我猜这解决了你的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      • 1970-01-01
      • 1970-01-01
      • 2017-02-28
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多