美文网首页js
ES5实现继承

ES5实现继承

作者: 书虫和泰迪熊 | 来源:发表于2020-04-08 18:59 被阅读0次

原型链继承

  • 原理:将子类的原型指向父类的实例
function Animal(name) {
    this.name = name;
    this.color = ['red', 'bule'];
} 
Animal.prototype.showName = function() {
    console.log(this.name);
}
function Dog(age) {
    this.age = age;
}

Dog.prototype = new Animal();      // Dog 继承 Animal
Dog.prototype.showAge = function() {      // 注意1
    console.log(this.age)
}

// 测试
let dog1 = new Dog(12);
dog1.color.push('black');      
console.log(dog1.color);      // ["red", "bule", "black"]
dog1.showName();              // undefined
dog1.showAge();                 // 12
let dog2 = new Dog(33);
console.log(dog2.color);    // ["red", "bule", "black"]
dog2.showName();            // undefined
dog2.showAge();               // 33
  • 缺点
  1. 父类包含引用类型的原型,他会被所有实例共享;因为子类的prototype指向了父类的实例,父类实例中的 color 指针一直保持不变;
  2. 因为子类直接指定了原型,所以不能实现多继承;
  3. 创造子类实例时,无法向父类构造函数中传递参数;
  • 优点
  1. 子类可以通过原型链共享父类原型中的方法;
  • 注意
  1. 子类原型添加方法的代码必须放在子类替换原型的语句之后,不能使用对象字面量方式添加原型方法,这样会重写原型链。 而添加的方法实质是添加到了子类默认的原型中。
  2. 默认的原型:所有的类型都继承自Object,所有函数的原型对象都是Object 的实例,因此默认原型都要一个指针,指向Object.prototype。

借用构造函数继承

  • 原理:在子构造函数内部调用父类构造函数,使用call() 或 apply() 方法将 this 指向子类
function Animal(name) {
    this.name = name;
    this.color = ['red', 'bule'];
} 
Animal.prototype.showName = function() {
    console.log(this.name);
}

function Dog(age, name) {
    Animal.call(this, name);
    this.age = age;
}
Dog.prototype.showAge = function() {
    console.log(this.age)
}

// 测试
let dog = new Dog(11, 'tom');
dog.color.push('pink');
console.log(dog.name);       // tom
console.log(dog.color);        // ["red", "bule", "pink"]
dog.showName();               // Uncaught TypeError: dog.showName is not a function
dog.showAge();                  // 11
let dog2 = new Dog(22, 'jack');
console.log(dog2.name);     // jack
console.log(dog2.color);     // ["red", "bule"]
dog2.showName();            // Uncaught TypeError: dog.showName is not a function
dog2.showAge();              // 22

-缺点

  1. 子类的原型无法通过原型链到父类原型,所以子类实例无法访问父类的方法。
  • 优点
  1. 引用类型在每个子类实例中都有一个单独的副本,不会相互影响;某种形式上可以实现多继承
  2. 创建子类实例时可以向父类传参数

组合继承(是原型链继承和构造函数继承的合体)

  • 原理:将原型链继承和构造函数结合在一起;使用原型链继承实现了对原型属性和方法的继承,使用构造函数实现了对父类实例和属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
function Animal(name) {
    this.name = name;
    this.color = ['red', 'bule'];
} 
Animal.prototype.showName = function() {
    console.log(this.name);
}
function Dog(age, name) {
    Animal.call(this, age);
    this.age = age;
}
Dog.prototype = new Animal();
Dog.prototype.showAge = function() {
    console.log(this.age);
}

// 测试
let dog = new Dog(11, 'tom');
dog.color.push('pink');
console.log(dog.name);       // tom
console.log(dog.color);        // ["red", "bule", "pink"] 
dog.showName();               // tom
dog.showAge();                  // 11
let dog2 = new Dog(22, 'jack');
console.log(dog2.name);     // jack
console.log(dog2.color);     // ["red", "bule"]
dog2.showName();            // jack
dog2.showAge();               // 22
  • 缺点
  1. 会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部,占用内存
  2. 由于调用了两次父构造函数在子类实例的原型对象上会有冗余的属性存在
  • 优点
  1. 既可以继承父类原型中的方法和属性,也可以为父构造函数传递参数,保证每个子实例都有自己的属性(副本)

寄生组合继承 (业内比较的方法)

  • 原理:通过调用构造函数来继承属性,通过原型链的混成形式来继承方法;不必为了指定子类型的原型而调用超类型的构造函数。本质:就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function obj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
function inheritPrototype(sonType,farType){ 
    let prototype = obj(farType);            // 创建对象
    prototype.constructor = sonType;    // 增强对象
    sonType.prototype = prototype ;      // 指定对象
}
function Animal(name) {
    this.name = name;
    this.color = ["red","green","blue"];
}
Animal.prototype.showName = function(){
    console.log(this.name);
}
function Dog(name, age) {
    Animal.call(this, name);
}
inheritPrototype(Dog, Animal.prototype);
Dog.prototype.sayAge = function() {
    console.log(this.age);
}

// 测试
let dog = new Dog('tom', 12);
dog.color.push('pink')                
console.log(dog.color)              // ["red", "green", "blue", "pink"]
dog.showName()                      // tom
dog.showAge()                         // 12
let dog2 = new Dog('jack', 33); 
dog2.color.push('pink')             
console.log(dog2.color)             // ["red", "green", "blue", "pink"]
dog2.showName()                    // jack
dog2.showAge()                       // 33

相关文章

  • 继承:es5 vs es6

    es5如何实现继承 es5实现继承主要是通过原型来实现的 首先实现一个父类 function Father(na...

  • ES5和ES6中继承的不同之处

    ES5和ES6中继承的不同之处 1、JS中视没有继承的,不过可以通过构造函数或是原型等实现继承,ES5实现继承的方...

  • 如何用es5实现继承

    extend (继承) 如何用 es5 实现继承 测试 结果 原文链接

  • 前端常见面试题(八)@郝晨光

    ES5/ES6 的继承除了写法以外还有什么区别? ES5寄生组合式继承(只是列举一个方法,ES5继承还有很多实现方...

  • 用ES5和ES6实现继承

    ES5 prototype实现继承 ES6 写法

  • Class 的继承 extend继承 es6继承基本用法

    Class继承基本用法 Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,...

  • 继承

    原型链继承 许多OO语言都支持两种继承方式接口继承和实现继承,ES5只有实现继承,且主要依靠原型链继承。 那我们先...

  • 浅谈JavaScript原型、原型链的概念与继承的实现原理

    关于js对象的继承,es5和es6提供了两种不同的继承机制。es5通过修改原型链的方式实现继承,由此可见继承与原型...

  • 面向对象类

    类与实例 类的声明 ES5 ES6 生成实例 类与继承 如何实现继承 继承的几种方式 原型链是实现继承的主要方法 ...

  • Class 的继承

    一、简介 Class 可以通过 extends 关键字实现继承,这比 ES5 通过修改原型链实现继承更加清晰和方便...

网友评论

    本文标题:ES5实现继承

    本文链接:https://www.haomeiwen.com/subject/rlmnphtx.html