热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue源码系列之响应式数据处理2数组的重写

目录vue源码系列之响应式数据处理2数组的重写

目录

vue源码系列之 响应式数据处理2 数组的重写

vue源码系列之 响应式数据处理1 链接: link.

array.js

  • 对数组的方法进行重写
    • oldArrayPrototype 原始的数组方法
    • arrayMethos = Object.create(oldArrayPrototype) 创建一个新的对象,也就是拷贝原始数组的方法
    • methods 中的方法,是会影响原始数组的,因此需要重写这些方法
    • 遍历这些会改原始数组的方法,然后执行步骤是
      • 先执行自己定义的arrayMethos 方法,之后再调用原始数组的方法
      • 其中最主要的是:假如args传入的实参为 对象时候 则需要特殊处理
      • inserted 为新增要插入的数据( [ [1,2,3] , {name:“ppp”} ] )类似这种需要特殊处理
      • 然后假设有新增数据时,则需要继续劫持,观测数组里面的每一项数据

let oldArrayPrototype = Array.prototype; // 原始的数组方法
export let arrayMethos = Object.create(oldArrayPrototype); // 数组方法的重写
// 其中arrayMethos_proto_ = Array.prototype
let methods = [
'push',
'shift',
'unshift',
'pop',
'reverse',
'sort',
'splice'
]
methods.forEach(method => {
// 用户调用了以上几个方法 会用自己重写的,否者使用原来的数组方法
arrayMethos[method] = function (...args) { // 先调用自己写的方法,之后调用内部原有的方法
// console.log("改变了原始数组"); // arr.push(1,2) -> [1,2]
oldArrayPrototype[method].call(this, ...args);
// 假如args传入的实参为 对象时候 则需要特殊处理
let inserted;
let ob = this.__ob__; // 根据当前数组实例获取到observer实例对象
switch (method) {
case "push":
case "unshift":
args; // 就是新增的内容
case "splice":
args.slice(2)
default:
break;
}
// 如果有新增的内容 要进行继续劫持, 我需要观测的数组里的每一项,而不是数组
if (inserted) ob.observeArray(inserted);
// 如果数组中的数据是对象类型,需要监控对象的变化
}
})

observe / index.js

  • 作用:观察者监听数据的变化,实现数据的响应式
  • 执行流程:
  • Observer观察者之内首先判断是对象还是数组
    • 是对象的时候,则是执行 walk() 方法,对对象属性的劫持,转化为响应式属性
      • 其中转化为响应式属性是采用 Object.defineProperty方法
      • 值得注意的是:若是设置新值时,为对象,则需要继续监听
      • 因此对于 data.__ob__属性,则需要设置为不可枚举,否者会陷入死循环
    • 为数组的时候:
      • 拿到重写的方法,赋值给当前对象的属性,也就是重写的方法
      • 值得注意的是:数组内含有数组或者对象时候,又需要针对数组进行监听 this.observeArray(data);
      • observeArray(data)遍历数组中的每一项,然后进行观测 observe(item)
    • 引入 数组重写的方法 arrayMethos

