标签:根据 特定 enum 判断 val 默认值 不同 red writable
JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性。
主要内容如下:
对象的本质:ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。即对象是一组没有特定顺序的值,对象的每个属性或方法都有一个名字,而这个名字都映射到一个值。故对象的本质是一个散列表:其中是一组名值对,值可以是数据或函数。
对象和类的关系:在JavaScript中,对象和类没有任何关系。这是因为ECMAScript中根本就没有类的概念,它的对象与其他基于类的语言中的对象是不同的。
对象和引用类型的关系:对象和引用类型并不是等价的,因为每个对象都是基于一个引用类型创建的。
由构造函数或对象字面量方法创建的对象中具有属性和方法(只要提到属性和方法,它们一定是属于对象的;只要提到对象,它一定是具有属性和方法的(自定义除外)),其中属性又可分为数据属性和访问器属性,他们的区别如下:
ECMAScript为了描述对象属性(property)的各种特征,定义了特性(attribute)这个概念。也就是说特性不同于属性,特性是为了描述属性的。下面,我将分别讲解:
1.数据属性及其特性
刚刚我们说过,数据属性是用于存储数据数值的,因此数据属性具有一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性,由于ECMAScript规定:在JavaScript中不能直接访问属性的特性(注意:不是不能访问),所以我们把它放在两组方括号中。如下:
这些特性都具有默认值,但是如果这些默认值不是我们想要的,该怎么办呢?当然就是修改啦!我们可以通过Object.defineProperty()方法来修改属性默认的特性。英文difineProperty即为定义属性的意思。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中第三个参数描述符对象是对象字面量的方法创建的,里面的属性和属性值实际上保存的是要修改的特性和特性值。
下面通过几个例子来深入理解。
a
1
2
3
4
5
6
7
8
9
|
var person={}; Object.defineProperty(person, "name" ,{ writable: false , value: "zhuzhenwei" }); console.log(person.name); //zhuzhenwei person.name= "heting" ; console.log(person.name); //zhuzhenwei |
这里我用对象字面量的方法创建了一个对象,但是没有同时创建方法和属性。而是利用了Object.defineProperty()方法来创建了属性和修改了默认值。这里将writable设置为false,于是后面我试图修改person.name时,是无效的。
b
1
2
3
4
5
6
7
|
var person={}; Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" }); console.log(person.name); //zhuzhenwei person.name= "heting" ; console.log(person.name); //zhuzhenwei |
注意看这个例子,这个例子中我删去了writable:false,为什么还是不能修改呢?这是因为之前我在介绍特性时,前三个默认为ture,是在创建对象并创建属性的情况下得到的。对于通过调用Object.defineProperty()方法创建的属性,其前三个特性的默认值均为false,这里需要注意。
c
1
2
3
4
5
6
7
8
|
var person={}; Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , configurable: false }); console.log(person.name); //zhuzhenwei delete person.name; console.log(person.name); //zhuzhenwei |
这里我们将新建的属性name的特性设置为了configurable:false;因此下面删除属性的操作是无效的。根据b,可知configurable,默认就是false,即使去掉也不可修改。
d
1
2
3
4
5
6
7
8
|
var person={}; Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , configurable: true }); console.log(person.name); //zhuzhenwei delete person.name; console.log(person.name); //undefined |
在这里我将默认的configurable的值由默认的false修改为了true,于是变成了可配置的,那么最后就成功删除了。
e
1
2
3
4
5
6
7
8
9
10
11
|
var person={}; Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , configurable: false }); console.log(person.name); //zhuzhenwei Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , configurable: true }); console.log(person.name); //Uncaught TypeError: Cannot redefine property: name(…) |
如果之前已经设置成为了false,那么后面再改成true也是徒劳的,即:一旦把属性设置成为不可配置的,就不能再把它变回可配置了。
f
1
2
3
4
5
6
7
8
9
10
11
|
console.log(person.name); //Uncaught TypeError: Cannot redefine property: name(…) var person={}; Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , }); console.log(person.name); //zhuzhenwei Object.defineProperty(person, "name" ,{ value: "zhuzhenwei" , configurable: true }); console.log(person.name); //Uncaught TypeError: Cannot redefine property: name(…) |
这里可以说明,即使前一步我们不管默认的configurable:false,后面得到的仍是不可配置。于是,可以得出结论,为了可配置,必须在第一次调用Object.defineProperty()函数时就将默认的值修改为true。
2.访问器属性及其特性
之前提到,访问器属性不包含数据值,他们包含一对getter函数和setter函数(这两个函数不是必须的)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性是,会调用setter函数并传入新值,这个函数负责决定如何处理数据。同样,由于不能通过JavaScript来直接访问得到访问器属性的特性,所以下面列出的特性将由[[]]括起来以作区分。
注意:1.相对于数据属性,我们发现访问器属性中没有writable特性和value特性。这是因为访问器属性不包含数据值,那么我们怎么当然就不可修改属性的值(用不到writable特性),更不用考虑value了。
2.访问器属性不能直接定义,必须是用Object.defineProperty()来定义。(通过这个规定我们就能准确地判断出访问器属性和数据属性了)
通过下面这个例子来深入理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
var book={ _year:2004, edition:1 }; Object.defineProperty(book, "year" ,{ get: function (){<br> return this ._year; }, set: function (newValue){ if (newValue>2004){ this ._year=newValue; this .edition+=newValue-2004; } } }); book.year=2005; console.log(book.edition); //2 |
几个需要深入理解的地方:
1 |
3.如何利用Object.defineProperties()方法定义多个特性
显然,一个对象不可能只具有一个属性,因此,定义多个属性的可能性很大,于是JavaScript提供了Object.defineProperties()方法解决这个问题。这个方法接收两个参数,第一个是要定义属性所在的对象,第二个是一个对象字面量方法创建的对象,对象的属性名即为要定义的特姓名,对象的属性值又是一个对象,这个对象里的属性名和属性值分别是特性名和特性值(这里不是很好理解,看例子即可)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var book={}; Object.defineProperties(book,{ _year:{ writable: true , value:2004 }, edition:{ writable: true , value:1 }, year:{ get: function (){ return this ._year; }, set: function (){ if (newValue>2004){ this ._year=newValue; this .edition+=newValue-2004; } } } }); |
4.如何利用Object.getOwnPropertyDescripter()方法读取属性的描述符以读取属性的特性
我们可以使用Object.getOwnPropertyDescripter()方法来取得给定属性的描述符。getOwnPropertyDescripter即为取得自身属性描述符的意思。这个方法接收两个参数:属性所在的对象要要读取其描述符的属性名称。返回一个对象。
对于访问器属性而言,这个对象的属性有configurable、enumerable、get和set;
对于数据属性而言,这个对象的属性有configurable、enumerable、writable和value。
var book={}; Object.defineProperties(book,{ _year:{ value:2004 }, edition:{ value:1 }, year:{ get: function (){ return this ._year; }, set: function (){ if (newValue>2004){ this ._year=newValue; this .edition+=newValue-2004; } } } }); var descriptor=Object.getOwnPropertyDescriptor(book, "_year" ); console.log(descriptor.value); //2004 console.log(descriptor.configurable); //false 因为通过Object.defineProperties()方法创建的属性的特性configurable enumerable都是false console.log( typeof descriptor.get); //undefined 注意:这是数据属性,是不具有get特性的 var descriptor=Object.getOwnPropertyDescriptor(book, "year" ); console.log(descriptor.value); //undefined console.log(descriptor.enumerable); //false console.log( typeof descriptor.get); //function get虽然是属性的一个特性,但是它也是函数。 |
点击这里返回页首
以大多数人的努力程度之低,根本轮不到去拼天赋。
标签:根据 特定 enum 判断 val 默认值 不同 red writable
原文地址:http://www.cnblogs.com/zhangsongren/p/7345117.html