vue2源码学习(二)---监听数组的变化

在监听对象变化的基础上只修改了observe.js,新增了array.js

通过重写数组内的会改变数组本身的方法进行监听数组的变化

//observe.js
import { newArrayProto } from './array' class Observer { constructor (data) { console.log(data,this) // Object.defineProperty只能劫持已经存在的属性(所以vue里定义了$set,$delete) Object.defineProperty(data,'__ob__',{ value:this, enumerable:false//将__ob__变为不可枚举(循环的时候无法获取,避免死循环) }) // data.__ob__ = this //判断是否是数组 if (Array.isArray(data)) { // 重写数组部分方法(保留数组原有的特性) data._proto_ = newArrayProto this.observeArray(data) } else { this.walk(data) } } walk (data) { //重新定义属性 Object.keys(data).forEach(key => defineReactive(data, key, data[key])) } observeArray (data) { data.forEach(item => observe(item)) } } export function defineReactive (target, key, value) {//闭包 observe(value) //对所有的对象进行属性劫持 Object.defineProperty(target, key, { get () {//取值的时候会执行get return value }, set (newV) {//修改的时候会执行set if (newV === value) return observe(newV)//防止新值为对象,所以对新值进行再次代理 value = newV }, }) } export function observe (data) { // 对data进行劫持 if (typeof data !== 'object' || data == null) { return;//只对对象进行劫持 } if(data.__ob__ instanceof Observer){ return } // 如果一个对象被劫持过了,就不需要再劫持了(判断一个对象是否被接吃过,可以增添一个实例,用实例来判断) return new Observer(data) }
//array.js重写数组中的部分方法
let oldArrayProto = Array.prototype

export let newArrayProto = Object.create(oldArrayProto)

//所有能修改原数组的方法
let methods = [
  'push',//向数组的末尾添加一个或更多元素,并返回新的长度。
  'pop',//删除数组的最后一个元素并返回删除的元素。
  'shift',//    删除并返回数组的第一个元素。
  'unshift',//向数组的开头添加一个或更多元素,并返回新的长度。
  'reverse',//反转数组的元素顺序。
  'sort',//对数组进行排序(可以穿进去一个函数)
  'splice',//splice(n,m)删除数组的第n个到第m-1个(不包含m个)从数组中添加或删除元素。
]

methods.forEach(method => {
  newArrayProto[method] = function (...args) {//重写数组方法
    const result = oldArrayProto[method].call(this, ...args)//内部调用原来的方法,函数的劫持,切片编程
    //需要对新增的数据再次进行劫持
    let ob = this.__ob__
    let inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
      default:
        break
    }
    console.log(inserted) //新增的内容
    if (inserted) {
      //  对新增的内容再次进行劫持
      ob.observeArray(inserted)

    }

    return result
  }
})

 

posted @ 2022-07-03 18:36  cuteyuchen  阅读(1595)  评论(0编辑  收藏  举报