深刻理解 Getter和Setter 對對象的屬性監聽

閱讀目錄html

一:理解普通對象在聲明時添加 get、setvue

在作vue的時候,咱們常常會看到 data裏面的屬性 都有 get 和 set方法,以下所示:數組

如上vue中data裏面它有兩個屬性,一個xxx 數組 和 一個 testA對象,可是都有get和set方法。也就是說在vue中data裏面的每一個屬性都有兩個相對應的get和set方法。爲何會有這樣的呢?下面咱們先來看一個普通的對象,以下代碼所示:瀏覽器

const obj = {
  name: 'kongzhi',
  _age: 30,
  get age() {
    return this._age;
  },
  set age(x) {
    this._age = x;
  }
};

console.log(obj); 

打印會以下所示:函數

當咱們繼續打印以下信息:this

console.log(obj._age); // 輸出:30 
console.log(obj.age); // 輸出:30

// 設置值
obj.age = 31;

console.log(obj.age); // 輸出:31

console.log(obj.age()); // Uncaught TypeError: obj.age is not a function

如上代碼演示所示,咱們在對象裏面使用 get 或 set定義的 age, 它只是obj中的一個屬性,它並非方法,所以如上咱們使用獲取屬性的值或設置屬性的值操做是正常的,當咱們使用 obj.age() 把它當作一個方法調用的時候,它會報錯。所以在vue中全部的屬性有get、set這樣的,當咱們自動給某個屬性賦值的時候,它會自動調用 set對應的方法,當咱們獲取某個屬性的時候,它會自動調用get方法。可是咱們不能手動調用 set/get xxx() 中的xxx這樣的方法。spa

二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__prototype

上面只是在聲明obj對象的時候,編寫get和set 對應的屬性。可是若是已經存在的對象的時候,再想繼續添加 get/set呢?那只有使用code

Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 了,以下代碼演示:htm

const obj = {
  name: 'kongzhi',
  _age: 30
};

obj.__defineGetter__('age', function(){
  console.log('監聽到正在獲取屬性age的值');
  return this._age;
});

obj.__defineSetter__('age', function(value) {
  console.log('監聽到正在設置屬性age的值爲:' + value);
  this._age = value;
});

/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出:30
*/
console.log(obj.age);

// 打印:監聽到正在設置屬性age的值爲:31
obj.age = 31;

/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出: 31
*/
console.log(obj.age);

可是呢?Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 這個方法已經不推薦使用了,而且隨着之後瀏覽器的發展,可能會再也不支持該方法,那怎麼辦呢?固然會有新的替代方案的,咱們繼續往下講。

三:Object.defineProperty

該方法它是由兩部分組成,分別是:數據描述符和訪問器描述符,數據描述符的含義是:它是一個包含屬性的值,並說明這個屬性值是可讀或不可讀的對象。訪問器描述符的含義是:包含該屬性的一對 getter/setter方法的對象。

那麼具體項瞭解該方法的使用及詳解,請看我這篇文章(http://www.javashuo.com/article/p-qpgkyhbt-hh.html),下面看使用 Object.defineProperty 來監聽對象屬性值的變化,以下代碼:

const obj = {
  name: 'kongzhi',
  _age: 30
};
Object.defineProperty(obj, 'age', {
  get() {
     console.log('監聽到正在獲取屬性age的值');
     return this._age;
  },
  set(value) {
    console.log('監聽到正在設置屬性age的值爲:' + value);
    this._age = value;
    return this._age;
  }
});

/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出:30
*/
console.log(obj.age);

// 打印:監聽到正在設置屬性age的值爲:31
obj.age = 31;

/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出: 31
*/
console.log(obj.age);

四:Object.defineProperties

Object.defineProperties 是對 Object.defineProperty的擴展的,它能夠一次性添加多個/修改多個對象屬性描述符。
以下代碼演示:

const obj = {
  _name: 'kongzhi',
  _age: 30
};
Object.defineProperties(obj, {
  age: {
    get() {
      console.log('監聽到正在獲取屬性age的值');
      return this._age;
    },
    set(value) {
      console.log('監聽到正在設置屬性age的值爲:' + value);
      this._age = value;
      return this._age;
    }
  },
  name: {
    get() {
      console.log('監聽到正在獲取屬性name的值');
      return this._name;
    },
    set(value) {
      console.log('監聽到正在設置屬性name的值爲:' + value);
      this._name = value;
      return this._name;
    }
  }
});
/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出:30
*/
console.log(obj.age);

// 打印:監聽到正在設置屬性age的值爲:31
obj.age = 31;

/*
 * 打印:監聽到正在獲取屬性age的值
 * 輸出: 31
*/
console.log(obj.age);

console.log('-------下面是對象name屬性的監聽-------');
/*
 * 打印:監聽到正在獲取屬性name的值
 * 輸出:kongzhi
*/
console.log(obj.name);

// 打印:監聽到正在設置屬性name的值爲:longen
obj.name = 'longen';

/*
 * 打印:監聽到正在獲取屬性name的值
 * 輸出: longen
*/
console.log(obj.name);

五:Proxy

那麼具體瞭解Proxy是啥,是幹啥使用的,請看我這篇文章(http://www.javashuo.com/article/p-gfvzjduv-be.html);

那麼它也能夠監聽對象屬性值的變化,以下代碼演示:

const target = {
  name: 'kongzhi'
};

const handler = {
  get: function(target, key) {
    console.log(`${key} 被讀取`);
    return target[key];
  },
  set: function(target, key, value) {
    console.log(`${key} 被設置爲 ${value}`);
    target[key] = value;
  }
};

const testObj = new Proxy(target, handler);

/*
  獲取testObj中name屬性值
  會自動執行 get函數後 打印信息:name 被讀取 及輸出名字 kongzhi
*/
console.log(testObj.name);

/*
 改變target中的name屬性值
 打印信息以下: name 被設置爲 111 
*/
testObj.name = 111;

console.log(target.name); // 輸出 111
相關文章
相關標籤/搜索