关于Vue数组操作

Vue的数组操作的实现代码大致如下:

const aryMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
const arrayAugmentations = [];

aryMethods.forEach((method)=> {

    // 这里是原生Array的原型方法
    let original = Array.prototype[method];

   // 将push, pop等封装好的方法定义在对象arrayAugmentations的属性上
   // 注意:是属性而非原型属性
    arrayAugmentations[method] = function () {
        console.log('我被改变啦!');

        // 调用对应的原生方法并返回结果
        return original.apply(this, arguments);
    };

});

let list = ['a', 'b', 'c'];
// 将我们要监听的数组的原型指针指向上面定义的空数组对象
// 别忘了这个空数组的属性上定义了我们封装好的push等方法
list.__proto__ = arrayAugmentations;
list.push('d');  // 我被改变啦! 4

// 这里的list2没有被重新定义原型指针,所以就正常输出
let list2 = ['a', 'b', 'c'];
list2.push('d');  // 4

在Vue的官方文档中,有着如下的提示:

  1. 当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如: vm.items.length = newLength

这个是Js语法的限制,什么限制呢?

先来看一下,在这篇文章中写到,为什么不利用如下的代码来实现:

function FakeArray() {
  return  Array.call(this,arguments);
}

FakeArray.prototype = [];
FakeArray.prototype.constructor = FakeArray;

FakeArray.prototype.push = function () {
    console.log('我被改变啦');
    return Array.prototype.push.call(this,arguments);
};

let list = ['a','b','c'];

let fakeList = new FakeArray(list);

然而,作者在测试代码的时候,发现fakeList实际上是一个数组,而且它的push是内置的push方法,并不是继承FakeArray的方法。

在作者文章的评论中,有个网友评论说,这是因为Array.call并不会引用this,不止Array,String,Number,Regexp,Object等等JS的内置类都不行。

所以实际上代码是这样的:

function FakeArray() {
  return  Array(arguments);
}

这也就是ES5以下无法完美继承数组的问题,回过头看一下Vue中的实现,Vue的作者用的是__proto__属性,该属性指向构造对象的原型。

也就是说,上面的例子我们可以这样改写:

function FakeArray() {
  var x =  Array.call(null,arguments);
   x.__proto__ = FakeArray.prototype
   return x;
}

FakeArray.prototype = [];
FakeArray.prototype.constructor = FakeArray;

FakeArray.prototype.push = function () {
    console.log('我被改变啦');
    return Array.prototype.push.call(this,arguments);
};

let list = ['a','b','c'];

let fakeList = new FakeArray(list);

但是呢,这样写,也就意味着我们不能检测到length,和fakeList[x] = 1;这样的操作,也就有了Vue文档中的提示了。

本文参考自https://github.com/youngwind/blog/issues/85及其评论。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript设计模式 观察者模式

    观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时...

    菜的黑人牙膏
  • zepto的构造器$

    fragmentRE是一个匹配普通标签<xxx>的表达式,关键是zepto.fragment()函数。

    菜的黑人牙膏
  • backbond整体架构

    原文地址:https://segmentfault.com/a/1190000006697372

    菜的黑人牙膏
  • 苹果申请加州测试牌照获批,无人驾驶项目Titan再加速

    大数据文摘
  • 如何参与 Kubernetes 文档的本地化工作

    去年我们对 Kubernetes 网站进行了优化,加入了多语言内容的支持。贡献者们踊跃响应,加入了多种新的本地化内容:截至 2019 年 4 月,Kuberne...

    CNCF
  • 苹果自动驾驶发生首起车祸,泰坦项目路测曝光

    苹果公司在向加州车管局(DMV)提交的一份文件中披露,它的一辆自动测试车辆发生了撞车事故:被另一辆车追尾。

    新智元
  • 业界 | 苹果自动驾驶汽车遭遇首次车祸

    苹果的高管们从未公开谈论过该公司的自动驾驶汽车计划,但今年 7 月份前员工张晓浪涉嫌窃取商业机密被 FBI 逮捕事件中的法律文件曾经向我们透露了一些信息:苹果公...

    机器之心
  • 进军自动驾驶,苹果来的未免太迟了

    镁客网
  • CTF| SQL注入之login界面

    SQL注入是CTF WEB方向必不可少的一种题型,斗哥最近也做了一些在线题目,其中最常见的题目就是给出一个登录界面,让我们绕过限制登录或者一步步注入数据。 万...

    漏斗社区
  • LastPass密码管理器再曝严重漏洞,基于浏览器的密码管理器还能用吗?

    没有使用密码软件前,大家容易忘记密码;使用密码软件后,大家“无奈地”泄露了所有密码。LastPass,最受欢迎的密码管理软件之一,近日再次爆出安全漏洞。安全人员...

    FB客服

扫码关注云+社区

领取腾讯云代金券