js几种继承方式

注意:

1,constructor总是指向类的构造函数

2,__proto__指向父类的原型对象

1,原型链继承


function Father(name){

    this.name=name;

    this.color=['red','blue'];

}

Father.prototype.getName=function(){

    console.log(this.name)

}

function Child(){}

Child.prototype = new Father();

Child.prototype.constructor = Child;

var son1 = new Child('ming');

var son2 = new Child('wei');

son1.color.push('white');

son2.color; //['red','blue','white']

缺点:对于复杂数据类型color,多个实例对引用的操作会被篡改

2,借用构造函数继承


function Father(name){

    this.name=name;

}

Father.prototype.getName=function(){

    console.log(this.name)

}

function Son(name){

    Father.apply(this,arguments);

}

var son = new Son('ming');

console.log(son.getName())  // son.getName is not a function

缺点:父类原型链上的属性和方法无法获取

3,组合继承(伪经典继承)


function Father(name) {

    this.name = name;

    this.color=['red','blue'];

}

Father.prototype.getName = function() {

    console.log(this.name)

}

function Child(name) {

    Father.apply(this, arguments);

}

Child.prototype = new Father();

Child.prototype.constructor = Child;

var son = new Child('ming');

console.log(son.color);

son.color.push('white') 

var son2 = new Child('wei');

console.log(son2.color)    //['red','blue']

基本ok,除了new Father()那个地方会多写一遍属性和方法,差不多还行

4,原型式继承(道爷-2006)


var Person={

    name:'ming',

    color:['red','blue']

}

function object(obj){

    function F(){};

    F.prototype=obj;

    return new F();

}

var son1 = object(Person);

var son2 = object(Person);

son1.name='wei';

son1.color = ['white'];

console.log(son2.color);  // ['red','blue','white']

缺点很明显:

1,原型实例指向的引用相同,可能存在篡改

2,不能传递参数

另:object方法已经由Object.create()实现

5,寄生式继承,(道爷有点皮)

创建一个函数,在内部构造新的属性和方法,以增强对象(原型式继承的加强版)


var Person = {

    name: 'ming',

    color: ['red', 'blue']

}

function object(obj) {

  function F() {};

      F.prototype = obj;

      return new F();

  }

  function createSon(obj){

      var son = object(obj);

      console.log(son)

      son.say=function(){

      console.log('Hello,'+this.name)

    }

 return son;

}

var son1 = createSon(Person);

console.log(son1.name)

缺点很明显:

1,原型实例指向的引用相同,可能存在篡改

2,不能传递参数

6,寄生组合式继承(借用构造函数继承+寄生式继承)


function object(obj) {

    function F() {};

    F.prototype = obj;

    return new F();

}

function inheritPerson(Person,Son){

    var pro = object(Person.prototype);

    Son.prototype.constructor=Son;

    Son.prototype = pro;

}

function Person(name){

    this.name=name;

    this.color=['red','blue'];

}

Person.prototype.say=function(){

    console.log('Hello,'+this.name)

}

function Son(name,age){

    Person.call(this,name);

    this.age = age;

}

inheritPerson(Person,Son);

Son.prototype.getAge=function(){

    console.log(this.age);

}

var child1 = new Son('ming',20);

var child2 = new Son('wei',30);

child1.say()  // ming

child1.color.push('white');

console.log(child2.color)  //['red','blue']

这个是es5的终极解决方案

7,混入方式继承多个对象


function Father1(name){this.name=name}

function Father2(age){this.age=age}

function Son(name,age){

    Father1.call(this,name);

    Father2.call(this,age);

}

Son.prototype = Object.create(Father1.prototype);

Object.assign(Father1.prototype,Father2.prototype);

Son.prototype.constructor=Son;

var son1 = new Son('ming',20);

console.log(son1)

这个实际上是寄生组合式继承的加强版

8.class继承


class Person{

  constructor(name){

  this.name=name

  }

  say(){

  console.log(this.name)

  }

}

class Son extends Person{

  constructor(name){

    super(name)

    }

}

使用babel转义为es5之后:


"use strict";

function _inheritsLoose(subClass, superClass) {

    subClass.prototype = Object.create(superClass.prototype); 

    subClass.prototype.constructor = subClass;

    subClass.__proto__ = superClass;

}

var Person =

function () {

  function Person(name) {

    this.name = name;

  }

  var _proto = Person.prototype;

  _proto.say = function say() {

    console.log(this.name);

  };

  return Person;

}();

var Son =

function (_Person) {

  _inheritsLoose(Son, _Person);

  function Son(name) {

    return _Person.call(this, name) || this;

  }

  return Son;

}(Person);

总结:

1,类方法调用时不会变量提升:

var p = new P(); // Cannot access 'P' before initialization

class P{}

2,es6的继承,实际上是先创建父类的实例对象this,然后再用子类的构造函数修改this,因此在子类的contructor中要调用父类的super(),否则要报错。

参考资料:

1,https://juejin.im/post/5bcb2e295188255c55472db0#heading-0

2,https://www.liaoxuefeng.com/wiki/1022910821149312/1023021997355072

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • (注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!)(注2:更多内容请查看我的目录。) ...
    love丁酥酥阅读 5,144评论 4 8
  • js 实现继承的方式有: 原型链继承; 构造函数继承; 组合继承(原型链继承 + 构造函数继承)(最常用);(原型...
    黎贝卡beka阅读 5,330评论 0 0
  • 前言 上篇文章详细解析了原型、原型链的相关知识点,这篇文章讲的是和原型链有密切关联的继承,它是前端基础中很重要的一...
    OBKoro1阅读 4,853评论 0 0
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 5,276评论 3 12
  • js的继承有6种方式,大致总结一下它们各自的优缺点,以及它们之间的关系。 1.原型链 js的继承机制不同于传统的面...
    XiaoAM阅读 3,499评论 0 1