《深入浅出vue.js》阅读笔记之数组变化侦测
1、如何追踪变化
数组的侦测方式和对象不同,比如:
this.list.push(1)
此时并不会像改变对象一样触发setter。
同理,要侦测数组的变化意味着我们在改变数组的时候得到通知,如图,我们可以用一个拦截器覆盖Array.prototype,每当使用array原型方法时,实际
执行的是拦截器中的方法,而拦截器中的方法储存原生方法实现。

2、实现拦截器
拦截器其实是一个和Array.prototype一样的object,只不过这个object中某些可以改变数组自身内容的方法是处理过的。
改变数组内容的方法一共有七个,push,pop,shift, unshiftj, slice, sort 和reverse
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
const methods = ['pop', 'push', 'shift', 'unshift', 'splice', 'sort', 'reverse']
methods.forEach(function (method) {
// 缓存原始方法
const original = arrayProto[method]
Object.defineProperty(arrayMethods, method, {
value: function mutator (...args) {
return original.apply(this, args)
},
enumerable: false,
writable: true,
configurable: true,
})
})
上面代码中,arrayMethods继承自Array.prototype,具备其所有功能。当使用push方法时,调用的是arrayMethods.push,即mutator函数,这里可以做一些发送通知
变化之类的事情。
3、使用拦截器覆盖Array原型
有了拦截器,就需要让它覆盖Array.prototype,但又不能直接覆盖,因为会污染全局变量Array,我们希望只是拦截那些被侦测了变化的数据生效。
这时就需要借助Observer
class Observer {
constructor (value) {
this.value = value
}
if (Array.isArray(value)) {
value.__proto__ = arrayMethods
} else {
this.walk(value)
}
}
它的作用是将拦截器(加工后具备拦截功能的arrayMethods)赋值给value.__proto__,通过__proto__巧妙的实现覆盖value原型功能。

__proto__其实是Object.getPrototypeOf和Object.setPrototypeOf的早期实现,所以使用es6的Object.setPrototypeOf来代替__ptoto__可以实现同样的效果。
4、将拦截器方法挂载到数组属性上
虽然绝大多数浏览器都支持这个非标准的属性来访问原型,但并不是所有浏览器都支持,因此需要处理不能使用__proto__的情况。
vue的做法是对于不能使用__proto__的,直接将arrayMethods身上的这些方法设置到被侦测的数组上。
export class Object {
if (Array.isArray(value)) {
const augment = hasProto ? protoAugment : copyAugment
augment(value, arrayMethods, arrayKeys)
} else {
this.walk(value)
}
}
function protoAugment (target, src, keys) {
target.__proto__ = src
}
function copyAugment (target, src, keys) {
for (let i=0, len = keys.lenght;i< 1; i++) {
const key = keys[i]
default(target, key, src[key])
}
}
在上面代码中,新增了hasProto来判断当前浏览器是否支持__proto__,如果支持,则使用protoAugment覆盖原型,否则用copyAugment将拦截器中的方法挂载到value。
copyAugment函数用来将已经加工了拦截操作的原型方法直接添加到value的属性中。

《深入浅出vue.js》阅读笔记之数组变化侦测的更多相关文章
- vue.js 学习笔记3——TypeScript
目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...
- Vue.js学习笔记(2)vue-router
vue中vue-router的使用:
- Vue.js学习笔记:在元素 和 template 中使用 v-if 指令
f 指令 语法比较简单,直接上代码: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " ...
- Vue中Object和Array数据变化侦测原理
在学完Vue.js框架,完成了一个SPA项目后,一直想抽时间找本讲解Vue.js内部实现原理的书来看看,经过多方打听之后,我最后选择了<深入浅出Vue.js>这本书.然而惭愧的是,这本书已 ...
- 手牵手,从零学习Vue源码 系列二(变化侦测篇)
系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...
- 《深入浅出vue.js》阅读笔记之(object)变化侦测
1.什么是变化侦测? 通常,在运行时应用内部的状态会不断发生变化,此时需要不停地重新渲染页面,这时如何确定状态中发生了什么变化? 变化侦测就是用来解决这个问题的,它分为两种类型,一种是"推& ...
- Vue.js——学习笔记
Vue-自学笔记 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅 ...
- Vue.js 学习笔记 第5章 内置指令
本篇目录: 5.1 基本指令 5.2 条件渲染指令 5.3 列表渲染指令 v-for 5.4 方法与事件 5.5 实战:利用计算属性.指令等知识开发购物车 回顾一下第2.2节,我们己经介绍过指令(Di ...
- Vue.js 学习笔记 第4章 v-bind 及 class与style绑定
本篇目录: 4.1 了解v-bind指令 4.2 绑定class的几种方式 4.3 绑定内联样式 DOM元素经常会动态地绑定一些class类名或style样式,本章将介绍使用v-bind指令来绑定cl ...
随机推荐
- 关于hive的基础
Hive基础 1.引入原因 对存在HDFS上的文件或HBase中的表进行查询时,是要手工写一堆MapReduce代码 对于统计任务,只能由懂MapReduce的程序员才能搞定 事实上,许多底层细节实际 ...
- C语言:字符编码
C语言是 70 年代的产物,那个时候只有 ASCII,各个国家的字符编码都还未成熟,所以C语言不可能从底层支持 GB2312.GBK.Big5.Shift-JIS 等国家编码,也不可能支持 Unico ...
- 00JAVA语法基础_四则运算 01
自动生成30道四则运算的数学题,当前只是简单符合出题,答题和判断的代码,还没做要求,所以现在只是能随机生成三十道100以内的加减法和九九乘法表的乘除法 package Sizeyunsuan; /** ...
- springMVC-3-获取参数
RequestMapping修饰类 源码: 根据源码可以知道,requestmapping既可以修饰方法也可以修饰类 @Target({ElementType.METHOD, ElementType. ...
- 微信小程序云开发-云存储的应用-识别身份证(正面和反面)
一.准备工作 1.创建云函数identify 2.云函数identify中index.js代码 1 // 云函数入口文件 2 const cloud = require('wx-server-sdk' ...
- like %和-的区别与使用
通配符的分类: %百分号通配符:表示任何字符出现任意次数(可以是0次). 下划线通配符:表示只能匹配单个字符,不能多也不能少,就是一个字符. like操作符: LIKE作用是指示mysql后面的搜索模 ...
- IOS自动化测试环境搭建(Python & Java)
一.前言 IOS的App自动化测试与Android的一样,也可以用appium来进行.但是IOS自动化依赖苹果的osx系统.Xcode构建等,且封闭的系统需要苹果开发者账号才可以驱动真机.A ...
- 八数码难题之 A* 算法
人生第一个A*算法-好激动-- 八数码难题--又称八数码水题,首先要理解一些东西: 1.状态可以转化成整数,比如状态: 1 2 3 4 5 6 7 8 0 可以转化成:123456780这个整数 2. ...
- 根据JavaScript中原生的XMLHttpRequest实现jQuery的Ajax
基本介绍 XmlHttpRequest XmlHttpRequest是JavaScript中原生的,历史悠久的一种发送网络请求的方案. 基本上所有前端框架对于网络请求的部分都是基于它来完成的. 在本章 ...
- Github连接远程仓库详细操作
首先 咱们需要配置ssh密钥 如何生成密钥呢 我们先来看下命令 在桌面新建一个文件夹,命名规范尽量不要使用中文,然后在文件夹内 新建测试文本: 如图 在文件夹内空白处右击进入GIt b ...