JavaScript對象屬性-數據屬性和訪問器屬性

屬性類型

數據屬性

[[Configurable]]:表示能否通過delete刪除屬性,能否修改屬性特性,能否把屬性修改爲訪問器屬性。
[[Enumerable]]:表示能否通過for-in循環返回屬性。
[[Writable]]:表示是否能修改屬性值。
[[Value]]:包含這個屬性的數據值,默認值爲undefined

當直接在對象上定義屬性時(即var Person={name:'Joker'}),前三個屬性都默認爲true

修改屬性默認的特性的方法——Object.defineProperty()

在調用Object.defineProperty()方法創建一個新的屬性時,如果不指定considerableinnumerablewriteable特性的默認值都是false。當只是修改一個已定義的屬性的特性時,無此限制。

一旦把屬性的considerable定義爲false,即,把屬性定義爲不可配置的,則不能變回可配置了,且修改除writable之外的屬性都會發生錯誤。

var Person = {}
Object.defineProperty(person, 'name', {
  value: 'Joker',	//如果不指定那三個屬性,則都默認爲false
})

// 'use strict' //聲明爲嚴格模式
person.name = 'rewrite' // 在嚴格模式下會報錯,在非嚴格模式下下會忽略該語句

在非嚴格模式下,修改已設置writablefalse的屬性的值,賦值操作將會被忽略;在嚴格模式下,將拋出錯誤。

var person = {
  name: 'defaultname',
}

Object.defineProperty(person, 'name', {	
  writable: false,		//設置name屬性爲不可修改
})

person.name = 'rewrite1'			//重寫失敗,在非嚴格模式下會忽略,嚴格模式下會報錯
console.log(person1.name)		//defaultname

Object.defineProperty(person1, 'name', {
  writable: true,		//重新設置name屬性爲可修改
})

person1.name = 'rewrite2'		//可以修改
console.log(person1.name)		//rewrite2

訪問器屬性

包含gettersetter函數。在讀取訪問器屬性時,會調用get函數負責返回有效的值;在寫入訪問期屬性時會調用set函數並傳入新值,負責如何處理數據。
通過Object.defineProperty()來定義。
使用訪問器屬性的常見方式是,設置一個屬性的值會導致其他屬性發生變化,如下:

var book = {
  year: 2000,
  edition: 1,
}

Object.defineProperty(book, 'year', {
  get: function () {
    return this.year
  },
  set: function (newValue) {
    if (newValue >= 2000) {		// 改變year的同時改變edition
      this.edition = Math.floor((newValue - 2000) / 3) + 1
    }
  },
})

book.year = 2001
console.log(book.edition)		// 1

book.year = 2010
console.log(book.edition)		// 4

只指定getter意味着屬性不可寫,非嚴格模式下,嘗試寫入會被忽略,嚴格模式下,會拋出錯誤。
只指定setter意味着屬性不可讀,非嚴格模式下,會返回undefined,嚴格模式下,會拋出錯誤。

讀取屬性的特性

var person = {}

Object.defineProperty(person, 'name', {
  enumerable: false,
  value: 'name',
})

// 讀取屬性的特性
var descriptor = Object.getOwnPropertyDescriptor(person, 'name')
console.log(descriptor.enumerable) 		//false
console.log(descriptor.value) 		//name

判斷是否包含某屬性和in操作符

.hasOwnProperty()用於檢測一個屬性存在於實例中,還是在原型中。當存在於實例中時返回true。

function Person() {}
Person.prototype.name = 'defaultName'		//添加一個原型屬性
person.job = 'instanceJob'		//添加一個實例屬性
console.log(person.hasOwnProperty('job')) 	// true
console.log(person.hasOwnProperty('name')) 	// false

in操作符:檢測屬性是否在實例或原型中,只要包括,就爲true。

console.log('name' in person1) 		// true
console.log('job' in person1)		 // true

結合in操作符和hasOwnProperty()可以判斷一個屬性是實例屬性還是原型屬性

function hasPrototypeProperty(obj, name) {
  return !obj.hasOwnProperty(name) && name in obj
}

console.log(hasPrototypeProperty(person, 'name')) // true
console.log(hasPrototypeProperty(person, 'job')) // false

獲取屬性

for-in——所有枚舉屬性

// 現在person實例有實例屬性name、sayName,原型屬性job、sayJob
for (let prop in person1) {
  console.log(prop) //所有實例屬性、原型屬性
}

被設置爲不可枚舉,即emunerable爲false的屬性在for…in中不會被訪問到。

function Person() {}
//定義原型屬性,其中一個在後面被設置爲不可枚舉
Person.prototype.protoNameEmun = 'protoNameEmun'
Person.prototype.protoNameUnemun = 'protoNameUnemun'
Person.prototype.protoSayName = function () {}

var person = new Person()

//定義實例屬性,其中一個在後面被設置爲不可枚舉
person.instanceNameEmun = 'instanceNameEmun'
person.instanceNameUnemun = 'instanceNameUnemun'
person.instanceSayName = function () {}

// 定義爲不可枚舉
Object.defineProperties(person, {
  protoNameUnemun: {
    enumerable: false,
  },
  instanceNameUnemun: {
    enumerable: false,
  },
})

// 輸出實例屬性、原型屬性中所有可枚舉的,不可枚舉的不輸出
// 輸出:instanceNameEmun、instanceSayName、protoNameEmun、protoSayName
for (let prop in person) {
  console.log(prop)
}

Object.keys()——可枚舉實例屬性的字符串數組

Object.keys()方法這個方法接收一個對象作爲參數,返回一個包含所有可枚舉的實例屬性字符串數組
同樣,對於上述的例子:

var key1 = Object.keys(Person.prototype)
var key2 = Object.keys(person)

console.log(key1)	//[ 'protoNameEmun', 'protoNameUnemun', 'protoSayName' ]
console.log(key2)	//[ 'instanceNameEmun', 'instanceSayName' ]

Object.getOwnPropertyNames()——所有實例屬性的字符串數組

返回包含所有實例屬性(不論是否可以枚舉)的字符串數組。

var names1 = Object.getOwnPropertyNames(Person.prototype)
var names2 = Object.getOwnPropertyNames(person)

console.log(names1)		
// [ 'constructor', 'protoNameEmun', 'protoNameUnemun', 'protoSayName' ]
console.log(names2)		
// [  'instanceNameEmun',  'instanceNameUnemun',  'instanceSayName',  'protoNameUnemun' ]

注意在name1中包含了不可枚舉屬性constructor,正說明了“不論是否可以枚舉”這一點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章