国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

JavaScript defineProperty如何實(shí)現屬性劫持

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:顏醬 欄目: JavaScript 歡迎投稿:712375056

目錄

前言

defineProperty是vue實(shí)現數據劫持的核心,本文一點(diǎn)點(diǎn)的說(shuō)明defineProperty怎么實(shí)現屬性劫持的。

其實(shí)我們一般的操作對象屬性的方式,增加或者修改屬性,均可以使用Object.defineProperty。

let obj = {};
// 尋常操作:增加/修改 新屬性
obj.a = 1;
// 等同于:
Object.defineProperty(o, "a", {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});

當然尋常的例子,我們是不會(huì )這么玩的,太啰嗦了。

但defineProperty可以更精確地添加或修改對象的屬性。

描述符

先說(shuō)個(gè)專(zhuān)有名詞:描述符。

其實(shí)就是defineProperty的第三個(gè)參數,是個(gè)對象。這個(gè)對象的有以下屬性:

  • configurable 屬性:能不能修改描述符,就是能不能再次修改描述符的其他屬性
  • enumerable 屬性:能不能枚舉該屬性,就是 a 屬性能不能被 for 到
  • writable 屬性:能不能修改屬性值,就是能不能這樣修改obj.a = 1
  • value 屬性:該屬性的值
  • get 屬性:是個(gè)函數,當訪(fǎng)問(wèn)該屬性的時(shí)候,函數自動(dòng)調用,函數返回值就是該屬性的值
  • set 屬性:是個(gè)函數,當修改該屬性的時(shí)候,函數自動(dòng)調用,函數有且只有一個(gè)參數,賦值的新值

注意?。?!

  • 描述符里的value屬性 writable屬性 與 get屬性 set屬性是互斥的關(guān)系,只能存在一個(gè)
  • 另外的屬性默認值都是false,不想false的話(huà),記得配置哈,不細說(shuō)(主要我也不怎么用)。

細說(shuō)get 和 set

  • get 屬性:是個(gè)函數,當訪(fǎng)問(wèn)該屬性的時(shí)候,函數自動(dòng)調用,函數返回值就是該屬性的值
  • set 屬性:是個(gè)函數,當修改該屬性的時(shí)候,函數自動(dòng)調用,函數有且只有一個(gè)參數,賦值的新值

默念三遍,背誦。

寫(xiě)個(gè)get 和 set 的例子輔助理解。

這個(gè)例子必須掌握,弄懂之后基本就掌握了數據劫持的精髓了

let obj = {};

let value = 1;
Object.defineProperty(obj, "b", {
  get() {
    console.log("讀取b屬性", value);
    return value;
  },
  set(newValue) {
    console.log("設置b屬性", newValue);
    value = newValue;
  }
});
// 觸發(fā)get函數,get的返回值就是屬性值
// 1
console.log(obj.b);
// 觸發(fā)set函數,value的值變成了2,注意?。?!,此時(shí)內存里,屬性值并沒(méi)有改變
obj.b = 2;
// 但是,想要讀取屬性值的時(shí)候,就必然會(huì )觸發(fā)get函數,屬性值也自然就改變了,這個(gè)思想真的很贊
console.log(obj.b);

這里有個(gè)坑:get里是不能有讀取的操作,不然一直死循環(huán),所以使用到get set的地方,總需要借助一個(gè)變量

所以,這里,變量value的值就是屬性的值,如果想要修改屬性,修改 value 的值即可。

這個(gè)例子弄懂了,get,set 的精髓,我覺(jué)得也就差不多了。

劫持對象的某個(gè)屬性

有了剛剛例子的基礎,試著(zhù)寫(xiě)寫(xiě)劫持對象的任意一個(gè)屬性。

function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    get() {
      console.log("讀取屬性", value);
      return value;
    },
    set(newValue) {
      console.log("設置屬性", newValue);
      value = newValue;
    }
  });
}
let obj = { a: 1 };
observeKey(obj, "a");
// 讀取a,觸發(fā)get函數
console.log(obj.a);
// 設置a,觸發(fā)set函數
obj.a = 1;

劫持對象的所有屬性

再試試劫持對象的所有屬性

其實(shí)就是遍歷:

function observeObj(obj) {
  for (let key in obj) {
    // 直接使用 obj.hasOwnProperty會(huì )提示不規范
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      observeKey(obj, key);
    }
  }
  return obj;
}
function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    get() {
      console.log("讀取屬性", value);
      return value;
    },
    set(newValue) {
      console.log("設置屬性", newValue);
      value = newValue;
    }
  });
}

let obj = { a: 1, b: 2 };
observeObj(obj);
console.log(obj);
// 讀取a,觸發(fā)get函數
console.log(obj.a);
// 設置a,觸發(fā)set函數
obj.a = 1;

