国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
當前位置: 首頁 - 科技 - 知識百科 - 正文

詳解Vue 如何監聽Array的變化

來源:懂視網 責編:小采 時間:2020-11-27 21:55:42
文檔

詳解Vue 如何監聽Array的變化

詳解Vue 如何監聽Array的變化:回憶 在上一篇Vue響應式原理-理解Observer、Dep、Watcher簡單講解了Observer、Dep、Watcher三者的關系。 在Observer的偽代碼中我們模擬了如下代碼: class Observer { constructor() { // 響應式綁定數據通過方法 observe(thi
推薦度:
導讀詳解Vue 如何監聽Array的變化:回憶 在上一篇Vue響應式原理-理解Observer、Dep、Watcher簡單講解了Observer、Dep、Watcher三者的關系。 在Observer的偽代碼中我們模擬了如下代碼: class Observer { constructor() { // 響應式綁定數據通過方法 observe(thi

回憶

在上一篇Vue響應式原理-理解Observer、Dep、Watcher簡單講解了Observer、Dep、Watcher三者的關系。

在Observer的偽代碼中我們模擬了如下代碼:

class Observer {
 constructor() {
 // 響應式綁定數據通過方法
 observe(this.data);
 }
}

export function observe (data) {
 const keys = Object.keys(data);
 for (let i = 0; i < keys.length; i++) {
 // 將data中我們定義的每個屬性進行響應式綁定
 defineReactive(obj, keys[i]);
 }
}

export function defineReactive () {
 // ...省略 Object.defineProperty get-set
}

今天我們就進一步了解Observer里還做了什么事。

Array的變化如何監聽?

data 中的數據如果是一個數組怎么辦?我們發現Object.defineProperty對數組進行響應式化是有缺陷的。

雖然我們可以監聽到索引的改變。

function defineReactive (obj, key, val) {
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: () => {
 console.log('我被讀了,我要不要做點什么好?');
 return val;
 },
 set: newVal => {
 if (val === newVal) {
 return;
 }
 val = newVal;
 console.log("數據被改變了,我要渲染到頁面上去!");
 }
 })
}

let data = [1];

// 對數組key進行監聽
defineReactive(data, 0, 1);
console.log(data[0]); // 我被讀了,我要不要做點什么好?
data[0] = 2; // 數據被改變了,我要渲染到頁面上去!

但是defineProperty不能檢測到數組長度的變化,準確的說是通過改變length而增加的長度不能監測到。這種情況無法觸發任何改變。

data.length = 0; // 控制臺沒有任何
輸出

而且監聽數組所有索引的的代價也比較高,綜合一些其他因素,Vue用了另一個方案來處理。

首先我們的observe需要改造一下,單獨加一個數組的處理。

// 將data中我們定義的每個屬性進行響應式綁定
export function observe (data) {
 const keys = Object.keys(data);
 for (let i = 0; i < keys.length; i++) {
 // 如果是數組
 if (Array.isArray(keys[i])) {
 observeArray(keys[i]);
 } else {
 // 如果是對象
 defineReactive(obj, keys[i]);
 }
 }
}

// 數組的處理
export function observeArray () {
 // ...省略
}

那接下來我們就應該考慮下Array變化如何監聽?

Vue 中對這個數組問題的解決方案非常的簡單粗暴,就是對能夠改變數組的方法做了一些手腳。

我們知道,改變數組的方法有很多,舉個例子比如說push方法吧。push存在Array.prototype上的,如果我們能
能攔截到原型上的push方法,是不是就可以做一些事情呢?

Object.defineProperty

對象里目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。存取描述符是由getter-setter函數對描述的屬性,也就是我們用來給對象做響應式綁定的。Object.defineProperty-MDN

雖然我們無法使用Object.defineProperty將數組進行響應式的處理,也就是getter-setter,但是還有其他的功能可以供我們使用。就是數據描述符,數據描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。

value

該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認為 undefined。

writable

當且僅當該屬性的writable為true時,value才能被賦值運算符改變。默認為 false。

因此我們只要把原型上的方法,進行value的重新賦值。

如下代碼,在重新賦值的過程中,我們可以獲取到方法名和所有參數。

function def (obj, key) {
 Object.defineProperty(obj, key, {
 writable: true,
 enumerable: true,
 configurable: true,
 value: function(...args) {
 console.log('key', key);
 console.log('args', args); 
 }
 });
}

// 重寫的數組方法
let obj = {
 push() {}
}

// 數組方法的綁定
def(obj, 'push');

obj.push([1, 2], 7, 'hello!');
// 控制臺
輸出 key push // 控制臺輸出 args [Array(2), 7, "hello!"]

通過如上代碼我們就可以知道,用戶使用了數組上原型的方法以及參數我們都可以攔截到,這個攔截的過程就可以做一些變化的通知。

Vue監聽Array三步曲

接下來,就看看Vue是如何實現的吧~

第一步:先獲取原生 Array 的原型方法,因為攔截后還是需要原生的方法幫我們實現數組的變化。

第二步:對 Array 的原型方法使用 Object.defineProperty 做一些攔截操作。

第三步:把需要被攔截的 Array 類型的數據原型指向改造后原型。

我們將代碼進行下改造,攔截的過程中還是要將開發者的參數傳給原生的方法,保證數組按照開發者的想法被改變,然后我們再去做視圖的更新等操作。

const arrayProto = Array.prototype // 獲取Array的原型

function def (obj, key) {
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 value: function(...args) {
 console.log(key); // 控制臺
輸出 push console.log(args); // 控制臺輸出 [Array(2), 7, "hello!"] // 獲取原生的方法 let original = arrayProto[key]; // 將開發者的參數傳給原生的方法,保證數組按照開發者的想法被改變 const result = original.apply(this, args); // do something 比如通知Vue視圖進行更新 console.log('我的數據被改變了,視圖該更新啦'); this.text = 'hello Vue'; return result; } }); } // 新的原型 let obj = { push() {} } // 重寫賦值 def(obj, 'push'); let arr = [0]; // 原型的指向重寫 arr.__proto__ = obj; // 執行push arr.push([1, 2], 7, 'hello!'); console.log(arr);

被改變后的arr。

Vue源碼解析

array.js

Vue在array.js中重寫了methodsToPatch中七個方法,并將重寫后的原型暴露出去。

// Object.defineProperty的封裝
import { def } from '../util/index'

// 獲得原型上的方法
const arrayProto = Array.prototype

// Vue攔截的方法
const methodsToPatch = [
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
];

// 將上面的方法重寫
methodsToPatch.forEach(function (method) {
 def(arrayMethods, method, function mutator (...args) {
 console.log('method', method); // 獲取方法
 console.log('args', args); // 獲取參數

 // ...功能如上述,監聽到某個方法執行后,做一些對應的操作
 // 1、將開發者的參數傳給原生的方法,保證數組按照開發者的想法被改變
 // 2、視圖更新等
 })
})

export const arrayMethods = Object.create(arrayProto);

observer

在進行數據observer綁定的時候,我們先判斷是否hasProto,如果存在__proto__,就直接將value 的 __proto__指向重寫過后的原型。如果不能使用 __proto__,貌似有些瀏覽器廠商沒有實現。那就直接循環 arrayMethods把它身上的這些方法直接裝到 value 身上好了。畢竟調用某個方法是先去自身查找,當自身找不到這關方法的時候,才去原型上查找。

// 判斷是否有__proto__,因為部分瀏覽器是沒有__proto__
const hasProto = '__proto__' in {}
// 重寫后的原型
import { arrayMethods } from './array'
// 方法名
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);

// 數組的處理
export function observeArray (value) {
 // 如果有__proto__,直接覆蓋 
 if (hasProto) {
 protoAugment(value, arrayMethods);
 } else {
 // 沒有__proto__就把方法加到屬性自身上
 copyAugment(value, arrayMethods, )
 }
}

// 原型的賦值
function protoAugment (target, src) {
 target.__proto__ = src;
}

// 復制
function copyAugment (target, src, keys) {
 for (let i = 0, l = keys.length; i < l; i++) {
 const key = keys[i]
 def(target, key, src[key]);
 }
}

通過上面的代碼我們發現,沒有直接修改 Array.prototype,而是直接把 arrayMenthods 賦值給 value 的 __proto__ 。因為這樣不會污染全局的Array, arrayMenthods 只對 data中的Array 生效。

總結

因為監聽的數組帶來的代價和一些問題,Vue使用了重寫原型的方案代替。攔截了數組的一些方法,在這個過程中再去做通知變化等操作。

本文的一些代碼均是Vue源碼簡化后的,為了方便大家理解。思想理解了,源碼就容易看懂了。

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

詳解Vue 如何監聽Array的變化

詳解Vue 如何監聽Array的變化:回憶 在上一篇Vue響應式原理-理解Observer、Dep、Watcher簡單講解了Observer、Dep、Watcher三者的關系。 在Observer的偽代碼中我們模擬了如下代碼: class Observer { constructor() { // 響應式綁定數據通過方法 observe(thi
推薦度:
標簽: VUE 的變化 數組的
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top 主站蜘蛛池模板: 日韩 欧美 亚洲 | 国产美女视频黄a视频免费全过程 | 日韩色视频 | 国产第八页 | 国产aⅴ精品一区二区三区久久 | 欧美国产日韩一区二区三区 | 亚洲最新视频在线观看 | 国产在线观看精品 | 免费视频二区 | 国产精品一区二区三区高清在线 | 亚洲欧美综合另类 | 国产一区二区三区精品视频 | 免费国产黄网站在线观看视频 | 在线免费观看国产视频 | 欧美精品一区二区三区免费 | 国产一级特黄a大片99 | 亚洲天堂欧美 | 国产欧美一区二区三区精品 | 国产69精品久久久久99不卡 | 美日韩免费视频 | 国产区精品 | 国产在线播放一区二区 | 欧美日韩亚洲一区二区三区在线观看 | 一级毛片免费视频观看 | 欧美在线视频在线观看 | 制服丝袜一区 | 日韩在线视频线视频免费网站 | 91国内精品久久久久免费影院 | 久久精品一区二区三区四区 | 亚洲 欧美 日韩 小说 另类 | 欧美日韩视频在线 | 国产区视频在线观看 | 久久a毛片 | 国产91精品一区二区麻豆亚洲 | 国产亚洲午夜精品a一区二区 | 亚洲国产欧美日韩 | 亚洲欧美日韩在线观看二区 | 国产精品一区二区免费 | 91热这里只有精品 | 国产视频分类 | 欧美日韩亚洲电影天堂 |