快速理解js继承原理

JS继承原理

js 的继承是通过原型链来实现的

什么是原型链呢?

首先说一下 prototype 属性,在js中所有的方法都会有一个prototype属性,这个属性就是方法的原型对象

比方说:

1
2
3
4
5
6
7
8
9
10

function Animal(){

}

Animal.prototype.run=function(){
console.log('run')
}

var cat = new Animal()

当我们声明 Animal 这个方法的时候, js引擎会赋予Animal一个原型对象,打印出来可以看到

1
2
3
4
5
6
7
8
9
10
console.log(Animal.prototype)

/**

{
constructor:这个指向 Animal这个方法,
__proto__:这个指向Object.prototype
}

**/

在我们构造实例的时候,cat的__proto__ 会指向 Animal 的 prototype, js引擎 在访问对象的属性的时候会先查看当前对象是否这个属性,如果没有则会查看改对象的 __proto__ 是否有这个属性,访问会沿着原型链访问下去直到找到属性或者 __proto__为null为止。

如何实现继承

这里只讲通用的一种继承的写法

这是父类:

1
2
3
4
5
6
7
function Animal(name){
this.name = name;
}

Animal.prototype.run=function(){
console.log(this.name + ' is run')
}

子类的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Cat(name){

// 这里通过调用父类并把this绑定到父类上
Animal.call(this,name)
}

(()=>{
// 这里其实本质要做的就是让Cat.prototype.__proto__=Animal.prototype
// Cat.prototype =Object.create(Animal.prototype) 相当于做了如下的工作
// var a = {};a.__proto__=Animal.prototype;
// Cat.prototype = a;

Cat.prototype = Object.create(Animal.prototype)
Cat.prototype.constructor = Cat
})()

ES6 的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Class Animal{
constructor(name){
this.name=name
}

run(){
console.log(this.name + ' is run')
}
}

Class Cat extends Animal{
constructor(name){
// ES6要求子类构造函数中必须要调用这个方法,这个方式是用来调用父类的constructor的
super(name)
}
}

其实es6的写法本质上上面的语法糖,使用之后代码对代码的可读性有了明显的提高,但是我们还是需要知道JS继承的原理是怎样的。