欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue數(shù)組的劫持逐步分析講解

 更新時(shí)間:2023年01月06日 15:59:25   作者:BraveWangDev  
小編這次要給大家分享的是如何實(shí)現(xiàn)vue2.x數(shù)組劫持,文章內(nèi)容豐富,感興趣的小伙伴可以來(lái)了解一下,希望大家閱讀完這篇文章之后能夠有所收獲

一,前言

上篇,主要介紹了 Vue 數(shù)據(jù)初始化流程中,對(duì)象屬性的深層劫持是如何實(shí)現(xiàn)的

核心思路就是遞歸,主要流程如下;

1.通過(guò) data = isFunction(data) ? data.call(vm) : data;處理后的 data 一定是對(duì)象類(lèi)型

2.通過(guò) data = observe(data)處理后的 data 就實(shí)現(xiàn)了數(shù)據(jù)的響應(yīng)式(目前只有劫持)

3.observe 方法最終返回一個(gè) Observer 類(lèi)

4.Observer 類(lèi)初始化時(shí),通過(guò) walk 遍歷屬性

5.對(duì)每一個(gè)屬性進(jìn)行 defineReactive(Object.defineProperty)就實(shí)現(xiàn)對(duì)象屬性的單層數(shù)據(jù)劫持

6.在 defineReactive 中,如果屬性值為對(duì)象類(lèi)型就繼續(xù)調(diào)用 observe 對(duì)當(dāng)前的對(duì)象屬性進(jìn)行觀測(cè)(即遞歸步驟 3~5),這樣就實(shí)現(xiàn)了對(duì)象屬性的深層數(shù)據(jù)劫持

本篇,繼續(xù)介紹 Vue 數(shù)據(jù)初始化流程中,對(duì)于數(shù)組類(lèi)型的劫持

二,對(duì)象劫持回顧

1,Demo

data 數(shù)據(jù)中對(duì)象屬性的深層觀測(cè),即對(duì)象屬性為對(duì)象(包含多層)的情況

let vm = new Vue({
  el: '#app',
  data() {
    return { message: 'Hello Vue', obj: { key: "val" }, a: { a: { a: {} } } }
});

當(dāng) data 中的屬性為數(shù)組時(shí),Vue 是如何進(jìn)行處理的

三,數(shù)組類(lèi)型的處理

1,當(dāng)前邏輯分析

按照當(dāng)前版本的處理邏輯,所有對(duì)象類(lèi)型會(huì)對(duì)被進(jìn)行深層觀測(cè),數(shù)組也不例外

let vm = new Vue({
  el: '#app',
  data() {
    return { message: 'Hello Vue', obj: { key: "val" }, arr:[1,2,3]}
  }
});

可以看到,數(shù)組中的每一項(xiàng),都被添加了 get、set 方法,也就相當(dāng)于實(shí)現(xiàn)了對(duì)數(shù)組的深層觀測(cè)

備注:Object.defineProperty支持?jǐn)?shù)組數(shù)據(jù)類(lèi)型的劫持

2,Vue 對(duì)性能的權(quán)衡

在 Vue2.x 中,不支持通過(guò)修改數(shù)組索引和長(zhǎng)度的數(shù)據(jù)劫持;

那么,為什么原本可以實(shí)現(xiàn)對(duì)數(shù)組索引的觀測(cè),Vue 卻選擇了不支持呢?

主要是考慮了性能問(wèn)題,比如,數(shù)組中的數(shù)據(jù)量非常大時(shí):

let vm = new Vue({
  el: '#app',
  data() {
    return { arr:new Array(9999) }
  }
});

這時(shí),數(shù)組中 9999 條數(shù)據(jù),將全部被添加 get、set 方法

而這一套操作就比較費(fèi)勁了:為了實(shí)現(xiàn)數(shù)組索引劫持,需要對(duì)數(shù)組中每一項(xiàng)進(jìn)行處理

還有就是,雖然數(shù)組能夠通過(guò) defineProperty 實(shí)現(xiàn)對(duì)索引更新劫持

但在實(shí)際開(kāi)發(fā)場(chǎng)景真的需要嗎?似乎很少會(huì)使用 arr[888] = x 這種操作

所以,權(quán)衡性能和需求,Vue 源碼中沒(méi)有采用 defineProperty 對(duì)數(shù)組進(jìn)行處理

當(dāng)然,這也就導(dǎo)致了在 Vue 中無(wú)法通過(guò)直接修改索引、length 觸發(fā)視圖的更新

3,數(shù)組的劫持思路

核心目標(biāo)是要實(shí)現(xiàn)數(shù)組的響應(yīng)式:

Vue 認(rèn)為這 7 個(gè)方法能夠改變?cè)瓟?shù)組:push、pop、splice、shift、unshift、reverse、sort

所以,只要對(duì)這 7 個(gè)方法進(jìn)行處理,就能劫持到數(shù)組的數(shù)據(jù)變化,實(shí)現(xiàn)數(shù)組數(shù)據(jù)的響應(yīng)式

備注:這種實(shí)現(xiàn)思路,也直接導(dǎo)致了 vue2 修改數(shù)組的索引和長(zhǎng)度不能觸發(fā)視圖更新

