似懂非懂的继承

原型链继承

js中当对象进行属性查找时,如果对象本身找不到对应的属性,就会去搜索原型链,结合这个特性,js就可以来实现对象之间的继承。

instanceof && isPrototypeOf()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.getInfo = function(){
console.log(this.name + " " + this.age)
}
function Teacher(subject){
this.subject = subject
}
Teacher.prototype = new Person()
var will = new Teacher("Math")
//把创建的新对象new Person()赋值为“Teacher”的原型,此时"Teacher"继承"Person"
will instanceof Object // true
will instanceof Person //true
will instanceof Teacher //true
------
Object.prototype.isPrototypeOf(will) //true
Person.prototype.isPrototypeOf(will) //true
Teacher.prototype.isPrototypeOf(will) //true
constructor属性

对于所有的js原型对象,有一个constructor属性,该属性对应构造函数。

  • 上述代码中will的原型是通过构造函数new Person()构造出来的对象(即Person{name:undefined, age:undefined}。will的构造函数是Person,而非Teacher。
  • will访问constructor属性的时候,先找到Teacher.prototype,接着是Person.prototype,它的constructor属性指向Person构造函数。

重设constructor属性,使wiil对应到正确的构造函数中

1
2
3
4
5
6
Teacher.prototype.constructor = Teacher
#更佳的方式,设置enumerable属性为默认的false
Object.defineProperty(Teacher.prototype,"constructor",{
enumerable: false,
value: Teacher
})

原型的更新和重写
1
2
3
4
5
6
7
8
9
10
11
#原型更新
Teacher.prototype.getId = function(){
console.log('原型更新')
}
#原型重写
Teacher.prototype = {
getStaffId:function(){
console.log('原型重写')
}
}
相当于Teacher的原型变成了一个字面量对象,里面有一个getStaffId方法。这个字面量对象的方法的原型指向Object.prototype

组合继承(两个构造函数)

在子类的构造函数中通过call来调用父类的构造函数进行初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.getId = function(){
console.log(this.name + " " + this.age)
}
function Teacher(name,age,country){
Person.call(this,name,age)
this.country = country
}
Teacher.prototype = new Person() //继承
Object.defineProperty(Teacher.prototype,"constructor",{ //确定constructor指向
enumerable:false,
value:Teacher
})
var tom = new Teacher("Tom",18,"shanghai")
  • 不足之处,在调用子类型构造函数的时候会重写超类型对象的属性。

原型式继承(通过字面量定义的对象)
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
function object(o){
function F(){} //创建一个函数
F.prototype = o //原型等于对象o
return new F() //返回函数的实例
}
---------------
var A = {
add:function(){
console.log('addA')
},
sub:function(){
console.log('subA')
}
}
var B = object(A)
B.add = function(){
console.log('addB')
}
B.div = function(){
console.log('divB')
}
-----------
B.add() //addB
B.sub() //subA
B.div() //divB

  • 以上的方法可以用Object.create()方法来实现原型式继承,两个参数

    • 用作新对象原型的对象
    • 为新对象定义的额外属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var C = Object.create(A,{
    sub:{
    value:function(){
    console.log('subC')
    }
    },
    multi:{
    value:function(){
    console.log('multiC')
    }
    }
    })

以上都是bullshit,又臭又长,现在直接使用es6的class,参照我后面一篇博客。