import {
arrayMethos
} from "../array";
import {
isObject
} from "../utils";
// 检测数据的变化 类是有类型的,对象是无类型!
class Observer {
constructor(data) { // 对对象中的所有属性 进行劫持
Object.defineProperty(data, '__ob__', {
value: "this",
enumerable: false, //不可枚举 之后也就无法遍历到 walk()
})
if (Array.isArray(data)) { // 数组劫持 -> 对数组的原来方法进行改写,切片编程,高阶函数
data.__proto__ = arrayMethos;
// 如果数组中的数据是对象类型,需要监控对象的变化
this.observeArray(data);
} else {
this.walk(data); // 对每一个对象劫持后 调用一次
}
}
// 遍历数组
observeArray(data) { // 针对数组中的数组 和 数组中的对象再一次劫持 递归了
data.forEach(item => {
observe(item)
})
}
// 遍历对象
walk(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key]); // 把对象中的属性 定义为响应式数据
})
}
}
// vue2 对对象进行遍历后 将每个属性 用defineProperty重新定义 -> 造成性能较差
function defineReactive(data, key, value) {
// 注意点:就是value为对象的时候,需要再劫持
observe(value); // 本身默认传入的数据为对象套对象时,则需要递归劫持
// console.log("defineReactive", data, key, value); // defineReactive {name: 'xpl'} name xpl
Object.defineProperty(data, key, {
get() { // 取值
return value;
},
set(newVal) { // 设置data新的值
observe(newVal) // 对数据进行修改时 是一个对象,又需要劫持,修改为响应式数据
value = newVal;
}
})
}
// 观察者 监听data数据
export function observe(data) {
// console.log("observe内的", data); // observe内的 {name: 'xpl'}
// 如果为对象的时候 才观测
if (!isObject(data)) {
return;
}
if (data.__ob__) { // 如果数组已经被劫持了观测过了
return;
}
// 默认而言 data是一个对象
return new Observer(data)
}

推荐阅读
  • 一、vue介绍Vue.js是一套构建用户界面(UI)的渐进式JavaScript框架,是一个轻量级MVVM(model-view-viewModel&# ... [详细]
  • 最近想用js做一个简单的计算器,不过网上的例子好像大部分都是直接从左到右挨个计算,就好像1+2*5,就会先计算1+2,再计算3*5,并没有实现运算符的优先级,这里找到了一种方法实现,来总结一下。不过这 ... [详细]
  • 作者|相学长原文|https:github.comwuomzfxblogblobmasterthis.md日常开发中,我们经常用到this。例如用Jquery绑定事件 ... [详细]
  • 开发笔记:js正则表达式属性及方法的使用
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了js正则表达式属性及方法的使用相关的知识,希望对你有一定的参考价值。正则表达式直接量 ... [详细]
  • 前端微服务二
    为了解决庞大的一整块后端服务带来的变更与扩展方面的限制,出现了微服务架构(Microservices):微服务是面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒 ... [详细]
  • 22.Container With Most Water(能装最多水的容器)
    thecontainercontainsthemos ... [详细]
  • 最近在做一个大屏项目,有一个需求视频做背景,这个在vue开发的时候做了很多遍了,以为手到擒来。背景分析前端框架:UMIved ... [详细]
  • 2019.4.14第1001题:SumProblemProblemDescriptionHey,welcometoHDOJ(HangzhouDianziUniversityOnli ... [详细]
  • 【自制小工具】代码生成器
    【自制小工具】代码生成器陆陆续续接触过好几款代码生成工具,发现确实好用,但都会有那么点不完善的地方,所以索性就自己做一个吧。界面非常简单,反正是自己用的,简单点用起来也方便上图:左 ... [详细]
  • 例子如Table表有性别字段,1代表男2代表女、3代表中性、还有没填就代表未说明selectid,decode(sex,'1','男', ... [详细]
  • 接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对 ... [详细]
  • 原数据vararr_obj[{current_period_val:896,etl_tmtimestamp:06-30},{current_period_val ... [详细]
  • 1、创建高级对象使用构造函数来创建对象构造函数是一个函数,调用它来例示并初始化特殊类型的对象。可以使用new关键字来调用一个构造函数。下面给出了使用构造函数的新示例。 ... [详细]
  • 日期:2012-4-7来源:GBin1.com在线演示本地下载今天我们介绍一个超棒的创建快速动态互动HTML5可视化图形效果的javascript类库-Envision.j ... [详细]
  • 媒介本日再看React纯函数的时刻,看到纯函数历程没有副作用,就是说在纯函数中我们不能转变外部状况.想到了之前看过的函数中传参的观点.数据范例在js中,数据范例分为两类:基础范例值 ... [详细]
author-avatar
你问什么只为她停留_538
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有