JavaScript面向对象知识点小结

JavaScript面向对象主要知识点小结,基于ECMAScript 5.

构造函数

1
2
3
4
5
6
7
function People(name){
//this可以理解为通过new即将创建的对象
this.name = name;
}
//将类实例化
var person = new People('Cassie Xu');
console.log(person.name);

给一个对象赋予属性或者方法

1
2
3
4
5
6
7
8
function People(name) {
this.name = name;
this.greet = function() {
console.log('Hello, my name is ' + this.name + '!');
};
}
var person = new People('Cassie Xu');
person.greet();

原型(prototype)

why we use prototype? -> 便于方法的重用
与构造函数模式相比,使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。
运行时没找到函数的方法时,对象会首先找它的类的prototype方法

Demo1

1
2
3
4
5
6
7
8
9
10
11
12
13
function People(name) {
this.name = name;
}
People.prototype = {
greet: function() {
console.log('Hello, my name is ' + this.name + '!');
}
};
var person = new People('Cassie Xu');
person.greet();
//在每个实例化后的对象都会有一个__proto__属性,类会将它的prototype赋给实例
//实例化一个对象时,People这个类首先会将person的__proto属性指向People.prototype
console.log(person.__proto__ === People.prototype); // true

Demo2

1
2
3
4
5
6
var a = { foo: 1 };
var b = { bar: 2 };
b.__proto__ = a;
//b本身没有foo属性,但是b会继续寻找__proto__属性
console.log(b.foo); // 1
console.log(b.bar); // 2
1
2
3
var a = {};
console.log(a.__proto__); // {}
console.log(a.__proto__.__proto__); // null

原型链(prototype chain)

1
2
3
var a = {};
console.log(a.__proto__); // {}
console.log(a.__proto__.__proto__); // null

继承(Inheritance)

Demo1

1
2
3
4
5
6
7
8
9
10
11
12
function Parent(){}
Parent.prototype = {
greet: function(){
console.log('hello world');
}
}
function Child(){}
//此方法适用于父类Child不需要传参数
Child.prototype = new Parent();
var c = new Child();
//c首先寻找自身的方法,没有great,所以找Child的原型方法,而Child.prototype等于Parent方法
c.greet(); //console.log('hello world');

上面的例子如果Parent有参数,将存在以下问题:

1
2
3
4
5
6
7
8
function Parent(a, b) {}
Parent.prototype.greet = function() {
console.log('JavaScript rocks');
}
function Child(a, b) {}
Child.prototype = new Parent(); //something wrong?->new Parent()不能传参数,否则参数一直不变
var child = new Child();
child.greet();

Demo2

解决父类参数问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Parent() {
this.name = 'xxx',
this.date = 'xxx'
}
Parent.prototype.greet = function() {
console.log('JavaScript rocks');
}
function Child() {}
//此方法适用于
Child.prototype = Object.create(Parent.prototype);
//硬记的知识
Child.prototype.constructor = Child;
var child = new Child();
child.greet();

Demo3:继承的一个实例

创建一个矩形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Rect(width,height){
this._setupDOM(width,height);
}
Rect.prototype._setupDOM = function(width,height){
this._dom = document.createElement('div');
this._dom.style.width = width + 'px';
this._dom.style.height = height + 'px';
};
Rect.prototype.appendToBody = function(){
document.body.appendChild(this._dom);
};
function BlueRect(width,height){
BlueRect._super.apply(this,arguments);
}
BlueRect.prototype = Object.create(Rect.prototype);
BlueRect.prototype.constructor = BlueRect;
BlueRect._super = Rect;
BlueRect.prototype._setupDOM = function(width,height){
BlueRect._super.prototype._setupDOM.apply(this,arguments);
this._dom.style.backgroundColor = 'blue';
};
var br = new BlueRect(200,300);
br.appendToBody();

this关键字

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
function Rect(width,height){
//私有属性加_
this._dom = document.createElement('div');
this._dom.style.width = width + 'px';
this._dom.style.height = height + 'px';
this._dom.style.backgroundColor = 'red';
}
Rect.prototype.appendToBody = function(){
document.body.appendChild(this._dom);
};
var rect = new Rect(100,100);
rect.appendToBody();

修改上面demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Rect(width,height){
this._setupDom(width,height);
}
Rect.prototype._setupDom = function(width,height){
//私有属性加_
this._dom = document.createElement('div');
this._dom.style.width = width + 'px';
this._dom.style.height = height + 'px';
this._dom.style.backgroundColor = 'red';
};
Rect.prototype.appendToBody = function(){
document.body.appendChild(this._dom);
};
var rect = new Rect(100,100);
rect.appendToBody();
1
2
3
4
5
6
7
8
9
var person = {
firstName: "Penelope",
lastName: "Barrymore",
sayFullName: function () {
console.log(this.firstName + " " + this.lastName); //=> "Penelope Barrymore"
console.log(person.firstName + " " + person.lastName); //=> "Penelope Barrymore"
}
};
person.sayFullName();

严格模式下的this

1
2
3
4
funtion foo(){
'use strict';
console.log(this) //undefined
}

强制修改函数上下文的方法

用Object.bind()代替this

1
2
3
4
5
6
function foo(a, b) {
console.log(this);
console.log(a + b);
}
var fooBinding = foo.bind({ name: 'Cassie Xu' });
fooBinding(1, 2);

上面code将输出

1
2
3
4
[object Object] {
name: "Cassie Xu"
}
3

使用Object.call/Object.apply执行上下文

call/apply方法都为调用Object方法,区别是apply将所有参数放到一个数组中去

1
2
3
4
5
6
function foo(a, b) {
console.log(this);
console.log(a + b);
}
foo.call({name:'Cassie Xu'}, 1, 2);
foo.apply({name:'Cassie Xu'}, [1, 2]);

补充其他

自执行函数

why we use it? ->避免泄露全局变量

1
2
3
4
5
6
(function(c){
var a = 1;
var b = 2;
console.log(a+b+c);
})(3)
// c = 3

闭包作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = {};
a.foo = function(callback) {
// do something and call callback in whatever way
}
a.bar = function() {
this.num = 1;
var that = this;
//闭包,这里that可以访问到a.bar的作用域
this.foo(function(newNum) {
that.num = newNum;
});
console.log(this.num);
}
a.bar();