今天我们讨论一下常用的几种继承方法:

首先我们创建一个动物函数Animal:
  function Animal () {
    this.species = '动物'
  }
再写准备名叫猫咪的函数Cat:
   function Cat (name, color) {
    this.name = name
    this.color = color
  }
最终目的是让Cat继承Animal的属性{spacies : "动物"}; 方法如下:
 
一、 构造函数绑定

首先解释下apply方法:
官方定义: apply方法能劫持另外一个对象的方法,继承另外一个对象的属性.其中第一个参数是用来代替原函数的this,第二个参数是一个数组集合;
说人话就是在CatA里调用Animal方法,同时改变Animal方法的this指向:
Animal.apply(this, arguments)
  function Animal () {
    this.species = '动物'
  }   function CatA (name, color) {
    Animal.apply(this, arguments)
    this.name = name
    this.color = color
  }   // 打印结果如下:
  console.log(new CatA('mimiA', 'red')) // CatA {species: "动物", name: "mimiA", color: "red"}
apply方法是最简单也是最最基础的一种'继承'方式;
 
二、prototype模式-new Animal()赋值给Cat
父函数实例一下赋值给子函数:
CatB.prototype = new Animal();
这样写有一个小坑, 就是子函数的构造函数会被父函数覆盖, 指向了父函数; 解决方法有两个, 一个是重新修正指向, 另一个是拷贝赋值;
 function Animal () {
this.species = '动物'
} function CatB (name, color) {
this.name = name
this.color = color
} CatB.prototype = new Animal()
// 修正子函数的构造函数指向; 即: constructor: ƒ Animal -> constructor: ƒ CatB
CatB.prototype.constructor = CatB
// 打印结果如下:
console.log(new CatB('mimiB', 'red')) // CatB {name: "mimiB", color: "red"} && {CatB.prototype.species: "动物"}
说到原型继承, 为什么我们要这么做呢, 举个简单的栗子:
我们写两个猫咪的函数, 如果不继承'species'属性, 我们就需要写两遍, 这样会出现冗余
function CatAA (name, color) {
  this.name = name
this.color = color
  this.species = '动物' // 公共属性
}
function CatBB (name, color) {
  this.name = name
this.color = color
  this.species = '动物' // 公共属性
}
这个就像是标签里的class和style一样, 如果同一个样式多次出现, 我们就该考虑把他们提取出来, 放在class里; 
关于构造函数和拷贝赋值, 我会在接下来两期单做说明 ( Link ), 在此不具;

三、 prototype模式-Animal原型赋值给Cat原型 原型链之间赋值:
CatC.prototype = Animal.prototype
这样改变原型属性,CatC原型的构造函数同样也会被Animal覆盖掉!
需要修正Cat构造函数指向:
CatC.prototype.constructor = CatC

function Animal () {}
Animal.prototype.species = "动物" function CatC (name, color) {
  this.name = name
  this.color = color
}
CatC.prototype = Animal.prototype
CatC.prototype.constructor = CatC // 修正子函数的构造函数指向! // 注意此时出现一个隐患: 由于CatC和Animal的原型引用地址相同, 此时Animal原型的构造函数也被CatC污染了
console.log(new CatC('mimiC', 'red')) // CatC {name: 'miniC', color: 'red'} && {CatC.prototype.species: "动物"}
console.log(new Animal()) // Animal.prototype.constructor: CatC

   

这里我们对上面的方法进行优化: 利用空对象作为中介,避免改变父级构造函数

他其实是方法二和方法三的组合:
首先写一个用来过渡的空函数F
function F () {}
先把Animal原型赋值给F, 因为F是一个无用的且几乎不占内存的空函数
所以无须担心构造指向改变等问题
F.prototype = Animal.prototype
然后让Cat继承new F()
CatD.prototype = new F()

function Animal () {}
Animal.prototype.species = "动物" function CatD (name, color) {
this.name = name
this.color = color
} function F () {} // 写一个用来过渡的空函数F
F.prototype = Animal.prototype CatD.prototype = new F() // 此时的F角色是: 具有Animal原型的空函数
CatD.prototype.constructor = CatD // 修正子函数构造函数指向 console.log(new CatD('mimiD', 'red')) //CatD.prototype.prototype.species: "动物"


四、 拷贝继承

我们可以开一个for in循环对原型上的属性进行拷贝赋值
其中原型上的constructor是私有属性, 不会被遍历到的

function Animal () {}
Animal.prototype.species = "动物" function CatE (name, color) {
this.name = name
this.color = color
} // 写一个函数原型属性拷贝的方法:
function extend (src, fn) {
var s = src.prototype, f = fn.prototype
for (var i in f) {
s[i] = f[i] // 其中原型上的constructor是私有属性, 不会被遍历到的
}
}
extend(CatE, Animal) console.log(new CatE('mimiE', 'red')) // CatE {name: 'miniE', color: 'red'} && CatE.prototype.species: '动物'


