【问题标题】:Javascript proxy behaves differently on Array.push() and set by indexJavascript 代理在 Array.push() 上的行为不同并由索引设置
【发布时间】:2020-03-03 19:15:03
【问题描述】:

我正在编写类似于以下 sn-p 的代码:

let arr = [];
let arr_handlers = {
    set: function(target, property, value, receiver) {
        console.log('setting ' + property + ' for ' + target + ' with value ' + value);

        target[property] = value;
        return true;
    }
};
let arr_proxy = new Proxy(arr, arr_handlers);

arr_proxy.push(1);
// setting 0 for  with value 1
// setting length for 1 with value 1
arr_proxy[1] = 5;
//  setting 1 for 1 with value 5
console.log(arr.length);
// 2

问题是当我使用arr_proxy.push() 和通过索引设置值时代理的行为不同:

当数组值由索引设置时,为什么不调用代理设置器来设置长度?

【问题讨论】:

  • 您的数组只有一项,但您在索引 3 上设置了一项。这会将数组转换为稀疏数组,不会更新长度。我在规范中找不到这个。
  • @Amy 如果我在索引 1 上设置一个项目,它的行为方式相同。我已经更新了问题
  • 是的,我的分析/结论是错误的。我不知道。我会留下我的评论,这样其他人就不会过来说同样的话。

标签: javascript


【解决方案1】:

当数组值由索引设置时,为什么不调用代理设置器来设置长度?

因为数组特有的动态length 属性仅存在于target在您的代理内部

相比之下,push 方法确实在其接收器上显式设置了.length 属性。它不会通过分配给索引而自动触发。你可以试试

const obj = { length: 0, push: Array.prototype.push };
obj.push(5)
console.log(obj) // { length: 1, 0: 5 }

您可以通过编写实现与arr_proxy.push(5) 调用相同的行为

const _len = arr_proxy.length;
arr_proxy[_len] = 5;
arr_proxy.length = _len + 1;

【讨论】:

  • 但问题是 为什么 setter 在分配给索引时不会自动触发? length 数组的特殊性只存在于目标上 在这两种情况下,我是通过push 还是通过索引添加值,但由于某种原因,它仅在通过@987654333 分配时由包装器设置@
  • @aryndin Push 不仅增加了价值。 Push 还显式写入 .length 属性(即使数组对象不需要这样做,它已经具有正确的长度)。
  • @aryndin 在分配给[1] 期间不会触发length 设置器,因为您没有分配给.length。然后,当您 访问 .length 属性时,length getter 将重新计算当前长度。
  • 不是push()array prototype specific,因此应该考虑到不需要显式设置数组的长度?
  • @aryndin 不,push 方法 is generic,它不需要数组 - 请参阅我的回答中的示例 obj,它没有魔法 .length 和仍然有效。 (我并不是说引擎在数组上调用 push 时不会实现内部优化,但是当它在任意代理对象上调用时它当然不能利用它们)。另请注意,push 必须是通用的才能在您的代理上工作,如果您尝试围绕类型数组使用代理,它将是 throw exceptions
猜你喜欢
  • 2012-02-03
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2020-02-03
  • 1970-01-01
  • 2021-02-01
  • 1970-01-01
相关资源
最近更新 更多