这是 javascript
面向对象版块的第二篇文章,主要讲解的是对象的属性,首先建立一个对象:javascript
var person = { name: "Nicholas", age: 29, job: "Software Engineer", sayName: function () { console.log(this.name); } };
上面的例子建立了一个名为 person 的对象,并为它添加了三个属性( name 、 age 和 job )和一个方法( sayName() )。其中, sayName() 方法用于显示 this.name (将被解析为 person.name )的值。
ECMAScript 中有两种属性:数据属性和访问器属性。java
数据属性是可获取和设置值得属性,数据属性将 value 和 writable 属性包含在其描述符中。数据属性有4个描述其行为的特性:chrome
对于像前面例子中那样直接在对象上定义的属性,它们的 [[Configurable]] 、 [[Enumerable]]和 [[Writable]] 特性都被设置为 true ,而 [[Value]] 特性被设置为指定的值。例如:segmentfault
var person = { name: "Nicholas", };
这里建立了一个名为 name 的属性,为它指定的值是 "Nicholas" 。也就是说, [[Value]] 特性将被设置为 "Nicholas" ,而对这个值的任何修改都将反映在这个位置。
此时有这样一个想法,若是我不容许修改 name 属性的值,怎么办?或者说我要修改属性的默认特性,怎样才能够实现呢?要实现这些功能就要用到 Object.defineProperty()
方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是: configurable 、 enumerable 、 writable 和 value 。设置其中的一或多个值,能够修改对应的特性值。例如:函数
var person = {}; Object.defineProperty(person, 'name', { writable: false, value: 'Nicholas' }) console.log(person.name); // Nicholas person.name = 'Greg'; console.log(person.name); // Nicholas
这个例子建立了一个 name 属性,它的值 "Nicholas" 是只读的。这个属性不可修改,若是尝试修改这个值的话在非严格模式下会被忽略,可是若是在严格模式下,会抛出错误:
Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'
相似的规则也适用于不可配置的属性:测试
var person = {}; Object.defineProperty(person, 'name', { configurable: false, value: 'Nicholas' }) console.log(person.name); // Nicholas delete person.name; console.log(person.name); // Nicholas
把 configurable 设置为 false ,表示不能从对象中删除属性。若是对这个属性调用 delete ,则在非严格模式下什么也不会发生,而在严格模式下会致使错误。并且一旦把属性定义为不可配置,就不能再把它变回可配置了。此时,再调用 Object.defineProperty() 方法修改特性,都会致使错误:this
var person = {}; Object.defineProperty(person, 'name', { configurable: false, value: 'Nicholas' }) console.log(person.name); // Nicholas /* delete person.name; console.log(person.name); // Nicholas */ Object.defineProperty(person, 'name', { writable: true })
也就是说 能够屡次调用 Object.defineProperty() 方法修改同一属性,可是当 configurable 设置为 false 后就不能够了。设计
在《JavaScript 高级程序设计(第三版)》中写到:
“一旦把属性定义为不可配置的,就不能再把它变回可配置了。此时,再调用 Object.defineProperty() 方法修改除 writable 以外的特性,都会致使错误。”
可是我试了一些,即便修改的是 writable 属性,仍是会报错。若是我描述的有错,还望各位大佬指出,以便交流。
在调用 Object.defineProperty() 来定义属性时。若是不指定, configurable 、 enumerable 和writable 特性的默认值都是 false。其实在平常的开发中用到这种高级方法来定义属性的机会仍是比较少,不过理解这部分对理解对象仍是有很大的好处。code
访问器属性不包含数据值,但包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。在读取访问器属性的时候,会调用 getter 方法,这个函数复制返回有效的值;在写入访问器属性的时候,会调用 setter 函数,这个函数复制若是修改数据。访问器属性有以下 4 个特性:对象
var book = { _year: 2004, edition: 1 } Object.defineProperty(book, 'year', { get: function () { return this._year; }, set: function (newVal) { if (newVal > this._year) { this._year = newVal; return this.edition += newVal - 2004; } } }) book.year = 2005; console.log(book.edition); // 2
以上代码代码建立了一个 book 对象,定义了两个属性,_year 和 edition。而访问器属性 year 包含了一个 geter 函数和 setter 函数。getter 函数返回 _year 的值,而 setter 函数返正确的版本。当把 year 属性修改为 2005 时,而 edition 变为 2,这是使用访问器属性的常见方式,即设置一个属性的值会致使其余属性发生变化。
不必定非要同时指定 getter 和 setter,若是只指定 getter ,代表该属性不能写,只能读取,尝试写入属性会被忽略,但在严格模式下会报错。若是只指定 setter ,代表该属性不能读取,若是尝试读取,在严格模式和非严格模式下都会返回 undefined。
在《JavaScript 高级程序设计(第三版)》中写到:
“只指定 setter 函数的属性也不能读,不然在非严格模式下会返回 undefined ,而在严格模式下会抛出错误。”
但在 chrome 中测试了一下,在严格模式下不会抛出错误,返回的也是 undefined 。若是我描述的有错,还望各位大佬指出,以便交流。
本片博客主要介绍了两种属性:数据属性和访问器属性,介绍了这两种属性的定义以及这两种属性的特性,主要使用方法 Object.defineProperty()。其实这篇文章主要是增强对对象的理解。