JavaScript 对象详解

创建对象

  • 使用对象初始化器来创建对象
1
2
var obj = {key_1:value_1,
key_2:value_2,...}
1
var myObj = {color: red, wheels:4, engine:{cylinders: 4, size: 2.2}}
  • 使用Object.create()方法创建对象
    • 语法是(属性描述符会在下面讲解):
1
Object.create(proto, [ propertiesObject ])
1
2
3
4
5
6
7
8
9
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: { writable:true, configurable:true, value: "hello" },
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) { console.log("Setting `o.bar` to", value) }
}})
  • 混合构造函数和原型方式创建对象
1
2
3
4
5
6
7
8
9
10
11
function Parent(){
this.name = "Jack";
this.age = 22;
}

Parent.prototype.lev = function(){
return this.name;
}

var x = new Parent();
alert(x.lev()); //Jack

对象属性的遍历

  • 遍历属性
1
2
3
4
var obj = {prop1: 4, prop2: 5, prop3: 6};
for(var i in obj){
console.log(i); //prop1 prop2 prop3
}
  • 遍历属性值
1
2
3
4
var obj = {prop1: 4, prop2: 5, prop3: 6};
for(var i in obj){
console.log(obj[i]); //4 5 6
}

对象常用操作

  • 对象的访问
    • obj.name和obj[“name”]效果一样;
  • 获取key值组成的数组
1
var arr = Object.keys(obj);
  • 删除对象或属性
1
2
3
delete objectName;
delete objectName.prop;
delete prop; //仅仅在with语句中可以使用

getter和setter

  • getter和setter是对象属性的属性描述符的一种,可以在定义对象属性的时候指明;
  • getter和setter用于获取或者修改对象的某个属性;
  • 通过对象初始化器在创建对象的时候指明:
1
2
3
4
5
6
7
8
9
10
11
(function () {
var o = {
a : 7,
get b(){return this.a +1;}, //通过 get,set的 b,c方法间接性修改a属性
set c(x){this.a = x/2}
};
console.log(o.a); //7
console.log(o.b); //8
o.c = 50;
console.log(o.a); //25
})();
  • 使用 Object.create 方法指定:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(function () {
var o = null;
o = Object.create(Object.prototype,//指定原型为 Object.prototype
{
bar:{
get :function(){
return this.a;
},
set : function (val) {
console.log("Setting `o.bar` to ",val);
this.a = val;
},
configurable :true
}
} //第二个参数
);
o.a = 10;
console.log(o.bar); //10
o.bar = 12;
console.log(o.bar); //12
})();
  • 使用 Object.defineProperty 方法指定:
    • Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回这个对象;
    • 语法:Object.defineProperty(obj, prop, descriptor)
    • 参数:obj 需要定义属性的对象;prop 需被定义或修改的属性名;descriptor 需被定义或修改的属性的描述符;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function () {
var o = { a : 1} //声明一个对象,包含一个 a 属性,值为1
Object.defineProperty(o,"b",{
get: function () {
return this.a;
},

set : function (val) {
this.a = val;
},

configurable : true
})
;


console.log(o.b);
o.b = 2;
console.log(o.b);
})
();

  • 使用 Object.defineProperties方法指定:
    • 概述:Object.defineProperties() 方法在一个对象上添加或修改一个或者多个自有属性,并返回该对象;
    • 语法:Object.defineProperties(obj, props)
    • 参数:obj 将要被添加属性或修改属性的对象;props 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置;
    • 用法与 Object.defineProperty 方法类似;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function () {
var obj = {a:1,b:"string"};
Object.defineProperties(obj,{
"A":{
get:function(){return this.a+1;},
set:function(val){this.a = val;}
},

"B":{
get:function(){return this.b+2;},
set:function(val){this.b = val}
}

})
;


console.log(obj.A);
console.log(obj.B);
obj.A = 3;
obj.B = "hello";
console.log(obj.A);
console.log(obj.B);
})
();

  • 使用 Object.prototype.defineGetter以及 Object.prototype.defineSetter方法指定:
1
2
3
4
5
6
7
8
9
10
11
12
(function () {
var o = {a:1};
o.__defineGetter__("giveMeA", function () {
return this.a;
})
;

o.__defineSetter__("setMeNew", function (val) {
this.a = val;
})

console.log(o.giveMeA); //1
o.setMeNew = 2;
console.log(o.giveMeA); //2
})
();

属性描述符

  • 说明:
    • 对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。
    • 数据描述符是一个拥有可写或不可写值的属性。
    • 存取描述符是由一对 getter-setter 函数功能来描述的属性。
    • 描述符必须是两种形式之一;不能同时是两者。
  • 数据描述符和存取描述符均具有以下可选键值:
1
2
3
4
configurable
当且仅当这个属性描述符值为 true 时,该属性可能会改变,也可能会被从相应的对象删除。默认为 false
enumerable
true 当且仅当该属性出现在相应的对象枚举属性中。默认为 false
  • 数据描述符同时具有以下可选键值:
1
2
3
4
value 
与属性相关的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined
writable
true 当且仅当可能用 赋值运算符 改变与属性相关的值。默认为 false
  • 存取描述符同时具有以下可选键值:
