日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Array变化侦测

發布時間:2024/3/13 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Array变化侦测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.為什么Array的偵測要和Object的偵測區分實現呢?

  • Object是通過getter、setter實現的偵測,但數組中使用push等方法改變數組時,不會觸發getter、setter
  • 在數組中的元素如果是個對象,也要對他們的子屬性進行監聽。
  • 在數組新增一個對象元素時,也要對新增的元素進行監聽。

雖然Array的原型最終還是Object,但是正是由于Array的這些特性,導致了對Object的那一套偵測方式無法直接使用在數組Array中。

2.Array對象中包含了什么?

想要對Array進行監聽,就需要了解Array里面到底有什么。

我們直接打印數組對象的原型

console.log(Array.prototype)

可以看到Array中的一些屬性

可以看到其中包含了push concat等方法。

3.監聽Array對象的大致思路

從上可以得出,可以通過覆蓋Array對象中的原生方法push等,實現一些我們想要的操作。

或者說是直接定義一個攔截器,覆蓋數組原型 Array.prototype

4.攔截器的實現思路

我們需要實現的攔截器,就相當于是把數組的原型對象Array.prototype復制出來, 然后將副本原型進行修改,并讓數組的實例對象的原型指向該副本原型。

整理后發現,Array中有7個可以改變自身的方法:push、pop、shift、unshift、splice、sort、reverse。

所以只需要先重寫這7個方法即可。

我們可以定義如下的攔截方式:

// 得到原生數組原型 const arrayProto = Array.prototype // 相當于復制數組原型對象。 const arrayMethods = Object.create(arrayProto);['push','pop','shift','unshift','splice','sort','reverse'].forEach(function (method) {// 取出原生數組原型中的方法const original = arrayProto[method]// 監聽副本中對應的方法Object.defineProperty(arrayMethods, method, {value: function mutator (...args) {// 攔截!處理完自己的邏輯后,調用原生的方法return original.apply(this, args)},enumerable: false,writable: true,configurable: true}) })

5.攔截器怎么覆蓋Array的原型

我們要的效果:

  • 攔截器不能直接覆蓋Array原型,會污染全局的Array
  • 只針對那些被監聽的數組進行攔截。

大致思路

在Object 的變化偵測 中,我們實現了一個屬性遍歷偵測器Observer。是用來遞歸監聽某個對象中所有屬性的的一個類。我們就可在它遞歸監聽時,判斷該屬性是否是數組,如果是數組,則在該子對象的原型中添加我們的副本原型(也就是我們的監聽器)。

class Observer {constructor(value) {this.value = valueif (Array.isArray(value)) {// 修改數組原型value.__proto__ = arrayMethods} else {this.walk(value);}}walk(obj) {for (let key in obj) {defineReactive(obj, key, obj[key]);console.log('value', obj[key]);console.log('key', key);}} }

**注意:**如果瀏覽器不支持_proto_,就手動遍歷副本原型的屬性

// 判斷瀏覽器是否能使用__proto__ const hasProto = '__proto__' in {} const arrayKeys = Object.getOwnPropertyNames(arrayMethods)class Observer {constructor(value) {this.value = valueif (Array.isArray(value)) {// 根據是否支持proto來決定使用哪種方式覆蓋原型對象。const augment = hasProto ? protoAugment : copyAugment} else {this.walk(value);}}walk(obj) {for (let key in obj) {defineReactive(obj, key, obj[key]);console.log('value', obj[key]);console.log('key', key);}}// 三個參數:target:要修改的對象;src:用于替換的對象,keys:替換對象的字段名function protoAument (target, src, keys) {target.__proto__ = src}function copyAugment(target, src, keys) {for (let i = 0; i < keys.length; i++) {const key = keys[i]// 修改原型對象def(target, key, src[key])}} }// 修改原型對象的工具方法 def(obj, key, val, enumerable) {Object.defineProperty(obj, key, {value: val,enumerable: !!enumerable,writable: true,configurable: true}) }

注意:這里遍歷對象屬性為什么用 Object.getOwnPropertyNames 而不是Object.keys或者for in呢:

因為Array.prototype 中的屬性都是不可枚舉的屬性。使用 Object.keys 和 for in 無法遍歷到它們

6.收集依賴

在Observer類中存儲依賴。

收集依賴時。每個值上新增一個_ob_字段,用于存儲該值的Observer實例。判斷某個元素已經創建Observer監聽實例,則不用再次創建。

7.Observer的簡單邏輯流程

總結

以上是生活随笔為你收集整理的Array变化侦测的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。