《javascript高級程序設計》筆記:對象數據屬性和訪問器屬性

1. 什麼是對象

對象是無序屬性的集合

建立自定義對象最簡單的方式就是以字面量的形式建立對象(或建立一個Object實例),而後再爲它添加屬性和方法,以下所示:javascript

var person = {
  name: "Nicholas",
  age: 29,
  sayHi: function() {
    console.log(this.name);
  }
}

可是咱們須要定義對象中的某個屬性可否修改,可以重寫等屬性,那咱們應該如何定義html

2. 內置屬性—數據屬性

Object.defineProperty()方法介紹(摘自MDN)前端

Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回這個對象

語法:Object.defineProperty(obj, prop, descriptor)
參數:
(1)obj:須要被操做的目標對象
(2)prop:目標對象須要定義或修改的屬性的名稱
(3)descriptor:將被定義或修改的屬性的描述符
返回:被傳遞給函數的對象java

2.1 configurable屬性

是否能夠刪除目標屬性或是否能夠再次修改屬性的特性(writable, configurable, enumerable)。默認爲false框架

設置爲true能夠被刪除或能夠從新設置特性;
設置爲false,不能被能夠被刪除或不能夠從新設置特性,只能將writabletrue置爲falsedom

一旦把屬性定義爲不可配置的,就不能再把它便會可配置的,這一點很重要函數

主要起到數據的保護做用,決定了目標屬性是否可使用delete刪除,是否能夠再次設置特性性能

//-----------------測試目標屬性是否能被刪除------------------------
  var obj = {}
  
  // 第一種狀況:configurable設置爲true,能夠被刪除。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    configurable: true
  });
  // 刪除屬性
  delete obj.newKey;
  console.log( obj.newKey ); //undefined
  
  // 第二種狀況:configurable設置爲false,不能被刪除。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    configurable: false
  });
  // 刪除屬性
  delete obj.newKey;
  console.log( obj.newKey ); //hello
  
//-----------------測試是否能夠再次修改特性------------------------
  var obj = {}
  
  //第一種狀況:configurable設置爲false,不能再次修改特性。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: false,
    enumerable: false,
    configurable: false
  });
  //從新修改特性
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: true,
    enumerable: true,
    configurable: true
  });
  console.log( obj.newKey ); //報錯:Uncaught TypeError: Cannot redefine property: newKey
  
  //第二種狀況:configurable設置爲true,能夠再次修改特性。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: false,
    enumerable: false,
    configurable: true
  });
  //從新修改特性
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: true,
    enumerable: true,
    configurable: true
  });
  console.log( obj.newKey ); //hello

2.2 enumerable 屬性

此屬性是否能夠被枚舉(使用for...in或Object.keys())默認爲false測試

設置爲true能夠被枚舉;設置爲false,不能被枚舉this

var obj = {}
  
  // 第一種狀況:enumerable設置爲false,不能被枚舉。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: false,
    enumerable: false
  });
  // 枚舉對象的屬性
  for( var attr in obj ){
    console.log( attr );  // undefined
  }
  
  // 第二種狀況:enumerable設置爲true,能夠被枚舉。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: false,
    enumerable: true
  });
  // 枚舉對象的屬性
  for( var attr in obj ){
  console.log( attr );  //newKey
  }

2.3 value 屬性

屬性對應的值,能夠是任意類型的值,默認爲undefined;

var obj = {}
  // 第一種狀況:不設置value屬性
  Object.defineProperty(obj, "key", {});
  console.log( obj.key );  //undefined
  
  // 第二種狀況:設置value屬性
  Object.defineProperty(obj, "key", {
    value: "hello"
  });
  console.log( obj.key );  //hello
  
  // 同字面定義的數據值對應

2.4 writable 屬性

屬性的值是否能夠被重寫。默認爲false

設置爲true能夠被重寫;設置爲false,不能被重寫

var obj = {}
  
  // 第一種狀況:writable設置爲false,不能重寫。
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: false
  });
  // 更改newKey的值
  obj.newKey = "change value";
  console.log( obj.newKey );  //hello
  
  // 第二種狀況:writable設置爲true,能夠重寫
  Object.defineProperty(obj, "newKey", {
    value: "hello",
    writable: true
  });
  // 更改newKey的值
  obj.newKey = "change value";
  console.log( obj.newKey );  //change value

2.5 默認值理解(重點)

在調用 Object.defineProperty 方法給對象添加屬性時,若是不指定,configurable、enumerable、writable這些值都爲默認的false

==> 使用 Object.getOwnPropertyDescriptor() 方法來查看對象的內置屬性

var obj = {};
  
  // 第一種狀況:使用 Object.defineProperty() 定義屬性
  Object.defineProperty(obj, 'key', {
    value: "hello"
  });
  Object.getOwnPropertyDescriptor(obj, 'key');
  // {value: "hello", writable: false, enumerable: false, configurable: false}
  
  // 第二種狀況:字面量方式
  obj.key = "hello";
  Object.getOwnPropertyDescriptor(obj, 'key');
  // {value: "hello", writable: true, enumerable: true, configurable: true}

