JavaScript精要之对象
1.定义属性
当一个属性第一次被添加给对象的时候,JavaScript在对象上调用了一个名为[[Put]]的内部方法。[[Put]]方法会在对象上创建一个新的节点来保存属性。此处创建的是自有属性,而不是原型属性。当一个已有属性,被赋予一个新的值的时候,调用[[Set]]方法。
2.属性探测
探测属性常见的错误:1
2
3if(person1.age){
do...
}
问题是:JavaScript的类型强制会影响其输出的结果。如果if判断的值是:一个对象、非空字符串、非0数字或者true时,判断为真;如果if判断的值是null、undefined、0、false、NaN或者空字符串的时候判断为假。
通过探测属性使用in和hasOwnProperty().1
2
3
4
5console.log("name" in person1);//true
console.log("toString" in person1);//true
console.log(person1 hasOwnProperty("name");//true
console.log(person1 hasOwnProperty("toString");//false
3.删除属性
注意:将一个属性值设置为null并不能从对象中彻底移除那个属性,只是调用了[[set]]这一内部方法,将属性值替换了而已。删除属性:delete。1
delete person1.name;
4.属性枚举
两种方式:①for…in ②Object.keys()
示例:
for in 一般用于你不知道该数组或者JSON中包含哪些元素(还有就是对象中的哪些属性),而进行遍历。(key的值就相当于下标)
例如有一个元素未知的JSON对象:1
2
3
4
5var clnums = {a:1,b:2,...};
var key;
for(key in clnums){
document.write(clnums[key]);
}
如果你只需获取一个对象的属性列表,以备程序将来使用。可以使用Object.keys()方法:1
2
3
4
5
6var zs = Object.keys(object);
var i;
for(i=0;i<zs.length;i++){
console.log("name:"+zs[i]);
console.log("value:"+object[zs]);
}
Console显示如下:
*注意:并不是所有的属性都是可以枚举的。实际上,大部分的原生方法的[[Enumerable]]都被设置成了false。可以使用propertyIsEnumerable()方法来检测属性是否是可以枚举的。1
2
3
4
5
6
7
8var person1 ={
name:“Cooling”
};
console.log(person1.propertyIsEnumerable("name"));//true
var zs = Object.keys(person1);
console.log("length" in zs);
console.log(zs.propertyIsEnumerable("length");//false内建属性不可枚举,因此zs是不存在的
5.属性类型
属性分为两种:++数据属性、访问器属性++。[[put]]方法默认创建的是数据属性,如前面的name、age属性等。
访问器属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14var person1 = {
_name: "Cooling",
get name(){
console.log("Reading name");
return this._name;
},
set name(value){
console.log("Setting name to %s",value);
this._name = value;
};
console.log(person1.name);
person1.name = "zs";
console.log(person1.name);
注释:本例定义了一个访问器属性name。一个数据属性_name保存了访问器属性的实际值。(下划线是一个约定俗成的规范,表示该属性是被私有的,实际上它还是公开的)。读取时调用的函数称为getter,写入时调用的函数称为setter。如果只定义其中一个函数,那么,其属性将会是只读或者是只写的。
6.属性特征
6.1通用特征:
通用属性有两个:[[Enumerable]](表示是否可以枚举,也就是是否可以遍历)、[[Configurable]](表示是否可以配置)。你所声明的所有属性都是可以枚举、可以配置的。如果想对一个属性进行设置是否可以枚举和配置(方法:Object.defineProperty()),可以如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19var person1 = {
name:"Cooling"
};
Object.defineProperty(person1,"name",{
Enumerable:false
});
console.log(person1.propertyIsEnumerable("name");//false
var zs = Object.keys(person1);
console.log(zs.length);//0
Object.defineProperty(person1,"name",{
configurable:false;
});
delete person.name;
console.log(person1.name);//Cooling
Object.defineProperty(person1,"name",{
confingurable:true;
}); //error!!!
6.2数据属性的特征
数据属性具有两个访问器属性不具有的特征。即:[[Value]]、[[Writable]].
实例:(当Object.defineProperty()被调用时,会先检测属性是否存在,如果不存在,则根据所给定的特征创建。)1
2
3
4
5
6
7var person1 = {};
Object.defineProperty(person1,"name",{
value:"cooling",
enumerable:true,
configurable:true,
writable:true
});
当你使用Object.defineProperty()定义新的属性的时候,一定要注意为所有的特征指定一个值,否则布尔型的特征值会被默认设置为false。如:1
2
3
4
5
6
7
8
9
10var person1 = {};
Object.defineProperty(person1,"name",{
value:"cooling";
});
console.log("name" in person1);//true
console.log(person1.propertyIsEnumerable("name")//false
delete person1.name;
console.log(person1.name);//cooling
person1.name = "zs";
console.log(person1.name);//cooling
温馨提示:数据属性可以通过writable来设置属性是否可以被写。而在访问器属性中,可以通过setter和getter设置!
6.3访问器属性的特征
也具有两个额外的特征:[[Get]]、[[Set]]。仅仅需要定义其中一个特征就可以创建一个访问器属性。
注意:不能同时创建一个具有数据属性特征和访问器属性特征的属性。
可以将前面的改写:1
2
3
4
5
6
7
8
9
10var person1 = {
_name: "Cooling",
get name(){
console.log("Reading name");
return this._name;
},
set name(value){
console.log("Setting name to %s",value);
this._name = value;
};
改写后:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var person1 = {
_name: "Cooling"
};
Object.defineproperty(person1,"name",{
get function(){//注意改变
console.log("Reading name");
return this._name;
},
set function(value){//注意改变
console.log("Setting name to %s",value);
this._name = value;
},
enumerable: true,
configurable:true
});
//注意:跟数据属性类似,如果这里的enumerable: true和configurable:true都不写的话,那么,就默认为false。这样就只能读取属性,不能改变属性。
6.4定义多重属性
使用方法:Object.defineProperties();
使用示例:(定义了_name数据属性和name访问器属性)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var person1 = {};
Object.defineProperties(person1,{
_name:{
value:"cooling",
enumerable:true,
configurable:true,
writable:true
},
name:{
get:function(){
console.log("Reading name");
return this.name;
},
set:function(value){
console.log("Setting name to %s",value);
},
enumerable:true,
configurable:true,
}
});
6.5获取属性的特征
方法:Object.getOwnPropertyDescriptor();1
2
3
4
5
6var person1 = {
name: "cooling"
};
var descipt = Object.getOwnPropertyDesciptor(person1,"name");
console.log(descipt.enumerable);//true
console.log(descipt.configurable);//true
温馨提示:要特别注意使用Object.defineProperty()定义属性和直接var person1 = {name:”cooling”};这样定义的区别。他俩一个属性特征是完全不一样的!
7.禁止修改对象
对象和属性一样都具有指导其行为的内部特征。其中,[[Extensible]]就是一个,值为布尔类型的,表示是否可以扩展,也就是是否可以为对象添加属性。
有三种方式禁止修改对象:
①禁止扩展(不可添加属性,可以对属性值进行修改,同时也可以删除属性值)
【注:[[Extensible]]为false】
方法:Object.preventExtensions();
使用示例:1
2
3
4
5
6
7
8
9
10
11
12var person1 = {
name:"cooling";
};
console.log(Object.isExtensible(person1));//true
Object.preventExtensions(person1);
console.log(Object.isExtensible(person1);//false
person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false
②对象封印(不可添加属性、可以对属性值进行修改,但是不能删除属性值)
【注:[[Extensible]]:flase [[Configurable]]:false】
方法:Object.seal();
使用示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var person1 = {
name:"cooling"
};
console.log(Object.isExtensible(person1));//true
console.log(Object.isSealed(person1));//false
Object.seal(person1);
console.log(Object.isExtensible(person1));//false
console.log(Object.isSealed);//true
person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false
person1.name = "zs";
console.log(person1.name)//zs
delete person1.name;
console.log("name" in person1);//true
console.log(person1.name)//zs
var de = Object.getOwnPropertyDescriptor(person1,"name");
console.log(de.configurable);//false
③对象冻结(不可添加属性,不可对属性进行修改,不能写入数据)
【注:[[Configurable]]:false [[Writable]]:false [[Extensible]]:false】
方法:Object.freeze();
使用示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var person1 = {
name:"cooling";
};
console.log(Object.isExtensible(person1));//true
console.log(Object.isSealed(person1));//false
console.log(Object.isFrozen);//false
Object.freeze(person1);
console.log(Object.isExtensible(person1));//false
console.log(Object.isSealed(person1));//true
console.log(Object.isFrozen);//true
person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false
person1.name = "zs";
console.log(person1.name);//cooling
var de = Object.getOwnPropertyDescriptor(person1,"name");
console.log(de.configurable);//false
console.log(de.writable);//false