【发布时间】:2017-08-06 04:15:25
【问题描述】:
为数组构建 Javascript 代理的正确方法是什么,这样“set”处理程序就不会被多次调用以对数组进行一次更改?
这就是我的意思:
我想在代理对象中包装一个简单的数组。当我希望 push() 一个新值到这个 Proxy 对象时,我希望运行一个“设置”处理程序。
问题在于,对于数组的一次操作,像“set”这样的代理处理程序会被多次调用。在某些情况下,处理该问题似乎相当容易,但在其他情况下,一次调用 来修改包装在 Proxy 对象中的数组会导致 set handler 至少被调用一次 every元素。
假设我像这样创建了最简单的代理处理程序对象和代理:
let proxyHandlerObj = {
set:function(target,property,value,receiver) {
console.log("Set handler is invoked on property:",property,"with value:",value);
/*
* Important and interesting things done here
*/
return (target[property] = value);
}
};
let proxyArray = new Proxy(["zero","one","two"],proxyHandlerObj);
此代理只是拦截对我的代理数组的 'set-like' 调用并向控制台写入消息。现在,当我在 proxyArray 对象的末尾添加一个新元素时:
proxyArray.push("three")
我会得到这样的东西:
Set handler is invoked on property: 3 with value: three
Set handler is invoked on property: length with value: 4
我看到 set 处理程序被调用了两次:一次用于在数组中创建新元素,另一次用于设置数组的新长度属性。
好的,这个问题可以通过检查被操纵的属性来解决。我见过 set properties 做了这样的事情:
set:function(target,property,value,receiver) {
if(property!="length") {
console.log("Set handler is invoked on property:",property,"with value:",value);
/*
* Important and interesting things done here
*/
}
return (target[property] = value);
}
对proxyArray.push("three") 的相同调用将对除length 属性之外的所有属性执行重要操作。这是因为我正在检查是否设置了 length 属性。这对我来说似乎没问题。
但是,假设我想从我的数组中简单地splice() 一些东西?:
proxyArray.splice(0,1);
这会为数组中的每个元素生成一个“集合”调用:
Set handler is invoked on property: 0 with value: one
Set handler is invoked on property: 1 with value: two
Set handler is invoked on property: 2 with value: three
这当然不是我想要的。我希望我的设置处理程序在“splice()”上运行一次,而不是三次。
更重要的是,对于同一个splice() 操作多次触发“set”方法会产生非常讨厌的副作用。通过将“set”处理程序更改为以下内容来查看数组的内容:
set:function(target,property,value,receiver) {
if(property!="length") {
console.log("Set handler is invoked on property:",property,"with value:",value);
/*
* Important and interesting things done here
*/
}
let result = (target[property] = value);
console.log(JSON.stringify(target));
return result;
}
会产生这个:
Set handler is invoked on property: 0 with value: one
["one","one","two","three"]
Set handler is invoked on property: 1 with value: two
["one","two","two","three"]
Set handler is invoked on property: 2 with value: three
["one","two","three","three"]
["one","two","three"]
因此,Javascript 将每个值向下移动到数组中,一次一个,然后弹出最后一个重复元素作为最后一步。必须构建您的集合处理程序来处理这种中间重复。
这似乎会产生令人讨厌和复杂的“设置”处理程序。
那么,构建包裹在数组周围的 Javascript 代理以使“设置”处理程序不会被多次调用并且目标对象在此过程中可靠的正确方法是什么?
【问题讨论】:
-
“这样 'set' 处理程序不会被多次调用并且目标对象在此过程中是可靠的?”
set有什么问题处理程序被多次调用?具体来说,“过程中的可靠”是要求的一部分? -
假设您有一组电子邮件地址。您想构建一个“设置”处理程序,当电子邮件地址数组更改时触发一些操作。也许,当添加电子邮件地址时。也许您不希望将单个 push() 多次触发到电子邮件地址数组中。更糟糕的是,如果您从数组中拼接出一个电子邮件地址,那么该集合处理程序将为数组中的每个元素运行。此外,“目标”对象(处理程序方法中的第一个参数)不准确,因为在拼接完成之前它有一个重复的元素。
-
如果每次索引更改都调用处理程序时出现问题,使用
set处理程序的目的是什么?是否需要创建一个在数组内更改索引时不验证数组的.length的函数? -
了解代理提供了一种方便的方法来拦截对象的基本操作并执行一些自定义行为。所以,假设我想创建一个自定义行为,每次添加地址时验证电子邮件地址。如果我 push() 一个新的电子邮件地址到我的电子邮件列表,我的小特殊验证功能会自动运行。但是,对于数组中的每个元素,一些基本功能每次都会触发我的验证功能——即使它已经过验证。那不是很好。
-
您是否尝试过使用 JavaScript 普通对象替换
target的Proxy()调用中的数组?
标签: javascript arrays proxy