关于JS中面向对象的理解

oop(Object Oriented Programming)

它是一种编程思想,我们的编程或者学习其实是按照实例来完成的

学习类的继承/封装/多态

封装

  • 把实现一个功能的代码封装到一个函数(类),以后再想实现这个功能,只需要执行函数方法即可,不需要再重复的编写代码
  • 低耦合,高内聚:减少页面中冗余代码,提高代码的重复使用率

多态

  • 一个类(函数)的多种形态
    • 重载
      • 后台编程语言中,对于重载的改变:方法名相同参数不同,叫做方法的重载
      • JS中的重载,同一个方法,通过传递不同的实参我们完成不同的功能,我们把这个也可以理解为重载
    • 重写
      • 不管是后台语言还是JS都有重写,子类重写父类的方法

类的继承

什么是继承?

让子类的原型指向父类的实例

1
Children.prototype = new Parent();

[细节]

  1. 我们首先让子类的原型指向父类的实例,然后再向子类原型上扩展方法。,目的是为了防止提前增加方法,等原型重新趾向后,之前再子类圆形上扩展的方法都没用了(子类原型已经指向新的空间地址)
  2. 让子类原型才重新指向父类实例,子类原型上原有的constructor就没了,为了保证构造函数的完整性,我们最好给子类的原型冲洗手动设置constructor Children.prototype.constructor = Children

[原理]

原型继承,并不是把父类的属性和方法copy一份给子类,而是让子类的原型和父类原型之间搭建一个链接的桥梁,以后子类(或者子类的实例),可以通过原型链的查找机制,找到父类原型上的方法,从而调取这些方法使用即可

Children.prototype.__proto__.setX = function... 子类通过原型链找到父类的原型,再父类原型上增加新的属性和方法(重写:子类重写父类原型上的方法)

[特征]

  1. 子类不仅可以继承父类原型上的共有属性和方法,而且父类提供给实例的那些私有属性和方法,也被子类继承了(存放在子类的原型上,作为子类共有的属性和方法)

call继承

1
2
3
4
5
6
7
8
9
10
11
function Parent(){
this.x = 100;
}
Parent.prototype.getX = function(){
console.log(this.x);
}
function Children(){
Parent.call(this); //=> Parent执行,方法中的this依然是子类的实例(再父类构造体中写一些this.xxx=xxx 都相当于给子类的实例增加一些私有的属性和方法)
this.y = 200;
}
var child = new Children();

[原理]

原理是把父类构造体当中私有的属性和方法,复制一份给子类的实例(继承完成后子类和父类是没关系的)

[细节]

我们一般把call继承放在子类构造体的第一行,也就是创建子类实例的时候,进来的第一件事情就是先继承,然后再给实例赋值自己私有的(好处:可以把继承过来的记过替换掉)

寄生组合继承

Object.create([obj]):创建一个空对象,把[obj]作为心创建对象的原型

子类公有的继承父类公有的(原型继承)

子类私有的继承父类私有的(call继承)

1
2
3
4
5
//=> Obejct.create
var Obj = {name: 'aa'}
//=> 创建一个空对象,把obj作为当前空对象的原型
var newObj = Obejct.create(obj);
newObj.__proto__ = obj;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Parent(){
this.x = 100;
}
Parent.prototype.getX = function(){
console.log(this.x);
}
var obj = Obejct.create(Parent.prototype);
//=> console.log(obj instanceof Parent); //=> true

function Children(){
Parent.call(this); //=> 继承父类私有
this.y = 200;
}
Children.prototype = Object.create(Parent.prototype); //=> 继承父类公有
Children.prototype.constructor = Children;
Children.prototype.getY = function(){
console.log(this.y);
}
1
2
3
4
5
6
7
Object.myCreate = function myCreate(obj){
var Fn = new Function();
Fn.prototype = obj;
return new Fn();
};
var aa = {name: 'aa'};
Object.myCreate(aa);

ES6中的类

创建类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Fn {
constructor(){
//=> constructor:Fn
//=> 这里边的 this.xxx = xxx;是给当前实例设置的私有属性
//=> 给实例设置的私有属性
this.xxx = xxx;
}
//=> 这里设置的方法都放在Fn.prototype上(给实例提供的公有的属性方法)
//=> getX setX 都是给fn的prototype设置方法
getX(){

}
setX(){

}
//=> 把Fn当做一个普通对象,增加的属性和方法
static xxx(){

}
};
var f = new Fn();

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A{
constructor(){
this.x = 100;
}
getX(){
console.log(this.x);
}
}
class B extends A {
constructor(){
super(); //=> call继承
this.y = 200;
}
getY(){
console.log(this.y);
}
}
var b = new B();

for in 循环问题

不仅可以遍历当前对象(或者实例)所有的私有属性和方法,还可以把原型上自己创建的公共属性和方法进行遍历

for循环只会遍历私有地属性和方法,自己在原型上扩展的方法不会被遍历出来

1
2
3
4
5
6
7
Object.prototype.myXX = function(){

};
var obj = {name: 'aa'};
for(var i in obj){
console.log(i);
}