javascript --- vue2.x中原型的使用(拦截数组方法) 响应式原理(部分)
说明
在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中,使用了修改原型链的结构的方式来对数组的变化进行拦截.
先看下面的关系
- 原本的关系图示已经描述的很清楚了
- 我们对pop和push的拦截的原理
- 实际上是对Array原型上的
pop、push
方法进行重写 - 但是我们不可能直接在这个原型上重写(因为有些数组的实例,并不需要响应式).
- 因此我们在
arr
和Array.prototype
之间添加一层arr_methods
,改进后的关系如下
【具体的实现思路】:
先创建一个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中原型的使用(拦截数组方法) 响应式原理(部分)相关推荐
- 【Vue3中的响应式原理】
Vue3响应式原理 在Vue2的响应式中,存在着新增属性,删除属性以及直接通过下标修改数组,但页面不会自动更新的问题.但是在Vue3中,这些问题都得以解决. Vue2中的响应式原理 首先我们先看一下V ...
- Day 05- Vue3 Vue2响应式原理
Vue2的响应式 核心:通过 Object.defineProtytype() 对对象的已有属性值的读取和修改进行劫持: 数据劫持 --> 给对象扩展属性 --> 属性设置 实现原理: ...
- Vue2.0 —— 由设计模式切入,实现响应式原理
Vue2.0 -- 由设计模式切入,实现响应式原理 <工欲善其事,必先利其器> 既然点进来了,麻烦你看下去,希望你有不一样的收获. 大家好,我是vk,好久不见,今天我们一起来盘一盘关于 V ...
- Vue2的响应式原理
--------Vue2响应式原理---------- 原理:通过数据劫持 defineProperty + 发布订阅者模式,当 vue 实例初始化后 observer 会针对实例中的 data 中的 ...
- vue2响应式原理解析并实现一个简单响应系统
vue2响应式原理 Object.defineProperty() 要理解 vue2 数据响应式原理,我们首先要了解Object.defineProperty()方法.下面这些概念引自MDN. Obj ...
- 【Vuejs】952- 一文带你了解vue2之响应式原理
在面试的过程中也会问到:请阐述vue2的响应式原理?,凡是出现阐述或者理解,一般都是知无不言言无不尽,知道多少说多少.接下来,我来谈谈自己的理解,切记不要去背,一定要理解之后,用自己的语言来描述出来. ...
- 前端清单:Vue2 响应式原理,RN 运行内置 Node,JS 巧用 Proxy 反混淆,GraphQL 优劣思辨...
前端每周清单第 25 期:Vue2 响应式原理,RN 运行内置 Node,JS 巧用 Proxy 反混淆,GraphQL 优劣思辨,深入 React 动画 作者:王下邀月熊 编辑:徐川 前端每周清单专 ...
- vue2的动画,混入Mixin,插件,指令,渲染函数,响应式,MVVM
文章目录 过渡 & 动画 Transition 组件 基于 CSS 的过渡效果 CSS 过渡类名 class 为过渡效果命名 CSS 过渡 transition 实例1: 实例2: CSS 动 ...
- vue2和vue3响应式原理
vue2响应式原理:核心使用Object.defineProperty给属性定义get和set方法 注意:对象的多次递归,针对数组需要重写数组方法 函数劫持:把函数内部进行重写同时继续调用老的方法,在 ...
最新文章
- C# 窗体实例化一次
- 【top-k】Answering Topk Queries with MultiDimensional Selections: The Ranking Cube Approach
- php中解析数组,在PHP中解析多维数组
- 如何得到长整数逆序后的整数
- 语音识别学习日志 2019-7-14 语音识别基础知识准备3 {Kmean算法分析与HMM(Hidden Markov Model)模型}
- 消息队列面试 - 如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
- Apache 403 错误。。
- 玩转springboot2.x之搭建Thymeleaf官方示例程序
- Java LocalDateTime
- 【JavaScript学习笔记】计算机编程基础
- linux版本的caj,同方知网文献阅读器CAJViewer for Linux版本安装说明
- 使用ACCESS数据库时出现“操作必须使用一个可更新的查询”的解决办法
- HTML5视频方案:支持iPad Safari、Firefox、Chrome、IE9876
- SpaceSyntax【空间句法】之DepthMapX学习:第一篇 数据的输入 与 能做哪些分析
- 11岁的Tumblr:开启艰难禁黄之路
- 诺手c语言教程,《云顶之弈》黑夜使者阵容运营技巧 黑夜使者怎么玩
- Bitly:构建月处理60亿点击的分布式系统
- 惊!又一家知名企业被查!
- AI实战:文本自动摘要简述
- Linux下php重启的问题
热门文章
- REHL yum的配置(本地和centos源)
- wpfdiagram 学习 教学_李倩、吴欣歆:新高考背景下高中语文教学的三个转变
- 切片器可以设置日期格式?_Power BI 中的切片器
- python中csv文件通过什么表示字符_python_写入csv文件时候无法进行原样写入(写入字符串中出现逗号,时候,csv文件自动分成两个单元格)...
- 【caffe-windows】全卷积网络特征图分析
- 运动合成——机器学习技术
- 第一章:线性空间和线性变换
- linux 查看进程
- 【LeetCode】200. 岛屿的个数
- 修改Jupyter的工作空间