五、 原型继承之ES6写法
;(function(){ // 为区分以上方法, 我把ES6写在了闭包里; 啰嗦一句,自调函数前面最好写一个分号,这样会降低多人协助报错率

    class Animal { // 定义了一个Animal的类,里面的构造函数必须写
constructor () {
this.species = '动物'
}
} class Cat extends Animal { // 定义了一个Cat类, 并且基层了上面的类Animal
constructor (name, color) {
super() // 继承类时, 需要super调用Animal
this.name = name
this.color = color
}
} console.log(new Cat('mimi','red')) // Cat {name: 'mini', color: 'red', species: '动物'} && Cat原型的构造函数是: class Cat; })()




面向对象之继承-5种JavaScript继承的方法的更多相关文章

  1. js(javascript) 继承的5种实现方式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240 js继承有5种实现方式:1.继承第一种方式:对象冒充  functio ...

  2. JavaScript强化教程——Cocos2d-JS中JavaScript继承

    javaScript语言本身没有提供类,没有其它语言的类继承机制,它的继承是通过对象的原型实现的,但这不能满足Cocos2d-JS引擎的要求.由于Cocos2d-JS引擎是从Cocos2d-x演变而来 ...

  3. [原创]JavaScript继承详解

    原文链接:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++. ...

  4. Cocos2d-JS中JavaScript继承

    JavaScript语言本身没有提供类,没有其它语言的类继承机制,它的继承是通过对象的原型实现的,但这不能满足Cocos2d-JS引擎的要求.由于Cocos2d-JS引擎是从Cocos2d-x演变而来 ...

  5. javascript面向对象系列第三篇——实现继承的3种形式

    × 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...

  6. 转载Javascript继承两种形式详解

    一直想对Javascript再次做一些总结,正好最近自己写了一个小型Js UI库,总结了一下Js的继承机制,在网上也看了一些前辈们博客里的总结,感觉分析不是特别全面.这里仅仅是把自己的学习体会拿出来分 ...

  7. 转载 Javascript继承两种形式详解

    一直想对Javascript再次做一些总结,正好最近自己写了一个小型Js UI库,总结了一下Js的继承机制,在网上也看了一些前辈们博客里的总结,感觉分析不是特别全面.这里仅仅是把自己的学习体会拿出来分 ...

  8. javascript 学习笔记之面向对象编程(二):继承&多态

    ~~接上篇~~上一篇实现了类的实现以及类成员变量和方法的定义,下面我们来了解下面向对象中两个最重要的特性:继承和多态. 继承 js中同样可以实现类的继承这一面向对象特性,继承父类中的所有成员(变量和属 ...

  9. JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

    JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...

随机推荐

  1. ffmpeg 视音处理

    (经常用到ffmpeg 做一些视频数据的处理转换等,用来做测试,今天总结了一下,参考了网上部分朋友的经验,一起在这里汇总了一下,有需要的朋友可以收藏测试一下,有问题欢迎在下面回帖交流,谢谢;by te ...

  2. stall and flow separation on airfoil or blade

    stall stall and flow separation Table of Contents 1. Stall and flow separation 1.1. Separation of Bo ...

  3. 使用NamedParameterJdbcTemplate

    [在JDBC模板中使用具名参数] 1.在经典的JDBC用法中,SQL参数使用占位符?表示,并且受到位置的限制.定为参数的问题在于,一旦参数的顺序发生变化,就必须改变参数绑定. 2.在Spring JD ...

  4. String与StringBuffer,StringBuilder

    在java中有3个类来负责字符的操作. 1.Character 是进行单个字符操作的, 2.String 对一串字符进行操作.不可变类. 3.StringBuffer 也是对一串字符进行操作,但是可变 ...

  5. 旅游电车(cogs 1175)

    [问题描述] Henryy国正致力于首都的一个旅游电车建设工程.首都有N个旅游景区.Henryy国的电车永远只沿道路规定的方向行驶,为了不使投入使用的电车有可能无法回到它的起始站,Henryy希望知道 ...

  6. [USACO07OCT]障碍路线Obstacle Course

    题目描述 Consider an N x N (1 <= N <= 100) square field composed of 1 by 1 tiles. Some of these ti ...

  7. 临时起异,要进入C++领域耍一个程序

    没办法.两周之内可以搞定吧. 就一个SESSION 0的问题. 网上有类似源码,调一下应该就可以吧..保佑顺利. 基本语法都还记得,快N年啦... #include <iostream> ...

  8. 洛谷—— P1725 琪露诺

    https://www.luogu.org/problem/show?pid=1725 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精.某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这 ...

  9. ubuntu18.04安装magento2

    magento2更新很快,使用的技术都是很前沿的,国内外的技术帖子又很少,安装的时候难免会遇到各种各样的问题.我们单位因为是外资,总部在国外,最近在自主开发电商网站,开发语言是php,首选了magen ...

  10. Android: 清除View跳转的历史记录

    Intent intent = new Intent(); intent.setClass(SetActivity.this, RegisterLoginActivity.class); intent ...