访问器属性学习

在学访问器属性之前,我们回味一下属性类型。
ECMAScript中有两种属性: 数据属性和访问器属性。
访问器属性
访问器属性不包含属性值;他们包含一对儿getter和setter函数(这两个函数都不是必需的)。
在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;
在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。
访问器属性有以下4个特性:

  1. [[configurable]]: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。
  2. [[enumerable]]:表示能否通过for-in循环遍历。
  3. [[Get]] 在读取属性时调用的函数。默认值为undefined。
  4. [[Set]]在写入属性时调用的函数,默认值为undefined。
    访问器属性不能直接定义,必须使用Object.defineProperty()来定义。请看下面的例子
var book = {
	_year: 2018,
	edtion: 1
}
Object.defineProperty(book,"year",{
	get: function() {
		return this._year;
	},
	set: function(newValue) {
		if(newValue > 2018 ) {
			this._year = newValue;
			this.edition += newValue - 2018;
		}
	}
})
book.year = 2019;
console.log(book.edtion);

以上代码创建了一个book对象,并给它定义两个默认的属性:_year和edition。_year前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。
而访问器属性year则包含一个getter函数setter函数。getter函数返回_year的值,setter函数通过计算来确定正确的版本。
因此把year属性修改为2019会导致_year的值变为2019,而edtion变为2。这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
不一定非要同时指定getter函数和setter函数。
在严格模式下,不指定setter函数,会报如下错误:

Uncaught TypeError: Cannot set property year of # which has only a getter at object.html:25
 
  

不指定setter函数,忽略不计。

访问器属性有什么作用呢?
如果我们有这么一个场景

天下
var obj = {
	name: '张三'
}
var root = document.getElementById('root');
root.innerHTML = obj.name;

这时候我们会发现页面变为‘张三’了。然后我们继续改变obj.name会发生什么情况呢?

obj.name = '李四';

页面会不会发生改变呢,当然不会哦。
除非我们再一次innerHTML,但这样会特别麻烦。
这时就会用到访问器属性。

Object.defineProperty(obj,'name',{
	  get: function() {
	       return this.name;
	   },
	   set: function(newValue) {
	       root.innerHTML = newValue;
	   }
})
obj.name = '小小1';

你会惊奇的发现,不论你在任何时候改变name的值,就会调用setter和getter函数,从而在页面中展示出来。其实在这里也具备了监听的作用。

如果定义多个属性值时,该如何?这时ECMAScript定义了Object.defineProperties(),此方法有两个参数:

  1. 添加和修改其属性的对象
  2. 第二个对象的属性和第一个对象中要添加或修改的属性一一对应。
var book = {}
Object.defineProperties(book,{
	_year: {
		value: 2018
	},
	edition: {
			value: 1
	},
	get: function() {
		return this._year;
	},
	set: function(newValue) {
		if(newValue > 2018 ) {
			this._year = newValue;
			this.edition = newValue - 2018;
		}
	}
})
book.year = 2019;
console.log(book.edition); //2

读取属性的特性
Object.getOwnPropertyDescriptor(),接受两个参数:

  1. 属性所在的对象
  2. 要读取其描述符的属性。返回值是一个对象。
var descriptor = Object.getOwnPropertyDescriptor(book1,'_year');
//为何描述符都是false。
console.log(descriptor.get); //undefined

var descriptor = Object.getOwnPropertyDescriptor(book1,'year');
console.log(typeof descriptor.get); //function
console.log('descriptor.value',descriptor.value); //undefined

//像这种字面量定义的对象 描述符configurable、enumberable、writable都是true。
var book2 = {
    year: 123
}
var descriptor = Object.getOwnPropertyDescriptor(book2,'year');
console.log(descriptor); //{value: 123, writable: true, enumerable: true, configurable: true}

var book3 = {}
Object.defineProperty(book3,'year',{
    value: 123
});
var descriptor = Object.getOwnPropertyDescriptor(book3,'year');
console.log(descriptor.writable); //false
//下面的方式不能重写year,因为没有写的权限,writable 是false
//Uncaught TypeError: Cannot assign to read only property 'year' of object '#'
//book3.year = 234;
 
  

问题:

1.像这种字面量定义的对象 描述符configurable、enumberable、writable都是true。为何Object.defineProperty()定义的属性的描述符是false?

书中这样写到:在调用Object.defineproperty()方法时,如果不指定,configurable、enumberable、writable特性的默认值都是false。

你可能感兴趣的:(原生js)