梳理對(duì)象屬性深層劫持的實(shí)現(xiàn):

  • 數(shù)據(jù)觀測(cè)入口:src/observe/index.js#observe方法
  • 如果數(shù)據(jù)為對(duì)象類(lèi)型就 new Observer
  • Observer 初始化時(shí),會(huì)遍歷對(duì)象屬性,逐一遞歸 Object.defineProperty

數(shù)組也是對(duì)象,所以,要把數(shù)組的處理邏輯單獨(dú)拆出來(lái)。即對(duì) 7 個(gè)變異方法進(jìn)行重寫(xiě)

// src/utils
/**
 * 判斷是否是數(shù)組
 * @param {*} val 
 * @returns 
 */
export function isArray(val) {
  return Array.isArray(val)
}
// src/observe/index.js
import { arrayMethods } from "./array";
class Observer {
  constructor(value) {
    if(isArray(value)){
      // 對(duì)數(shù)組類(lèi)型進(jìn)行單獨(dú)處理:重寫(xiě) 7 個(gè)變異方法
    }else{
      this.walk(value);
    }
  }
}

4,數(shù)組方法的攔截思路

  • 重寫(xiě)方法需要在原生方法基礎(chǔ)上,實(shí)現(xiàn)對(duì)數(shù)據(jù)變化的劫持操作
  • 僅對(duì)響應(yīng)式數(shù)據(jù)中的數(shù)組進(jìn)行方法重寫(xiě),不能影響非響應(yīng)式數(shù)組

所以,對(duì)響應(yīng)式數(shù)據(jù)中數(shù)組這 7 個(gè)方法進(jìn)行攔截,即優(yōu)先使用重寫(xiě)方法,其他方法還走原生邏輯

數(shù)組方法的查找,先查找自己身上的方法(即重寫(xiě)方法),找不到再去鏈上查(原生方法)

5,數(shù)組方法重寫(xiě)的實(shí)現(xiàn)

// src/Observer/array.js
// 拿到數(shù)組的原型方法
let oldArrayPrototype = Array.prototype;
// 原型繼承,將原型鏈向后移動(dòng) arrayMethods.__proto__ == oldArrayPrototype
export let arrayMethods = Object.create(oldArrayPrototype);
// 重寫(xiě)能夠?qū)е略瓟?shù)組變化的七個(gè)方法
let methods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'reverse',
  'sort',
  'splice'
]
// 在數(shù)組自身上進(jìn)行方法重寫(xiě),對(duì)鏈上的同名方法進(jìn)行攔截
methods.forEach(method => {
  arrayMethods[method] = function () {
    console.log('數(shù)組的方法進(jìn)行重寫(xiě)操作 method = ' + method)
  }
});

添加 new Observer 時(shí),對(duì)數(shù)組方法重寫(xiě)的邏輯:

// src/observe/index.js
import { arrayMethods } from "./array";
class Observer {
  constructor(value) {
    // 分別處理 value 為數(shù)組和對(duì)象兩種情況
    if(isArray(value)){
      value.__proto__ = arrayMethods; // 更改數(shù)組的原型方法
    }else{
      this.walk(value);
    }
  }
}

測(cè)試數(shù)組方法的重寫(xiě):

數(shù)組的鏈:

  • array.proto:包含 7 個(gè)重寫(xiě)方法
  • array.proto.proto:原始方法

6,數(shù)組方法攔截的實(shí)現(xiàn)

// src/state.js#initData
function initData(vm) {
    let data = vm.$options.data;
    data = isFunction(data) ? data.call(vm) : data;
    observe(data);	// 在observe方法中new Observer執(zhí)行后,數(shù)組的原型方法已完成重寫(xiě)
    // 測(cè)試數(shù)組方法的攔截效果
    data.arr.push(666); 
    data.arr.pop()
}

  • arrayMethods.push:會(huì)在數(shù)組自身找到重寫(xiě)的push方法,不會(huì)繼續(xù)到鏈上查找,實(shí)現(xiàn)攔截
  • arrayMethods.pop:數(shù)組自身沒(méi)找到重寫(xiě)方法,繼續(xù)到鏈上找到原生pop方法

四,結(jié)尾

本篇主要介紹了 Vue 數(shù)據(jù)初始化流程中,數(shù)組類(lèi)型的數(shù)據(jù)劫持,核心有以下幾點(diǎn):

出于對(duì)性能的考慮,Vue 沒(méi)有對(duì)數(shù)組類(lèi)型的數(shù)據(jù)使用 Object.defineProperty 進(jìn)行遞歸劫持,而是通過(guò)對(duì)能夠?qū)е略瓟?shù)組變化的 7 個(gè)方法進(jìn)行攔截和重寫(xiě)實(shí)現(xiàn)了數(shù)據(jù)劫持

下一篇,數(shù)據(jù)代理的實(shí)現(xiàn)

到此這篇關(guān)于Vue數(shù)組的劫持逐步分析講解的文章就介紹到這了,更多相關(guān)Vue數(shù)組劫持內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論