2.6 數據屬性總結

  1. configurable: 目標屬性是否能夠被刪除或是否能夠再次修改特性 true | false
  2. enumerable: 目標屬性是否能夠被枚舉。true | false
  3. value: 設置屬性的值 undefined
  4. writable: 值是否能夠重寫。true | false

3. 內置對象—訪問器屬性

Object.getOwnPropertyDescriptor()方法介紹(摘自MDN)

Object.getOwnPropertyDescriptor() 方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不須要從原型鏈上進行查找的屬性)

語法:Object.getOwnPropertyDescriptor(obj, prop)
參數:
(1)obj:須要被操做的目標對象
(2)prop:目標對象內屬性名稱(String類型)
返回:若是指定的屬性存在於對象上,則返回其屬性描述符對象(property descriptor),不然返回 undefined

3.1 configurable 屬性

參照數據屬性中的configurable屬性

3.2 enumerable 屬性

參照數據屬性中的enumerable屬性

3.3 get 方法

在讀取屬性是調用的函數,默認值爲undefined

var obj = {}, value = "hello";
  
  Object.defineProperty(obj, 'key', {
    get: function() {
      console.log("獲取obj.key的值上下文");
      return value;
    }
  });
  
  console.log(obj.key); // "獲取obj.key的值上下文" hello
  obj.key = "new value";
  console.log(obj.key); // "獲取obj.key的值上下文" hello

3.4 set 方法

在寫入屬性時調用的函數,默認值爲undefined

// 通常不會單獨爲屬性設置set而不設置get
  var obj = {}, value = "hello";
  Object.defineProperty(obj, 'key', {
    set: function(val) {
      console.log("設置obj.key的值上下文");
    }
  });
  
  obj.key = "new value"; // "獲取obj.key的值上下文"
  console.log(obj.key); // undefined
不必定非要同時指定getter和setter。只指定getter意味着屬性是不能寫,嘗試寫入屬性會被忽略。在嚴格模式下,嘗試寫入只指定getter函數的屬性會拋出錯誤。相似的,只指定setter函數的屬性也不能讀,不然在非嚴格模式下會返回undefined,而在嚴格模式下會拋出錯誤。
var book = {
    _year: 2004,
    edition: 1 };
  Object.defineProperty(book, "year", {
      get: function() {
        return this._year;
      },
      set: function(newValue) {
        if (newValue > 2004) {
          this._year = newValue;
          this.edition += newValue - 2004;
        }
      }
  });
  book.year = 2005; alert(book.edition); //2

使用訪問器屬性的常見方式,即設置一個屬性的值會致使其餘屬性發生變化

3.5 數據和視圖聯動(重點)

給對象o定義新的屬性b,而且定義屬性b的get和set方法,當o.b的時候會調用b屬性的get方法,給b屬性賦值的時候,會調用set方法,這就是修改數據的時候,視圖會自動更新的關鍵前端獲取數據後,須要根據數據操做dom,視圖變化後,須要修改很多代碼,有沒有方法將數據和dom操做隔離,看一個例子

<!-- 顯示用戶信息的html模版 -->
  <div>
  <p>你好,<span id='nickName'></span></p>
  <div id="introduce"></div>
  </div>
// 視圖控制器
  var userInfo = {};
  Object.defineProperty(userInfo, "nickName", {
    get: function(){
      return document.getElementById('nickName').innerHTML;
    },
    set: function(nick){
      document.getElementById('nickName').innerHTML = nick;
    }
  });
  Object.defineProperty(userInfo, "introduce", {
    get: function(){
      return document.getElementById('introduce').innerHTML;
    },
    set: function(introduce){
      document.getElementById('introduce').innerHTML = introduce;
    }
  });
  
  // 數據
  // todo 獲取用戶信息的代碼
  // ....
  userInfo.nickName = "xxx";
  userInfo.introduce = "我是xxx,我來自雲南,..."

訪問器屬性是實現MVVM框架的核心原理哦~

4. 定義多個屬性

Object.defineProperties() 方法直接在一個對象上定義新的屬性或修改現有屬性,並返回該對象

語法:Object.defineProperties(obj, props)
參數:
(1)obj:在其上定義或修改屬性的對象
(2)props:要定義其可枚舉屬性或修改的屬性描述符的對象。對象中存在的屬性描述符主要有數據描述符和訪問器描述符兩種
返回:傳遞給函數的對象

var obj = {};
  Object.defineProperties(obj, {
    'property1': {
      value: true,
      writable: true
    },
    'property2': {
      value: 'Hello',
      writable: false
    }
    // etc. etc.
  });

參考:
Javascript中的Object.defineProperty
MDN Object.defineProperty
MDN Object.getOwnPropertyDescriptor

相關文章
相關標籤/搜索