1
2
3
4
get 
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。方法将返回用作属性的值。默认为 undefined
set
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将收到作为唯一参数的新值分配给属性。默认为 undefined
  • 上面键值的含义:

    • 数据描述符包括两个属性 : value 属性以及 writable属性,第一个属性用来声明当前欲修饰的属性的值,第二个属性用来声明当前对象是否可写即是否可以修改;
    • 存取描述符就包括 get 与 set 属性用来声明欲修饰的象属性的 getter 及 setter;
    • 属性描述符内部,数据描述符与存取描述符只能存在其中之一,但是不论使用哪个描述符都可以同时设置 configurable 属性以及enumerable 属性;
    • configurable属性用来声明欲修饰的属性是否能够配置,仅有当其值为 true 时,被修饰的属性才有可能能够被删除,或者重新配置;
    • enumerable 属性用来声明欲修饰属性是否可以被枚举,决定属性是否能被 for…in 循环或 Object.keys 方法遍历得到;
  • create方法为显示配置对象的属性和值,如不声明将按照属性描述符的默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function () {
var obj = {};
Object.defineProperty(obj,"key",{
value:"static"
//没有设置 enumerable 使用默认值 false
//没有 configurable 使用默认值 false
//没有 writable 使用默认值 false
})
;


console.log(obj.key); // static
obj.key = "new" //尝试修改其值,修改将失败,因为 writable 为 false
console.log(obj.key); // static
delete obj.key; //尝试删除属性,失败,因为 configurable 使用默认值 false
console.log(obj.key); // static
obj.a = 1; //动态添加一个属性
for(var item in obj){ //遍历所有 obj 的可枚举属性
console.log(item);
} //只输出一个 “a” 因为 “key”的 enumerable为 false

})
();

  • defineProperty、defineProperties方法为显示配置对象的属性和值,如不声明将按照属性描述符的默认值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function () {
var obj = {};
Object.defineProperty(obj,"key",{
value : "static"
//没有设置 enumerable 使用默认值 false
//没有 configurable 使用默认值 false
//没有 writable 使用默认值 false
})


console.log(obj.key); // static
obj.key = "new" //尝试修改其值,修改将失败,因为 writable 为 false
console.log(obj.key); // static
delete obj.key; //尝试删除属性,失败,因为 configurable 使用默认值 false
console.log(obj.key); // static
obj.a = 1; //动态添加一个属性
for(var item in obj){ //遍历所有 obj 的可枚举属性
console.log(item);
} //只输出一个 “a” 因为 “key”的 enumerable为 false

})
();

  • var o = {}; o.a = 1;这个语句却和上面不同,它的等价配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function () {
var o = {};
o.a = 1;
//等价于
Object.defineProperty(o,"a",{value : 1,
writable : true,
configurable : true,
enumerable : true})
;


Object.defineProperty(o,"a",{value :1});
//等价于
Object.defineProperty(o,"a",{value : 1,
writable : false,
configurable : false,
enumerable : false})
;

})
();

  • Enumerable属性专项研究:
    • 属性特性 enumerable 决定属性是否能被 for…in 循环或 Object.keys 方法遍历得到;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function () {
var o = {};
Object.defineProperty(o,"a",{value :1,enumerable :true});
Object.defineProperty(o,"b",{value :2,enumerable :false});
Object.defineProperty(o,"c",{value :2}); //enumerable default to false
o.d = 4; //如果直接赋值的方式创建对象的属性,则这个属性的 enumerable 为 true

for(var item in o){ //遍历所有可枚举属性包括继承的属性
console.log(item); //a d
}


console.log(Object.keys(o)); //输出["a","d"],获取o对象的所有可遍历属性不包括继承的属性

console.log(o.propertyIsEnumerable('a')); //true
console.log(o.propertyIsEnumerable('b')); //false
console.log(o.propertyIsEnumerable('c')); //false
console.log(o.propertyIsEnumerable('d')); //true
})
();

  • Configurable属性专项研究:
    • Configurable属性如果为false,表示对象的Configurable、Enumerable、value、writable、set、get属性一旦确定(包含默认确定的)就不能再更改,对象的这个属性也不能被删除;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(function () {
var o = {};
Object.defineProperty(o,"a",{get: function () {return 1;},
configurable : false} );

//enumerable 默认为 false,
//value 默认为 undefined,
//writable 默认为 false,
//set 默认为 undefined

//抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置
Object.defineProperty(o,"a",{configurable : true} );
//抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置,enumerable 的原值为 false
Object.defineProperty(o,"a",{enumerable : true} );
//抛出异常,因为最开始定义了 configurable 为 false,set的原值为 undefined
Object.defineProperty(o,"a",{set : function(val){}} );
//抛出异常,因为最开始定义了 configurable 为 false,故无法进行覆盖,尽管想用一样的来覆盖
Object.defineProperty(o,"a",{get : function(){return 1}});
//抛出异常,因为最开始定义了 configurable 为 false,故无法将其进行重新配置把属性描述符从存取描述符改为数据描述符
Object.defineProperty(o,"a",{value : 12});

console.log(o.a);//输出1
delete o.a; //想要删除属性,将失败
console.log(o.a);//输出1

})
();

您的支持是对我最大的鼓励!