说明

在Vue2.x中,利用了对原型链的理解,巧妙的利用JavaScript中的原型链,实现了数组的pop、push、shift、unshift、reverse、sort、splice等的拦截.

你可能需要的知识

  • 参考 - MDN

原型链

JavaScript常被描述为一种基于原型的语言(prototype-based language),每个对象拥有一个原型.
数组类型也不例外.验证如下:

let arr = [];
console.log(arr)
/*{length: 0__proto__: {length: 0constructor: f Array()...__proto__: Object}}
*/

可见数组的原型是继承于Object。

响应式

参考 - MDN
响应式的核心是使用Object.defineProperty在对数据进行读取或者写入时进行劫持操作.

let o = {}
,_gender
Object.defineProperty(o, gender, {get(){return _gender},set(newVal){_gender = newVal}
})

对一个属性,同时使用get和set方法时,需要一个中间变量取存储,否则会造成循环使用.

Vue 2.x中的响应式

  • Vue在使用过程中,可能会用到很多的变量,而每把一个数据进行响应式化,就需要一个变量去存储.这样有可能会污染全局作用域.
  • Vue中采取的方法是使用函数的形参,来实现响应式,实现如下
function defineReactive(target, key, value, enumerable){// 注意: 此处的value与上文的_gender类型Object.defineProperty(target, key, {configurable: true,enumerable: !!enumerable,get(){console.log(`读取${value}`)return value},set(newVal){console.log(`写入: ${value} --> ${newVal}`)value = newVal}})
}
let o = {name: 'marron',age: 26,remark: 'hunt for job'
}
Object.keys(o).forEach(k => {defineReactive(o,k,o[k],true)
})


以上实现了对数据的拦截: 即对数据进行 写入/读取 操作时,会按照一定规则优先执行某些步骤.
但是以上代码还存在一些小小的瑕疵

对象深层次

以上代码不对对象的深层次进行响应式化,如下面数据

let o = {list: [ { person1: {name:'Marron',age: 18}},{person2: {name:'Mar',age: 25}}]
}


此时,需要考虑数组,和对象的子元素问题.
对于数组问题,我们修改遍历,如果是数组,则取出数组中的每个元素,进行添加响应式处理

- Object.keys(o).forEach(k =>{
-   defineReactive(o, k, o[k], true)
- })
+ function reactify(o){
+  Object.keys(o).forEach(k => {
+      if(Array.isArray(o[k])){
+          o[k].forEach(val => reactive(val))
+      } else {
+          defineReactive(o, k, o[k], true)
+      }
+ })}

对于深层次对象问题,我们对defineReactive进行修改

