高程笔记-对象1

《JavaScript高级程序》笔记,主要关于对象属性以及对象的创建方式。

最简单的创建方式是通过Object。

1
2
3
4
5
6
7
8
var person = new Object();
person.name = "xiaoming";
person.age = "12";
person.job = "student";

person.sayName = function(){
console.log(this.name);
}

属性类型

属性分类

ECMA-262定义描述内部特性,有两种(只能为其中一种),如下:

数据属性 访问器属性
[[ Configurable ]] [[ Configurable ]]
[[ Enumerable ]] [[ Enumerable ]]
[[ Writable ]]
[[ Value ]]
[[ Get ]]
[[ Set ]]

[[ Configurable ]]:表示能否被delete删除重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。

[[ Enumerable ]]:表示能否被for-in循环返回属性。

[[ Writable ]]:表示能否修改属性的值。

[[ Value ]]:包含这个属性的数据值。读取属性值时,从这个位置读取;写入属性值的时候,把新值保存在这个位置。默认undefined。

[[ Get ]]:在读取属性时掉用的函数。默认值为undefined。

[[ Set ]]:在写入属性时掉用的函数。默认值为undefined。

设置默认属性需要es5的Object.definedProperty()方法。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var person = {};
Object.definedProperty(person,'name',{
writable : false,
value: 'xiaoMing'
});

console.log(person.name); // 'xiaoMing'
person.name = 'xiaoHong';
console.log(person.name); // 'xiaoMing'

Object.definedProperty(person,'name',{
configurable : false,
value: 'xiaoMing'
});
console.log(person.name); // 'xiaoMing'
person.name = 'xiaoHong';
console.log(person.name); // 'xiaoMing'

// 报错
Object.definedProperty(person,'name',{
configurable : true,
value: 'xiaoMing'
});

单属性定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var book = {
_year: 2004,
edition: 1
}
Object.definedProperty(book,'year',{
get: function (){
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var book = { };
Object.definedProperties(book,{
_year:{
value: 2004
},
edition: {
value: 1
},
year: {
get: function (){
return this._year;
},
set: function(newValue){
if( newValue > 2004 ){
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});

var descriptor = Object.getOwnPropertyDescriptor(book,"_year");
alert(descriptor.value) //2004
alert(descriptor.configurable) //false

创建对象

工厂模式

对象的识别不明确。

1
2
3
4
5
6
7
8
9
10
11
12
function createPerson(name,age,job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName =function(){
alert(this.name);
}
return o;
}
var person1 = createPerson('Nicholas','29','teacher');
var person2 = createPerson('Greg','19','student');

构造函数模式

方法的重复创建,即每个实例上面都会创建一个方法。如下例中,person1和person2都含有sayName()的方法。如果将sayName()单独提取出来,当方法很多的时候,就会出现污染全局变量的问题。

1
2
3
4
5
6
7
8
9
10
function Person(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName =function(){
alert(this.name);
}
}
var person1 = new Person('Nicholas','29','teacher');
var person2 = new Person('Greg','19','student');

原型模式

解决了方法会污染环境变量的问题,但是对于数组、对象这种引用类型,可能会出现如下例的问题。虽然friends属性不同,但是指向的同一地址,从而影响其它实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Person() {}
Person.prototype = {
name: 'Nicholas',
age:'29',
job:'teacher',
friends:['lucy','jon','angus'],
sayName: function(){
alert(this.name);
}
}

var person1 = new Person();
person1.sayName() // 'Nicholas'

var person2 = new Person();
person2.sayName() // 'Nicholas'

person1.friends.push('van');
alert(person1.friends); //'lucy','jon','angus'
alert(person2.friends); //'lucy','jon','angus'
alert(person1.friends === person2.friends); //true

组合构造函数和原型模式

常用的一种创建方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ['lucy','jon','angus'];
}
Person.prototype = {
constructor: Person,
sayName: function(){
alert(this.name);
}
}
var person1 = new Person('Nicholas','29','teacher');
var person2 = new Person('Greg','19','student');

person1.friends.push('van');
alert(person1.friends); //'lucy','jon','angus'
alert(person2.friends); //'lucy','jon'
alert(person1.friends === person2.friends); //false

动态原型模式

初次执行函数时,会触发判断。原型不能使用字面量的模式创建,相当于重写,会出现丢失构造函数的问题。

1
2
3
4
5
6
7
8
9
10
function Person(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != 'function' ){
Person.prototpe.sayName = function(){
alert(this.name);
};
}
}

稳妥构造函数模式

name只能由sayName()函数访问属性,通过提供安全性,特殊情况使用。

1
2
3
4
5
6
7
8
9
function Person(name,age,job) {
var o = new Object();
o.sayName = function(){
alert(name);
};
return o;
}
var person1 = Person('Nicholas','29','teacher');
person1.sayName(); // Nicholas
------本文结束 感谢阅读------