Javascript对象

《JavaScript高级程序设计学习笔记》之Javascript对象。
面向对象(Object-Oriented, OO)的语言有一个标志,那就是它们都有类的概念
而通过类可以创建任意多个具有相同属性和方法的对象。
ECMAScript没有类的概念,因此它的对象也与机遇类的语言中的对象有所不同
ES6新增了对象Class的语法糖,这里不讨论ES6

理解对象

1.对象

1
2
3
4
5
6
7
var person = new Object();

person.name = "jack";

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

2.属性

ECMAScript中有两种属性

1)数据属性,数据属性有4个描述其行为的特性

1
2
3
4
5
6
7
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性改为访问器属性。

[[Enumerable]]:能否通过for-in遍历

[[Writabe]]:是否能修改属性的值

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

要修改属性的默认特性必须使用ECMAScript5的Object.defineProperty()方法。

1
2
3
4
5
6
7
var person = {};

Object.defineProperty(person, "name", {
configurable:true, //设置false之后下次用defineProperty修改此属性就会抛错
value: jack
});

2)访问器属性

访问器属性不包含数据值;它们包含一对getter和setter函数;

读取访问器属性的时候会调用getter函数;写入访问器属性的时候会调用setter函数

访问器属性有如下4个特性

1
2
3
4
5
6
7
[[Configurable]]:同上数据属性

[[Enumerable]]:同上数据属性

[[Get]]:在读取属性的时候调用的函数。默认undefined

[[Set]]:在写入属性的时候调用的函数。默认为undefined
  1. 访问器属性不能直接定义,必须使用Object.defineProperty()来定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var book = {
__year:2016,
edition:1
};

Object.defineProperty(book, "year", {
get: function() {
return this.__year;
},
set: function(newValue) {
if (newValue > 2016) {
this.__year = newValue;
this.edition += newValue - 2016;
}
}
});

book.year = 2017;
console.log(book.edition); // 2
  1. 定义多个属性

ECMAScript5定义了一个Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var book = {};

Object.defineProperties(book, {
__year: { //数据属性
value:2016,
writable:false
},
edition: { //数据属性
value:1,
writable:true
},
year: { //访问器属性
get: function() {
return this.__year;
},
set: function(newValue) {
if (newValue > 2016) {
this.__year = newValue;
this.edition += newValue - 2016;
}
}
}
});
  1. 读取属性的特性

使用ECMAScript5的Ojbect.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。

1
2
3
4
5
//...上面的例子

var descriptor = Object.getOwnPropertyDescriptor(book, "__year");
console.log(descriptor.value, descriptor.writable, descriptor.configurable, descriptor.value);

  1. Object 排序
1
2
3
4
5
6
7



如果key字符串和数字,数字优先

如果属性名是 symbol,按照string排

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var obj0 = {
0: 'a',
3: 'b',
2: 'c',
1: 'd'
}
// console.log(obj0)
// 如果 key 为数字,按照从小到大排
// {0: "a", 1: "d", 2: "c", 3: "b"}

var obj1 = {
'0': 'a',
'3': 'b',
'2': 'c',
'1': 'd'
}
// console.log(obj1)
// 如果 key 为数字组成的字符串,按照从小到大排
// {0: "a", 1: "d", 2: "c", 3: "b"}

var obj2 = {
'd': 'a',
'b': 'b',
'c': 'c',
'a': 'd'
}
// console.log(obj2)
// 如果 key 为字符串,按照字符串创建时间顺序排
// {d: "a", b: "b", c: "c", a: "d"}

var obj3 = {
c: 'a',
b: 'b',
2: 'c',
1: 'd'
}
// console.log(obj3)
// 如果 key 为字符串和数字,数字优先
// {1: "d", 2: "c", c: "a", b: "b"}

var obj4 = {
'伯': 'b',
'c': 'cc',
'阿': 'a',
2: 'c',
1: 'd'
}
// console.log(obj4)
// 如果 key 为字符串,按照字符串创建时间顺序排,中文也算字符串
// {1: "d", 2: "c", 伯: "b", c: "cc", 阿: "a"}

var obj5 = {
0: 'a',
3: 'b',
'-2': 'c',
1: 'd'
}
// console.log(obj4)
// 如果 key 为字符串,按照字符串创建时间顺序排,负数算字符串
// {0: "a", 1: "d", 3: "b", -2: "c"}

创建对象

1.工厂模式

2.构造函数模式

3.原型模式

4.组合使用构造函数模式和原型模式

5.动态原型模式

6.寄生构造函数模式

7.稳妥构造函数模式


继承

许多OO语言都支持两种继承方式:

1
2
3
接口继承:继承方法签名

实现继承:继承实际方法

JavaScript支持实现继承,且继承方式是依靠原型链实现的(es6的class类已经支持继承)

1.原型链继承

2.借用构造函数实现继承

3.组合继承

4.原型式继承

5.寄生继承

6.寄生组合式继承