劫持對象的所有屬性 - 包括對象類(lèi)型的屬性值

上面的有個(gè)缺陷,就是當屬性值也是對象的時(shí)候,不能劫持屬性值,如{a:1,c:{b:1}}

簡(jiǎn)單,遞歸,補上就行。

function observeObj(obj) {
  // 加上參數限制,必須是對象才有劫持,也是遞歸的終止條件
  if (typeof obj !== "object" || obj == null) {
    return;
  }
  for (let key in obj) {
    // 直接使用 obj.hasOwnProperty會(huì )提示不規范
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      observeKey(obj, key);
      // 這里劫持該屬性的屬性值,如果不是對象直接返回,不影響
      observeObj(obj[key]);
    }
  }
  return obj;
}
function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    get() {
      console.log("讀取屬性", value);
      return value;
    },
    set(newValue) {
      console.log("設置屬性", newValue);
      value = newValue;
    }
  });
}

let obj = { a: 1, b: 2, c: { name: "c" } };
observeObj(obj);
console.log(obj);
// 讀取a,觸發(fā)get函數
console.log(obj.a);
// 設置a,觸發(fā)set函數
obj.a = 1;
// 觸發(fā)set函數
obj.c.name = "d";

注意,observeObj這個(gè)函數,不能劫持對象的新增屬性,只能劫持對象已有的屬性。

defineProperty的缺陷

  • 不能監測對象增加屬性
  • 不能監測對象刪除屬性
  • 不能劫持數組的修改

當然數組的修改可以通過(guò)別的方式監測到的,。

以上缺陷,也是vue里面為啥有$set/$delete以及對數組只能使用特定方法才能檢測到。

let obj = { a: 1, b: [1, 2] };
observeObj(obj);
// 新增屬性
obj.c = 3;
// 不會(huì )觸發(fā)get函數
console.log(obj.c);
// 不會(huì )觸發(fā)set函數
obj.b.push(3);

defineProperty還可以?huà)燧d屬性

其實(shí)就是訪(fǎng)問(wèn)options.data.name 可以簡(jiǎn)寫(xiě)成 options.name,專(zhuān)業(yè)話(huà)術(shù),將data上的屬性?huà)燧d到options上

相當于,用defineProperty,在options上增加新屬性:

// 先掛載單個(gè)屬性
// options.data相當于source options相當于target
function proxyKey(target, source, key) {
  Object.defineProperty(target, key, {
    // 這里的source[key]相當于變量value,所以說(shuō)最簡(jiǎn)單的那個(gè)例子是核心
    get() {
      return source[key];
    },
    set(newValue) {
      if (newValue === source[key]) {
        return;
      }
      source[key] = newValue;
    }
  });
}
// 遍歷屬性,掛載下
function proxyObj(target, source) {
  for (let key in source) {
    // 直接使用 obj.hasOwnProperty會(huì )提示不規范
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      proxyKey(target, source, key);
    }
  }
}
let options = {
  data: { name: 1 }
};
proxyObj(options, options.data);
// 1
console.log(options.name);

話(huà)說(shuō),vue的屬性劫持和掛載屬性,核心原理差不多就是上面這些。

defineProperty還能寫(xiě)日志

比如 obj 有個(gè)屬性,此屬性值經(jīng)常變化,想要記錄其所有變化的值,以此可以形成日志。

let obj = { a: 1 };

let log = [obj.a];

let value = obj.a;
Object.defineProperty(obj, "a", {
  get() {
    return value;
  },
  set(newValue) {
    if (newValue === value) {
      return;
    }
    value = newValue;
    log.push(newValue);
  }
});

obj.a = 2;
obj.a = 3;
obj.a = 4;
// [1,2,3,4]
console.log(log);

通用的可以抽離出一個(gè)類(lèi),專(zhuān)門(mén)記錄某個(gè)值的變化

class Archiver {
  constructor() {
    let value = null;
    this.archive = [];
    Object.defineProperty(this, "a", {
      get() {
        return value;
      },
      set(newValue) {
        if (newValue === value) {
          return;
        }
        value = newValue;
        this.archive.push(newValue);
      }
    });
  }
}
let archiver = new Archiver();
archiver.a = 1;
archiver.a = 2;
// [1,2]
console.log(archiver.archive);

引用

總結

到此這篇關(guān)于JavaScript defineProperty如何實(shí)現屬性劫持的文章就介紹到這了,更多相關(guān)defineProperty屬性劫持內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

两个奶头被吃高潮视频| 青青河边草免费的观看| 妺妺坐在我腿上勃起弄了视频| 久久九九日本韩国精品| 亚洲情综合五月天| 亚洲AV色无码乱码在线观看|