Object.defineProperty()

Object.defineProperty()

MDN上的解释是Object.defineProperty()会直接在对象上定义一个新的属性,或者修改一个对象的现有属性,并返回这个对象。


###在ECMAScript中属性有两种

数据属性


数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有四个描述其行为的特性

  • [[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,默认为true
  • [[Enumerable]] : 表示能否通过for-in循环返回属性,默认为true
  • [[Writable]] : 表示能否修改属性的值,默认为true
  • [[Value]] : 属性的数据值,默认值为undefined

访问器属性


访问器属性不包含数据值;它包含一对getter和setter函数(这两个函数都不是必须的,也不需要成对出现),在读取访问其属性时,会调用getter函数,这个函数负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。在这里让我想起了vue中也有一个getter和setter,vue的双向绑定就是通过object.defineProperty()完成的。

  • [[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,默认为true
  • [[Enumerable]] : 表示能否通过for-in循环返回属性,默认为true
  • [[Get]] : 在读取属性时调用的函数,默认为undefined
  • [[Set]] : 在读取属性时调用的函数,默认值为undefined

通常我们创建一个对象,可以用构造函数或者字面量的形式,当然除了这些还有很多方式如原型模式、工厂模式、构造函数和原型的组合方式等等

1
2
3
var obj = new Object;  //obj = {}
obj.name = "张三"; //添加描述
obj.say = function(){}; //添加行为

###Object.defineProperty(obj, prop, descriptor)


参数:

  • obj: 目标对象
  • prop: 需要定义或修改的属性名字
  • descriptor: 目标属性所拥有的特性

返回值:

  • 传入函数的对象,即第一个参数obj

####针对Configurable、Writable特性

1
2
3
4
5
6
7
8
9
10
11
12
var person = {}
Object.defineProperty(person, 'name', {
configurable: false,
writalbe: false,
value: 'xiaoming'
})

console.log(person.name) //xiaoming
person.name = "xiaohong"
console.log(person.name) //xiaoming
delete person.name
console.log(person.name) //xiaoming

这个例子创建了一个名为name的属性,但是这个属性是只读的,不可修改。而在configurablefalse时,该属性不能被删除。同时在严格模式下,如果尝试给它赋予新值将会抛出错误。


####针对Get、Set特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var book = {
_year: 2017,
edition: 1
}

Object.defineProperty(book, 'year', {
get: function () {
return this._year
},
set: function (newValue) {
if (newValue > 2017) {
this._year = newValue
this.edition += newValue - 2017
}
}
})

book.year = 2018
console.log(book.edition) //2

以上代码创建了一个book对象,并给它定义了两个属性, _ year 和 edition。_year前面的下划线表示该属性只能被对象方法访问的属性,是一种常用的记号。这是使用访问器的常用方式,即设置一个属性的值会导致其他属性发生变化。


###此外
记我一次见过的面试题
==利用给定接口获得闭包的对象==

1
2
3
4
5
6
7
8
9
10
11
var o = (function() {
var person = {
name: 'xiaoming',
age: '18'
}
return {
run: function(k) {
return person(k)
}
}
}());

Q: 在不改变上面代码的情况下,怎么得到原有的person对象?
A:

1
2
3
4
5
6
7
8
Object.defineProperty(object.prototype, 'self', {
get: function() {
return this
},
configureable: ture
})

o.run('self') // person