深切明白JavaScript中的属性和特性
JavaScript中属性和特性是完整差别的两个观点,这里我将依据本身所学,来深切明白JavaScript中的属性和特性。
主要内容以下:
- 明白JavaScript中对象的实质、对象与类的关联、对象与援用范例的关联
- 对象属性怎样举行分类
- 属性中特性的明白
第一部份:明白JavaScript中对象的实质、对象与类的关联、对象与援用范例的关联
对象的实质:ECMA-262把对象定义为:无序属性的鸠合,其属性可以包括基础值、对象或许函数。即对象是一组没有特定递次的值,对象的每一个属性或要领都有一个名字,而这个名字都映射到一个值。故对象的实质是一个散列表:个中是一组名值对,值可以是数据或函数。
对象和类的关联:在JavaScript中,对象和类没有任何关联。这是因为ECMAScript中根本就没有类的观点,它的对象与其他基于类的语言中的对象是差别的。
对象和援用范例的关联:对象和援用范例并非等价的,因为每一个对象都是基于一个援用范例建立的。
第二部份:对象属性怎样举行分类
由组织函数或对象字面量要领建立的对象中具有属性和要领(只需提到属性和要领,它们一定是属于对象的;只需提到对象,它一定是具有属性和要领的(自定义除外)),个中属性又可分为数据属性和接见器属性,他们的辨别以下:
- 数据属性平经常使用于存储数据数值,接见器属性不包括数据值
- 接见器属性多用于
get/set
操纵
第三部份:属性中特性的明白
ECMAScript为了形貌对象属性(property)的种种特性,定义了特性(attribute)这个观点。也就是说特性差别于属性,特性是为了形貌属性的。下面,我将离别解说:
- 数据属性及其特性
- 接见器属性及其特性
- 怎样应用
Object.defineProperties()
要领定义多个特性 - 怎样应用
Object.getOwnPropertyDescripter()
要领读取属性的形貌符以读取属性的特性
1.数据属性及其特性
方才我们说过,数据属性是用于存储数据数值的,因而数据属性具有一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个形貌其行动的特性,因为ECMAScript划定:在JavaScript中不能直接接见属性的特性(注重:不是不能接见),所以我们把它放在两组方括号中。以下:
-
[[Configurable]]
:默许值为true
,a、示意可否经由过程delete
删除属性从而从新定义属性 b、可否修正属性的特性
c、可以把属性由数据属性修正为接见器属性 -
[[Enumerable]]
:默许值为true
,示意可否经由过程for-in
轮回返回该属性(所以:假如为false
,那末for-in
轮回没法罗列它地点的属性) -
[[Writable]]
:默许值为true
,示意可否修正属性的值,这是与[[Configurable
]]差别之处。 -
[[Value]]
:默许值为undefined
,这个值即为属性的属性值,我们可以在这个位置上读取属性值,也可以在这个位置上写入属性值。 - 注重:上述的默许是指经由过程组织函数或对象字面量建立的对象所本身具有的属性,而不是下面要引见的
Object.defineProperty()
要领
这些特性都具有默许值,然则假如这些默许值不是我们想要的,该怎样办呢?固然就是修正啦!我们可以经由过程Object.defineProperty()
要领来修正属性默许的特性。英文difineProperty即为定义属性的意义。这个要领吸收三个参数:属性地点的对象、属性的名字和一个形貌符对象。个中第三个参数形貌符对象是对象字面量的要领建立的,内里的属性和属性值实际上保留的是要修正的特性和特性值。
下面经由过程几个例子来深切明白。
a
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
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
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
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
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
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来直接接见获得接见器属性的特性,所以下面列出的特性将由[[]]括起来以作辨别。
-
[[Configurable]]
:默许值为true
,a、示意可否经由过程delete
删除属性从而从新定义属性 b、可否修正属性的特性c、可以把属性由接见器属性修正为数据属性 -
[[Enumerable]]
:默许值为true,示意可否经由过程for-in
轮回返回该属性(所以:假如为false
,那末for-in
轮回没法罗列它地点的属性) -
[[Get]]
:在读取属性时挪用的函数。默许值为undefined
症结:特性可以是一个函数 -
[[Set]]
: 在写入属性时挪用的函数。默许值为undefined
症结:特性可以是一个函数
因为get
和set
函数也属于属性的特性,那末他们就有能够(说有能够是因为这两个函数也不是必需的)出现在Object.defineproperty
的第三个参数形貌符对象的属性中。
注重:1.相关于数据属性,我们发明接见器属性中没有writable
特性和value
特性。这是因为接见器属性不包括数据值,那末我们怎样固然就不可修正属性的值(用不到writable
特性),更不必斟酌value
了。
2.接见器属性不能直接定义,必需是用Object.defineProperty()
来定义。(经由过程这个划定我们就可以正确地推断出接见器属性和数据属性了)
经由过程下面这个例子来深切明白:
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.接见器属性不能直接定义,必需运用Object.defineProperty()
来定义,且该属性具有set
和get
特性,因而可以推断,_year
和edition
是数据属性,而year
是接见器属性。
2.我们看到_year
这个数据属性前面是以_(下划线)开首的,这个一种经常使用的暗号,用于示意只能经由过程对象要领接见的属性。从上面的例子中可以看到get相当于形貌符对象的一个要领,而_year
恰是在这个对象要领接见的属性。而edition
既可以经由过程对象要领接见,也可以由对象直接接见。
-
book.year
示意正在读取接见器属性,这时候会挪用get
函数,并返回了2004这个有用的值。 -
book.year=2005
示意写入接见器属性,这时候会挪用set
函数并传入新值,行将2005传给newValue
,这个函数决议怎样处置惩罚数据。 - 这时候运用接见器属性的罕见要领-即设置一个属性的值会致使其他属性发生变化。
3.怎样应用Object.defineProperties()
要领定义多个特性
明显,一个对象不能够只具有一个属性,因而,定义多个属性的能够性很大,因而JavaScript供应了Object.defineProperties()
要领处理这个题目。这个要领吸收两个参数,第一个是要定义属性地点的对象,第二个是一个对象字面量要领建立的对象,对象的属性名即为要定义的特姓名,对象的属性值又是一个对象,这个对象里的属性名和属性值离别是特性名和特性值(这里不是很好明白,看例子即可)。
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虽然是属性的一个特性,然则它也是函数。