为什么vue无法检测到“vm.items [indexOfItem] = newValue”的变化?

时间:2017-03-19 02:52:52

标签: vue.js frontend

当我从Vue阅读指南时,它说:

  

Vue无法检测到数组的以下更改,例如vm.items[indexOfItem] = newValue

但是当我阅读代码时,我发现了这个:

var Observer = function Observer(value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);
    if (Array.isArray(value)) {
        var augment = hasProto ? protoAugment : copyAugment;
        augment(value, arrayMethods, arrayKeys);
        this.observeArray(value);
    } else {
        this.walk(value);
    }
};

如果我改为:

var Observer = function Observer(value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);
    this.walk(value);
};

如果vm.items[indexOfItem] = newValue小于indexOfItem,则可以检测到array.length - 1的更改。

为什么不呢?

1 个答案:

答案 0 :(得分:1)

警告我并不完全确定Vue的所有反应性是如何起作用的。

但是,我认为答案在于,因为需要支持> = IE9 Vue使用Object.defineProperty。这允许您为事先已知的对象属性创建getter和setter 。这与Proxies不同,你可以设置陷阱来设置一个新的未知属性(虽然粗略检查代码让我觉得Vue确实使用了Proxies,然后又回到了defineProperty它可以的地方。

这对于数组来说意味着类似于对象,你不能设置Vue事先不知道的任意属性。 vm.list.newProperty='foo'vm.list[5]='foo'。这两个都执行等效操作,因为括号是属性访问的替代形式。

现在,解决这样一个事实:当你更改代码时,它适用于数组。问题是它只适用于你所提到的length-1。这意味着向数组添加新值不会变为被动,除非您使用push之类的内容添加它们。这导致我们回到你不能使用括号来设置数组上的值。

此外,对于开发者来说'为了(或可能是性能)你最好不要使用括号进行所有访问,然后说

  

使用括号访问数组仅适用于初始化或稍后使用数组方法设置的数组中的值。如果它在列表当前列表之外,则尝试使用括号表示法设置数组值将不起作用。

或者,如果我们对代码进行更改,则采用其他方式

data:{
  list:[1,2,3]
}
//in your methods
list[0]=0//works
list[3]=4//doesn't work
list.push(4)
list[3]=5//now works

我认为,如果开发人员必须跟踪他脑中每个数组的长度并且仅使用少于此的访问器,那么很容易出现错误。

希望这种解释是有道理的。对于那些对将来可能会使这种情况过时的Proxies采用感到好奇的人,请查看Vue的创建者Evan You的answer