function defineReactive(o, key, value, enumerable){if(typeof value =='object' && value !== null && !Array.isArray(value)){// 此处可以认为是对象reactify(value)}// 此处是最后一层,添加响应式Object.defineProperty(o, key, {configurable: true,enumerable: !!enumerable,get(){console.log(`读取${key}`)return value},set(newVal){console.log(`写入${key} => ${newVal}`)value = newVal}})
}

Vue2.x对数组部分方法的拦截

上面的响应式无法对数组的pop、push等方法进行响应

在Vue2.x中,使用了修改原型链的结构的方式来对数组的变化进行拦截.
先看下面的关系

arr
Array.prototype
Object.prototype
  • 原本的关系图示已经描述的很清楚了
  • 我们对pop和push的拦截的原理
  • 实际上是对Array原型上的pop、push方法进行重写
  • 但是我们不可能直接在这个原型上重写(因为有些数组的实例,并不需要响应式).
  • 因此我们在arrArray.prototype之间添加一层arr_methods,改进后的关系如下
arr
arr_methods
Array.prototype
Object.prototype

【具体的实现思路】:
先创建一个arr_methods对象其原型是Array.prototype.然后修改arr_methods上需要拦截的方法(存储在数组ARRAY_METHOD中)

const ARRAY_METHOD = ['push','pop','shift','unshift','reverse','sort','splice'
]
let arr_methods = Object.create(Array.prototype)ARRAY_METHOD.forEach(method=>{arr_methods[method] = function(){// 拦截的函数console.log(`调用${method}方法`) return Array.prototype[method].apply(this, arguments)}
})
arr.__proto__ = arr_methods


此时既不影响原生的Array.prototype,又实现了对pop、push...方法的拦截,完成之后只需要修改前面的方法.即可完成对数组pop、push方法的拦截

 function reactify(o){Object.keys(o).forEach(k => {if(Array.isArray(o[k])){// 数组方法的响应式o[k].__proto__ = array_method
.           o[k].forEach(val => reactive(val))} else {defineReactive(o, k, o[k], true)}})}

最后,此时只是拦截,还差一步形成响应式

ARRAY_METHOD.forEach(method=>{arr_methods[method] = function(){// 拦截的函数console.log(`调用${method}方法`)for(let i =0, len = arugments.length; i < len; i++){reactify(arguments[i])}return Array.prototype[method].apply(this, arguments)}
})

javascript --- vue2.x中原型的使用(拦截数组方法) 响应式原理(部分)相关推荐

  1. 【Vue3中的响应式原理】

    Vue3响应式原理 在Vue2的响应式中,存在着新增属性,删除属性以及直接通过下标修改数组,但页面不会自动更新的问题.但是在Vue3中,这些问题都得以解决. Vue2中的响应式原理 首先我们先看一下V ...

  2. Day 05- Vue3 Vue2响应式原理

    Vue2的响应式 核心:通过 Object.defineProtytype() 对对象的已有属性值的读取和修改进行劫持: 数据劫持  --> 给对象扩展属性 -->  属性设置 实现原理: ...

  3. Vue2.0 —— 由设计模式切入,实现响应式原理

    Vue2.0 -- 由设计模式切入,实现响应式原理 <工欲善其事,必先利其器> 既然点进来了,麻烦你看下去,希望你有不一样的收获. 大家好,我是vk,好久不见,今天我们一起来盘一盘关于 V ...

  4. Vue2的响应式原理

    --------Vue2响应式原理---------- 原理:通过数据劫持 defineProperty + 发布订阅者模式,当 vue 实例初始化后 observer 会针对实例中的 data 中的 ...

  5. vue2响应式原理解析并实现一个简单响应系统

    vue2响应式原理 Object.defineProperty() 要理解 vue2 数据响应式原理,我们首先要了解Object.defineProperty()方法.下面这些概念引自MDN. Obj ...

  6. 【Vuejs】952- 一文带你了解vue2之响应式原理

    在面试的过程中也会问到:请阐述vue2的响应式原理?,凡是出现阐述或者理解,一般都是知无不言言无不尽,知道多少说多少.接下来,我来谈谈自己的理解,切记不要去背,一定要理解之后,用自己的语言来描述出来. ...

  7. 前端清单:Vue2 响应式原理,RN 运行内置 Node,JS 巧用 Proxy 反混淆,GraphQL 优劣思辨...

    前端每周清单第 25 期:Vue2 响应式原理,RN 运行内置 Node,JS 巧用 Proxy 反混淆,GraphQL 优劣思辨,深入 React 动画 作者:王下邀月熊 编辑:徐川 前端每周清单专 ...

  8. vue2的动画,混入Mixin,插件,指令,渲染函数,响应式,MVVM

    文章目录 过渡 & 动画 Transition 组件 基于 CSS 的过渡效果 CSS 过渡类名 class 为过渡效果命名 CSS 过渡 transition 实例1: 实例2: CSS 动 ...

  9. vue2和vue3响应式原理

    vue2响应式原理:核心使用Object.defineProperty给属性定义get和set方法 注意:对象的多次递归,针对数组需要重写数组方法 函数劫持:把函数内部进行重写同时继续调用老的方法,在 ...

最新文章

  1. C# 窗体实例化一次
  2. 【top-k】Answering Topk Queries with MultiDimensional Selections: The Ranking Cube Approach
  3. php中解析数组,在PHP中解析多维数组
  4. 如何得到长整数逆序后的整数
  5. 语音识别学习日志 2019-7-14 语音识别基础知识准备3 {Kmean算法分析与HMM(Hidden Markov Model)模型}
  6. 消息队列面试 - 如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
  7. Apache 403 错误。。
  8. 玩转springboot2.x之搭建Thymeleaf官方示例程序
  9. Java LocalDateTime
  10. 【JavaScript学习笔记】计算机编程基础
  11. linux版本的caj,同方知网文献阅读器CAJViewer for Linux版本安装说明
  12. 使用ACCESS数据库时出现“操作必须使用一个可更新的查询”的解决办法
  13. HTML5视频方案:支持iPad Safari、Firefox、Chrome、IE9876
  14. SpaceSyntax【空间句法】之DepthMapX学习:第一篇 数据的输入 与 能做哪些分析
  15. 11岁的Tumblr:开启艰难禁黄之路
  16. 诺手c语言教程,《云顶之弈》黑夜使者阵容运营技巧 黑夜使者怎么玩
  17. Bitly:构建月处理60亿点击的分布式系统
  18. 惊!又一家知名企业被查!
  19. AI实战:文本自动摘要简述
  20. Linux下php重启的问题

热门文章

  1. REHL yum的配置(本地和centos源)
  2. wpfdiagram 学习 教学_李倩、吴欣歆:新高考背景下高中语文教学的三个转变
  3. 切片器可以设置日期格式?_Power BI 中的切片器
  4. python中csv文件通过什么表示字符_python_写入csv文件时候无法进行原样写入(写入字符串中出现逗号,时候,csv文件自动分成两个单元格)...
  5. 【caffe-windows】全卷积网络特征图分析
  6. 运动合成——机器学习技术
  7. 第一章:线性空间和线性变换
  8. linux 查看进程
  9. 【LeetCode】200. 岛屿的个数
  10. 修改Jupyter的工作空间