什么是对象
对象是单个实物的抽象,通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。
面向对象编程的第一步,就是要生成对象。
对象是一个容器,封装了属性(property)和方法(method),属性是对象的状态,方法是对象的行为(完成某种任务)。
比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是那一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。
典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。
JavaScript 语言的对象体系,不是基于“类”的,而是基于构造数constructor
和原型链prototype
;
所以JS ;一个构造函数,可生成多个实列对象,它们有相同的结构
构造函数与普通函数区别
- 构造函数就是一个普通的函数,但是有自己的特征和用法。
- 函数体内部使用了this关键字,代表了所要生成的对象实例。
- 生成对象的时候,必须使用new命令。
1
2
3
4
5
6
7
8
9
10
11
12//constructor
var Bird = function () {
this.name = 'lai fu';
};
var bird1 = new Bird(); // 也可以使用 new Bird; 推荐使用前者
console.log(bird1.name) // "lai fu"
//ordinary
var a =Bird();
console.log(a) // undefined
console.log(a.name) // typeError
name // 'laifu'
防止把构造函数constructor
当普通函数使用
1 | //使用 严格模式 |
new
命令的原理
- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的prototype属性。
- 将这个空对象赋值给函数内部的this关键字。
- 开始执行构造函数内部的代码。
1 | /** |
new.target
1 | function f() { |
this
实质
原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。
1 | var obj = { a: 1 }; |
JavaScript 存储变量实际上是以下面的形式保存的。
1 | { |
如果 a 属性的值是 那么属性将以下面的形式保存的:1
2
3
4
5
6
7
8
9
10
11var obj = { fn: function () {} };
/*
{
fn: {
[[value]]:
[[writable]]: true
[[enumerable]]: true
[[configurable]]: true
}
}
*/
由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。
1 | var f n= function () {}; |
JavaScript 允许在函数体内部,引用当前环境的其他变量。
由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代。
下面这几种用法,都会改变this的指向。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(obj.fn = obj.fn)() // window
// 等同于
(function () {
console.log(this);
})()
(false || obj.fn)() // window
// 等同于
(false || function () {
console.log(this);
})()
(4, obj.fn)() // window
// 等同于
(4, function () {
console.log(this);
})()
数组调用forEach 方法时函数内部this 指向window ,将父级上下文传递给forEach 改变this指向1
2
3
4
5
6
7
8
9
10
11var o = {
v: 'hello',
p: [ 'Owen', 18 ],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + '-' + item);
}, this); //将外层的this传递给forEach方法
}
}
o.f() // hello-Owen hello-18
end