国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vue源碼學習之Object.defineProperty 對數組監聽

2019-11-19 13:45:20
字體:
來源:轉載
供稿:網友

上一篇中,我們介紹了一下defineProperty 對對象的監聽,這一篇我們看下defineProperty 對數組的監聽

數組的變化

先讓我們了解下Object.defineProperty()對數組變化的跟蹤情況:

var a={};bValue=1;Object.defineProperty(a,"b",{  set:function(value){    bValue=value;    console.log("setted");  },  get:function(){    return bValue;  }});a.b;//1a.b=[];//setteda.b=[1,2,3];//setteda.b[1]=10;//無輸出a.b.push(4);//無輸出a.b.length=5;//無輸出a.b;//[1,10,3,4,undefined];

可以看到,當a.b被設置為數組后,只要不是重新賦值一個新的數組對象,任何對數組內部的修改都不會觸發setter方法的執行。這一點非常重要,因為基于Object.defineProperty()方法的現代前端框架實現的數據雙向綁定也同樣無法識別這樣的數組變化。因此第一點,如果想要觸發數據雙向綁定,我們不要使用arr[1]=newValue;這樣的語句來實現;第二點,框架也提供了許多方法來實現數組的雙向綁定。

對于框架如何實現數組變化的監測,大多數情況下,框架會重寫Array.prototype.push方法,并生成一個新的數組賦值給數據,這樣數據雙向綁定就會觸發。

實現簡單的對數組的變化的監聽

var arrayPush = {};(function(method){  var original = Array.prototype[method];  arrayPush[method] = function() {    // this 指向可通過下面的測試看出    console.log(this);    return original.apply(this, arguments)  };})('push');var testPush = [];testPush.__proto__ = arrayPush;// 通過輸出,可以看出上面所述 this 指向的是 testPush// []testPush.push(1);// [1]testPush.push(2);

在官方文檔,所需監視的只有 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 7 種方法。我們可以遍歷一下:

var arrayProto = Array.prototypevar arrayMethods = Object.create(arrayProto);[ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(item){  Object.defineProperty(arrayMethods,item,{    value:function mutator(){      //緩存原生方法,之后調用      console.log('array被訪問');      var original = arrayProto[item]        var args = Array.from(arguments)    original.apply(this,args)      // console.log(this);    },  })})

完整代碼

function Observer(data){  this.data = data;  this.walk(data);}var p = Observer.prototype;var arrayProto = Array.prototypevar arrayMethods = Object.create(arrayProto);[ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(item){  Object.defineProperty(arrayMethods,item,{    value:function mutator(){      //緩存原生方法,之后調用      console.log('array被訪問');      var original = arrayProto[item]        var args = Array.from(arguments)    original.apply(this,args)      // console.log(this);    },  })})p.walk = function(obj){  var value;  for(var key in obj){    // 通過 hasOwnProperty 過濾掉一個對象本身擁有的屬性     if(obj.hasOwnProperty(key)){      value = obj[key];      // 遞歸調用 循環所有對象出來      if(typeof value === 'object'){        if (Array.isArray(value)) {          var augment = value.__proto__ ? protoAugment : copyAugment           augment(value, arrayMethods, key)          observeArray(value)        }        new Observer(value);      }      this.convert(key, value);    }  }};p.convert = function(key, value){  Object.defineProperty(this.data, key, {    enumerable: true,    configurable: true,    get: function(){      console.log(key + '被訪問');      return value;    },    set: function(newVal){      console.log(key + '被修改,新' + key + '=' + newVal);      if(newVal === value) return ;      value = newVal;    }  })}; var data = {  user: {    // name: 'zhangsan',    age: function(){console.log(1)}  },  apg: [{'a': 'b'},2,3]}function observeArray (items) {  for (var i = 0, l = items.length; i < l; i++) {    observe(items[i])  }}//數據重復Observerfunction observe(value){  if(typeof(value) != 'object' ) return;  var ob = new Observer(value)   return ob;}//輔助方法function def (obj, key, val) { Object.defineProperty(obj, key, {  value: val,  enumerable: true,  writable: true,  configurable: true })}// 兼容不支持__proto__的方法//重新賦值Array的__proto__屬性function protoAugment (target,src) { target.__proto__ = src}//不支持__proto__的直接修改相關屬性方法function copyAugment (target, src, keys) { for (var i = 0, l = keys.length; i < l; i++) {  var key = keys[i]  def(target, key, src[key]) }}var app = new Observer(data);// data.apg[2] = 111;data.apg.push(5);// data.apg[0].a = 10;// console.log(data.apg);

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 疏附县| 福建省| 沁阳市| 库尔勒市| 纳雍县| 延庆县| 澳门| 耿马| 永康市| 新营市| 沅陵县| 大名县| 张家界市| 泸州市| 海晏县| 延川县| 广南县| 肇庆市| 宁津县| 庆云县| 班戈县| 贡山| 河东区| 新邵县| 葵青区| 永春县| 达州市| 宜兴市| 太康县| 曲松县| 营山县| 东乌珠穆沁旗| 保山市| 双流县| 宝清县| 湾仔区| 新绛县| 万年县| 天柱县| 乌鲁木齐县| 武夷山市|