继承属性

JavaScript对象是一个动态的属性“包”,每个对象都有一个指向一个原型对象的链,当我们访问一个对象的属性时,他不仅会在该对象上搜索,还会搜寻该对象的原型,以及该对象的原型的原型,这样依次向上寻找,直到找到一个名字匹配的属性或者到达原型链的末端(null)

继承的实现方法

先实现一个父级函数

function Person(name, age){
    this.name = name || "Person";
    this.age = age||'18';
    //实例方法
    this.say = function(){
        console.log(this.name)
    }
}

//原型方法
Person.prototype.eat=function(food){
    console.log("我是" + this.name + ",我正在吃:" + food)
}

原型继承

实现:将父函数的实例赋值给子函数的原型

//创建子类-学生
function Student(){}
Student.prototype = new Person();

var stu = new Student();
console.log(stu.name);//Person
stu.eat("apple");//我是Person,我正在吃:apple

console.log(stu instanceof Student);//true
console.log(stu instanceof Person);//true

特点:

  • 父级函数原型发生变化时,子类都能访问到
  • 简单,易于实现

缺点:

  • 想要为子类新增属性和方法,必须在完成赋值父函数的实例之后再执行
  • 无法实现多继承(继承多个父类)
  • 创建子类实例时,无法向父类构造函数传参
  • 父级函数原型中所有属性都被所有实例共享

借用构造函数继承

原理:使用call、apply改变父函数内this,指向子函数,用父级构造函数来增强子类实例

function Student(name, grade){
    Person.call(this, name);
    this.grade = grade;
    this.say = function(){
        console.log(`我是${this.name},现在${this.grade}年级`)
    }
}
var stu = new Student('tom', '3');

console.log(stu.name);//tom
stu.say();//我是tom,现在3年级
console.log(stu instanceof Person);//false
console.log(stu instanceof Student);//true

特点:

  • 可以向父级函数中传递参数
  • 可以实现多继承
  • 解决了1中子类实例共享所有父类原型属性的问题

缺点:

  • 只能继承实例属性和方法,不能继承原型属性方法
  • 实例只是子类的实例,不是父类的实例

组合继承

原理:结合1和2

function Student(name, grade){
    Person.call(this, name);
    this.grade = grade;
    this.say = function(){
        console.log(`我是${this.name},现在${this.grade}年级`)
    }
}

Student.prototype = new Person();

var stu = new Student('tom', 3);

stu.say();//我是tom,现在3年级
stu.eat('apple');//我是tom,我正在吃:apple

console.log(stu instanceof Student);//true
console.log(stu instanceof Person);//true

特点:

  • 既可以继承实例方法和属性,也可以继承原型方法和属性
  • 既是子类的实例,也是父类的实例

缺点:

  • 调用了两次父类构造函数,生成了两份父类实例属性,父类实例属性和方法也在子类原型中

寄生方式继承

寄生组合继承

原理:通过寄生方式,去掉父类实例属性,这样就不会初始化两次父类的实例方法/属性,避免了组合方式继承的缺点

function Super(){};
Super.prototype = Person.prototype;

function Student(name, grade){
    Person.call(this, name);
    this.grade = grade;
    this.say = function(){
        console.log(`我是${this.name},现在${this.grade}年级`)
    }
}

Student.prototype = new Super();

var stu = new Student('tom', 3);

stu.say();//我是tom,现在3年级
stu.eat('apple');//我是tom,我正在吃:apple

console.log(stu instanceof Student);//true
console.log(stu instanceof Person);//true