js的继承

137 阅读2分钟

一,原型的继承

javascript中的继承是通过原型链来体现的。先看几句代码

function Foo() {
    var f1 = new Foo();
    
    f1.a = 10;
    
    Foo.prototype.a = 100;
    Foo.prototype.b = 200;
    
    console.log(f1.a);  //10
    console.log(f1.b);  //200
   }

以上代码中,f1是Foo函数new出来的对象,f1.a是f1对象的基本属性,f1.b是怎么来的呢?——从Foo.prototype得来,因为f1.__proto__指向的是Foo.prototype

访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。

看图:

f1本身没有hasOwnProperty方法,这个hasOwnProperty方法是从Object.prototype中来的

对象的原型链是沿着__proto__这条线走的,因此在查找f1.hasOwnProperty属性时,就会顺着原型链一直查找到Object.prototype。

由于所有的对象的原型链都会找到Object.prototype,因此所有的对象都会有Object.prototype的方法。这就是所谓的“继承”。

我们都知道每个函数都有call,apply方法,都有length,arguments,caller等属性。为什么每个函数都有?这肯定是“继承”的。函数由Function函数创建,因此继承的Function.prototype中的方法。

二、Class 的继承

   class Person {
     constructor(name, age){
      this.name = name
      this.age = age
  }
     sayHi(){
      console.log('你好,我是'+this.name)
  }
}

Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class PrimaryPerson extends Person{  //=>extends 类似实现原型继承
    constructor(name, age) {
        super(name);  //// 调用父类的constructor(name)。
        this.age = age;
    }

    myName() {
        console.log('你好,我叫jack ' + this.age);
    }
}

注意PrimaryStudent的定义也是class关键字实现的,而extends则表示原型链对象来自Person。子类的构造函数可能会与父类不太相同,例如,PrimaryPerson需要name和age两个参数,并且需要通过super(name)来调用父类的构造函数,否则父类的name属性无法正常初始化。

PrimaryPerson已经自动获得了父类Person的sayHi方法,我们又在子类中定义了新的myName方法。

ES6引入的class和原有的JavaScript原型继承有什么区别呢?实际上它们没有任何区别,class的作用就是让JavaScript引擎去实现原来需要我们自己编写的原型链代码。简而言之,用class的好处就是极大地简化了原型链代码。

目前,主流浏览器都不支持ES6的class。