美文网首页前端开发那些事让前端飞
深入javascript之原型链继承

深入javascript之原型链继承

作者: 不止前端 | 来源:发表于2017-12-27 19:16 被阅读0次

前言

温故而知新,主要梳理js的原型链继承知识, 先看一张经典的图,很好的描述了js原型链。对对这一块还不是很了解的同学可以一起学习。

原型链

引子

在面向类的语言中,类可以被复制(或者说实例化)多次,就像用模具制作东西一样。我们在第4章中看到过,之所以会这样是因为实例化(或者继承)一个类就意味着“把类的行为复制到物理对象中”,对于每一个新实例来说都会重复这个过程。

但是在JavaScript中,并没有类似的复制机制。你不能创建一个类的多个实例,只能创建多个对象,它们[[Prototype]]关联的是同一个对象。但是在默认情况下并不会进行复制,因此这些对象之间并不会完全失去联系,它们是互相关联的。

最后我们得到了两个对象,它们之间互相关联,就是这样。我们并没有初始化一个类,实际上我们并没有从“类”中复制任何行为到一个对象中,只是让两个对象互相关联 。

js是基于原型(对象)的语言,并非面向对象,也没有类似java的类的概念,只有利用函数模拟类的实现,这就是我们常常看到的原型链继承。

传统继承

首先介绍传统实现继承的几种方法,(代码参考阮一峰和幻神的文章,写的很好,强烈建议阅读。)先构造一个父类,代码如下:

function Animal (name) {
 
  this.name = name || 'Animal';

  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
}

Animal.prototype.type = '猫科动物'

prototype继承

function Cat(){}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat; // 需要修复下原型指向
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat);
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

优点:

  • 父类新增原型方法/原型属性,子类都能访问到
  • 实现简单,方便易用

缺点:

  • 无法实现多继承
  • 创建子类实例时,无法向父类构造函数传参

构造继承


function Cat(name){
  Animal.call(this, name);
}

// Test Code
var cat = new Cat();
console.log(cat);
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

优点:

  • 创建子类实例时,可以向父类传递参数
  • 可以实现多继承(call多个父类对象)

缺点:

  • 只能继承父类的实例属性和方法,不能继承原型属性/方法
  • 创建子类实例时,无法向父类构造函数传参

拷贝继承

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  Cat.prototype.name = name || '';
}

// Test Code
var cat = new Cat();
console.log(cat);
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

优点:

  • 支持多继承

缺点:

  • 效率较低,内存占用高
  • 无法拷贝不可枚举的属性

不建议使用,推荐object.create继承

组合继承

function Cat(name){
  Animal.call(this, name);
}
Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

// Test Code
var cat = new Cat();
console.log(cat);
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

优点:

  • 构造继承优化版,弥补了无法继承父类原型属性/方法的缺点

缺点:

  • 调用了两次父类构造函数,生成了两份实例

无法拷贝不可枚举的属性实例

寄生组合继承

function Cat(name){
  Animal.call(this, name);
}
(function(){
  // 创建一个没有实例方法的类
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
  Cat.prototype.constructor = Cat; //修复
})();


// Test Code
var cat = new Cat();
console.log(cat);
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

优点:

  • 最理想的继承方法

缺点:

  • 实现复杂

ES6继承

Object.create继承

//构造父类
function Animal(name) {
  this.name = name || 'bb'
}
Animal.prototype.speak = function(name) {
  console.info('lalala, ' + name);
};

//定义子类  并创建原型
function Dog(name) {
   Animal.call(this, name); 
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

var dog = new Dog("小白")

console.log(dog)
dog.speak('小白')


create也支持多继承, 代码如下:

//再定义一个父类
function AnimalOther(age) {
  this.age = age || 1
}

function Dog(name, age) {
   Animal.call(this, name); 
   AnimalOther.call(this, age)
}

Dog.prototype = Object.create(Animal.prototype);
Object.assign(Dog.prototype, AnimalOther.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
     // do a thing
};

var dog = new Dog('name', 18)
console.log(dog) //...

class构造类

//首先声明一个父类
class Animal {
    constructor(name, type) {
        this.name = name || '小白',
        this.type = type || '柴犬'
    }
    speak () {
        console.log(this.name + '旺旺')
    }
}

// 通过extends创建子类
class Lion extends Cat {
  speak() {
    super.speak();  //通过super调用父类函数
    console.log(this.name + ' roars.');
  }
}
        

如果是使用reac框架,应该对class是非常熟悉的。

后记

这篇文章传统继承本来自己结合多篇文章总结写了例子,可惜markdown挂了,导致数据丢了😢。

闭包,this,原型链等等问题一向是前端入门的难点、重点,好记性不如烂笔头,记录下来,忘了就多看几遍,总能记住,近期在整理面试题,梳理基础,内容太多,可能不打算写下来。

如果觉得本文对你有所帮助,就star一下吧~大传送之术! 我的博客Github

相关文章

  • 原型链1:原型与原型链

    参考JavaScript深入之从原型到原型链和阮一峰的博客:Javascript继承机制的设计思想 Why??? ...

  • JavaScript深入系列的学习(一)

    JavaScript深入之从原型到原型链JavaScript深入之词法作用域和动态作用域JavaScript深入之...

  • javaScript原型链

    javaScript原型链概念JavaScript之继承(原型链)数据结构var Person = functio...

  • 原型、原型链

    (什么是原型、原型链?有什么作用) JavaScirpt深入之从原型到原型链 图解 Javascript 原型链 ...

  • 继承的多种方式和优缺点

    原文出处 JavaScript深入之继承的多种方式和优缺点JavaScript高级程序设计(第3版) 1.原型链继...

  • 【javascript】继承

    javascript只支持实现继承,而且继承主要是依靠原型链来实现的。 原型链 javascript将原型链作为实...

  • 深入javascript之原型链继承

    前言 温故而知新,主要梳理js的原型链继承知识, 先看一张经典的图,很好的描述了js原型链。对对这一块还不是很了解...

  • js原型、原型链、继承的理解

    一、原型、原型链 原型是Javascript中的继承的基础,JavaScript的继承主要依靠原型链来实现的。 原...

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • es5的部分继承以及es6的class

    一、JavaScript常用的原型继承方式 原型链继承 2,构造函数继承(对象冒充继承) 3,组合继承(原型链继承...

网友评论

    本文标题:深入javascript之原型链继承

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