菜单

于本质认识JavaScript的原型继承和类继承

2018年11月16日 - JavaScript

自从实质认识JavaScript的原型继承和类继承

2016/04/06 · JavaScript
· 1 评论 ·
继承

原文出处:
十年踪迹(@十年踪迹)   

JavaScript发展到今日,和其余语言不雷同的一个特点是,有多种多样的“继承方式”,或者小准确一点的传道,叫做有丰富多彩的因prototype的模拟类继承实现方式。

于ES6之前,JavaScript没有接近继承的概念,因此使用者为了代码复用的目的,只能参考其他语言的“继承”,然后用prototype来效仿出相应之兑现,于是产生矣各种继承方式,比如《JavaScript高级程序设计》上说的 原型链,借用构造函数,组合继承,原型式继承,寄生式继承,寄生组合式继承 等等

这就是说多延续方式,让第一次接触就无异片的伴侣们良心小崩溃。然而,之所以发生那么多延续方式,其实要以“模拟”二配,因为我们当游说继续的时光不是以研究prototype本身,而是于用prototype和JS特性来拟别的语言的好像继承。

咱俩今天撇下这些项目层出不穷的继续方式,来拘禁一下prototype的精神与咱们为何要模拟类继承。

笔者:十年踪迹
章源自:https://www.h5jun.com/post/inherits.html

原型继承

“原型”
这个词本身源自心理学,指神话、宗教、梦境、幻想、文学中不断重复出现的意境,它源自民族记忆与原有经验的官无意识。

之所以,原型是一样栽浮泛,代表物表象之下的联络,用简短的语句来说,就是原型描述事物和物之间的相似性.

设想一个小朋友如何认知是世界:

当孩子没见了虎的时刻,大人可能会见使他,老虎呀,就像是同样一味怪猫。如果这孩子刚刚常常同左邻右舍家的猫咪玩耍,那么它们免用去动物园见到真实的虎,就能够想象发生老虎大概是添加什么则。

图片 1

斯故事发生只更简明的表述,叫做“照猫画虎”。如果我们用JavaScript的原型来讲述其,就是:

JavaScript

function Tiger(){ //… } Tiger.prototype = new Cat();
//老虎的原型是同样单独猫

1
2
3
4
5
function Tiger(){
    //…
}
 
Tiger.prototype = new Cat(); //老虎的原型是一只猫

死醒目,“照猫画虎”(或者转“照虎画猫”,也可,取决孩子为事先认识老虎或先认识猫)是千篇一律种认知模式,它被人类儿童不需以脑际里再次完全构建平仅虎的整消息,而足经过它们熟悉的猫咪的“复用”得到老虎的绝大多数信,接下去她独自需要去交动物园,去考察老虎及猫咪的例外部分,就得是认知什么是老虎了。这段话用JavaScript可以描述如下:

JavaScript

function Cat(){ } //小猫喵喵叫 Cat.prototype.say = function(){ return
“喵”; } //小猫会爬树 Cat.prototype.climb = function(){ return
“我会爬树”; } function Tiger(){ } Tiger.prototype = new Cat();
//老虎的喊叫声和小猫不同,但老虎为会爬树 Tiger.prototype.say = function(){
return “嗷”; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Cat(){
 
}
//小猫喵喵叫
Cat.prototype.say = function(){    
  return "喵";
}
//小猫会爬树
Cat.prototype.climb = function(){
  return "我会爬树";
}
 
function Tiger(){
 
}
Tiger.prototype = new Cat();
 
//老虎的叫声和小猫不同,但老虎也会爬树
Tiger.prototype.say = function(){
  return "嗷";
}

故此,原型可以通过讲述两个东西之间的相似关系来复用代码,我们好将这种复用代码的模式称为原型继承。

JavaScript发展到今天,和任何语言不平等的一个特性是,有各种各样的“继承方式”,或者稍微准确一点之传道,叫做有各式各样的依据prototype的模拟类继承贯彻方式。

类继承

差一点年过后,当时底小家伙长大了,随着它的学识结构不断丰富,她认识世界之主意呢时有发生了一部分变通,她学会了最为多之动物,有喵喵叫的猫,百兽之王狮子,优雅的森林的君老虎,还有豺狼、大象之类。

此刻,单纯的相似性的回味方式就死少给下于这么长的文化内容里,更加谨慎的体会方式——分类,开始为再度累利用。

图片 2

这儿当年之少儿会说,猫和狗都是动物,如果其碰巧学习之是明媒正娶的生物学,她也许还会说猫和狗都是脊索门哺乳纲,于是,相似性被“类”这无异种更胜品位之纸上谈兵表达取代,我们用JavaScript来叙述:

JavaScript

class Animal{ eat(){} say(){} climb(){} … } class Cat extends Animal{
say(){return “喵”} } class Dog extends Animal{ say(){return “汪”} }

1
2
3
4
5
6
7
8
9
10
11
12
class Animal{
    eat(){}
    say(){}
    climb(){}
    …
}
class Cat extends Animal{
    say(){return "喵"}
}
class Dog extends Animal{
    say(){return "汪"}
}

每当ES6之前,JavaScript没有像样继承的概念,因此使用者为了代码复用,只能参考其他语言的“继承”,然后据此prototype来效仿出相应的贯彻,于是产生矣各种继承方式,比如《JavaScript高级程序设计》上说的
原型链,借用构造函数,组合继承,原型式继承,寄生式继承,寄生组合式继承
等等。

原型继承和类继承

用,原型继承和类继承是简单种植认知模式,本质上都是为了架空(复用代码)。相对于类,原型更初级且又灵活。因此当一个网外没有最多干的东西的时刻,用原型明显比用类更灵活轻便。

原型继承的便捷性表现于系受目标比较少的下,原型继承不待组织额外的抽象类和接口就可以实现复用。(如网里独自生猫及狗两种植动物吧,没必要更为它们组织一个空洞的“动物类”)

原型继承的八面玲珑还显现于复用模式更灵活。由于原型和类的模式不均等,所以针对复用的判断标准吧即不相同,例如将一个红皮球当做一个阳光的原型,当然是可的(反过来也推行),但肯定不可知以“恒星类”当做太阳及红球的公物父类(倒是可以为此“球体”这个类似作为它们的共用父类)。

既是原型本质上是相同栽认知模式可就此来复用代码,那咱们为何还要模仿“类继承”呢?在及时间我们就得看原型继承来什么问题——

这就是说基本上累方式,让第一不行沾就无异片的同伙等良心小崩溃。然而,之所以发生那么多延续方式,其实要以“模拟”二配。因为我们当游说继承的时光,不是在研prototype本身,而是于于是prototype和JS特性来模拟别的语言的类继承

原型继承的题目

由于我们才前举例的猫及老虎的构造器没有参数,因此大家格外可能无发现问题,现在我们试验一个起参数构造器的原型继承:

JavaScript

function Vector2D(x, y){ this.x = x; this.y = y; }
Vector2D.prototype.length = function(){ return Math.sqrt(this.x *
this.x + this.y * this.y); } function Vector3D(x, y, z){
Vector2D.call(this, x, y); this.z = z; } Vector3D.prototype = new
Vector2D(); Vector3D.prototype.length = function(){ return
Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); } var
p = new Vector3D(1, 2, 3); console.log(p.x, p.y, p.z, p.length(), p
instanceof Vector2D);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Vector2D(x, y){
  this.x = x;
  this.y = y;
}
Vector2D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y);
}
 
function Vector3D(x, y, z){
  Vector2D.call(this, x, y);
  this.z = z;
}
Vector3D.prototype = new Vector2D();
 
Vector3D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
 
var p = new Vector3D(1, 2, 3);
console.log(p.x, p.y, p.z, p.length(), p instanceof Vector2D);

方立段代码里面我们看出我们为此 Vector2D 的实例作为 Vector3D 的原型,在
Vector3D 的构造器里面我们还可以调用 Vector2D 的布局器来初始化 x、y。

不过,如果认真钻研方面的代码,会发现一个聊题目,在中等描述原型继承的时:

JavaScript

Vector3D.prototype = new Vector2D();

1
Vector3D.prototype = new Vector2D();

咱实在不管参数地调用了同样次 Vector2D 的构造器!

当下无异浅调用是勿必要之,而且,因为我们的 Vector2D
的构造器足够简单又没有副作用,所以我们这次无谓的调用除了聊小消耗了性外,并无见面带最好严重的问题。

但每当实际项目被,我们发出几组件的构造器比较复杂,或者操作DOM,那么这种状态下无谓多调用同样次等构造器,显然是有或引致深重问题之。

乃,我们得想方法克服这同一次剩余的构造器调用,而明确,我们发现我们好免必要就无异于浅剩余的调用:

JavaScript

function createObjWithoutConstructor(Class){ function T(){}; T.prototype
= Class.prototype; return new T(); }

1
2
3
4
5
function createObjWithoutConstructor(Class){
    function T(){};
    T.prototype = Class.prototype;
    return new T();    
}

面的代码中,我们通过创办一个拖欠的构造器T,引用父类Class的prototype,然后回new
T(
),来都行地避开Class构造器的履。这样,我们的确可绕开父类构造器的调用,并以她的调用时机延迟到子类实例化的时节(本来也应有如此才合理)。

JavaScript

function Vector2D(x, y){ this.x = x; this.y = y; }
Vector2D.prototype.length = function(){ return Math.sqrt(this.x *
this.x + this.y * this.y); } function Vector3D(x, y, z){
Vector2D.call(this, x, y); this.z = z; } Vector3D.prototype =
createObjWithoutConstructor(Vector2D); Vector3D.prototype.length =
function(){ return Math.sqrt(this.x * this.x + this.y * this.y +
this.z * this.z); } var p = new Vector3D(1, 2, 3); console.log(p.x,
p.y, p.z, p.length(), p instanceof Vector2D);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Vector2D(x, y){
  this.x = x;
  this.y = y;
}
Vector2D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y);
}
 
function Vector3D(x, y, z){
  Vector2D.call(this, x, y);
  this.z = z;
}
Vector3D.prototype = createObjWithoutConstructor(Vector2D);
 
Vector3D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
 
var p = new Vector3D(1, 2, 3);
console.log(p.x, p.y, p.z, p.length(), p instanceof Vector2D);

如此,我们缓解了父类构造器延迟构造的题目以后,原型继承就比适用了,并且这样概括处理以后,使用起来还未会见潜移默化
instanceof 返回值的科学,这是和其它模拟方式对比最要命之补。

咱们现委这些品种层出不穷的接续方式,来拘禁一下prototype的真相和咱们为何而模拟类继承。

模拟类继承

说到底,我们采用这个原理还得兑现比全面的类继承:

JavaScript

(function(global){“use strict” Function.prototype.extend =
function(props){ var Super = this; //父类构造函数 //父类原型 var TmpCls
= function(){ } TmpCls.prototype = Super.prototype; var superProto = new
TmpCls(); //父类构造器wrapper var _super = function(){ return
Super.apply(this, arguments); } var Cls = function(){
if(props.constructor){ //执行构造函数 props.constructor.apply(this,
arguments); } //绑定 this._super 的方法 for(var i in Super.prototype){
_super[i] = Super.prototype[i].bind(this); } } Cls.prototype =
superProto; Cls.prototype._super = _super; //复制属性 for(var i in
props){ if(i !== “constructor”){ Cls.prototype[i] = props[i]; } }
return Cls; } function Animal(name){ this.name = name; }
Animal.prototype.sayName = function(){ console.log(“My name is
“+this.name); } var Programmer = Animal.extend({ constructor:
function(name){ this._super(name); }, sayName: function(){
this._super.sayName(name); }, program: function(){ console.log(“I\”m
coding…”); } }); //测试我们的类 var animal = new Animal(“dummy”),
akira = new Programmer(“akira”); animal.sayName();//输出 ‘My name is
dummy’ akira.sayName();//输出 ‘My name is akira’ akira.program();//输出
‘I”m coding…’ })(this);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
(function(global){"use strict"
 
  Function.prototype.extend = function(props){
    var Super = this; //父类构造函数
 
    //父类原型
    var TmpCls = function(){
 
    }
    TmpCls.prototype = Super.prototype;
 
    var superProto = new TmpCls();
 
    //父类构造器wrapper
    var _super = function(){
      return Super.apply(this, arguments);
    }
 
    var Cls = function(){
      if(props.constructor){
        //执行构造函数
        props.constructor.apply(this, arguments);
      }
      //绑定 this._super 的方法
      for(var i in Super.prototype){
        _super[i] = Super.prototype[i].bind(this);
      }
    }
    Cls.prototype = superProto;
    Cls.prototype._super = _super;
 
    //复制属性
    for(var i in props){
      if(i !== "constructor"){
        Cls.prototype[i] = props[i];
      }
    }  
 
    return Cls;
  }
 
  function Animal(name){
    this.name = name;
  }
 
  Animal.prototype.sayName = function(){
    console.log("My name is "+this.name);
  }
 
  var Programmer = Animal.extend({
    constructor: function(name){
      this._super(name);
    },
    sayName: function(){
      this._super.sayName(name);
    },
    program: function(){
      console.log("I\"m coding…");
    }
  });
  //测试我们的类
  var animal = new Animal("dummy"),
      akira = new Programmer("akira");
  animal.sayName();//输出 ‘My name is dummy’
  akira.sayName();//输出 ‘My name is akira’
  akira.program();//输出 ‘I"m coding…’
 
})(this);

好比一下ES6的切近继承:

JavaScript

(function(global){“use strict” //类的定义 class Animal {
//ES6遇最新组织器 constructor(name) { this.name = name; } //实例方法
sayName() { console.log(“My name is “+this.name); } } //类的持续 class
Programmer extends Animal { constructor(name) {
//直接调用父类构造器进行初始化 super(name); } sayName(){
super.sayName(); } program() { console.log(“I\”m coding…”); } }
//测试我们的类 var animal = new Animal(“dummy”), akira = new
Programmer(“akira”); animal.sayName();//输出 ‘My name is dummy’
akira.sayName();//输出 ‘My name is akira’ akira.program();//输出 ‘I”m
coding…’ })(this);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(function(global){"use strict"
 
  //类的定义
  class Animal {
    //ES6中新型构造器
      constructor(name) {
          this.name = name;
      }
      //实例方法
      sayName() {
          console.log("My name is "+this.name);
      }
  }
 
  //类的继承
  class Programmer extends Animal {
      constructor(name) {
        //直接调用父类构造器进行初始化
          super(name);
      }
      sayName(){
          super.sayName();
      }
      program() {
          console.log("I\"m coding…");
      }
  }
  //测试我们的类
  var animal = new Animal("dummy"),
      akira = new Programmer("akira");
  animal.sayName();//输出 ‘My name is dummy’
  akira.sayName();//输出 ‘My name is akira’
  akira.program();//输出 ‘I"m coding…’
 
})(this);

原型继承

“原型”
这个词本身源自心理学,指神话、宗教、梦境、幻想、文学中穿梭重复出现的意境,它源自民族记忆与原经验的国有无意识。

用,原型是平等种浮泛,代表物表象之下的联系。用简单的言辞来说,就是原型讲述事物和物之间的相似性

想象一个小如何认知是世界:

当儿童没见了於的时,大人可能会见令他,老虎呀,就比如是一致单纯大猫。如果这孩子正常常与邻家家的猫咪玩耍,那么其未用去动物园见到真实的大虫,就能够想象发生老虎大概是加上什么法。

图片 3

本条故事来个重复简单的表达,叫做“照猫画虎”。如果我们用JavaScript的原型来描述她,就是:

function Tiger(){
    //...
}

Tiger.prototype = new Cat(); //老虎的原型是一只猫

特别明白,“照猫画虎”(或者转“照虎画猫”,也足以,取决孩子叫事先认识老虎或事先认识猫)是一模一样种认知模式,它给人类儿童不待以脑际里还完全构建平一味虎的百分之百音,而得通过其熟悉的猫咪“复用”得到老虎的大多数信,接下她只需要去到动物园,去考察老虎和猫咪的例外部分,就得正确认知嘿是老虎了。这段话用JavaScript可以描述如下:

function Cat(){

}
//小猫喵喵叫
Cat.prototype.say = function(){    
  return "喵";
}
//小猫会爬树
Cat.prototype.climb = function(){
  return "我会爬树";
}

function Tiger(){

}
Tiger.prototype = new Cat();

//老虎的叫声和小猫不同,但老虎也会爬树
Tiger.prototype.say = function(){
  return "嗷";
}

因而,原型可以经讲述两独东西之间的一般关系来复用代码,我们可把这种复用代码的模式称为原型继承

总结

原型继承和类继承是片种植不同的体会模式,原型继承在靶非是多多益善底略利用模型里比类继承更加灵敏方便。然而JavaScript的原型继承在语法上发出一个组织器额外调用的题材,我们设透过
createObjWithoutConstructor 来延迟构造器的调用,就能够迎刃而解者问题。

3 赞 8 收藏 1
评论

图片 4

类继承

几年以后,当时的小子长大了,随着它的学问结构不断丰富,她认识世界之法也出了一些转移。她学会了极致多之动物,有喵喵叫的猫,百兽之王狮子,优雅的树丛的君老虎,还有豺狼、大象之类。

这儿,单纯的相似性的体会方式已特别少让应用以如此丰富的学问内容里,更加严谨的咀嚼方式——分类,开始为再度累利用。

图片 5

此时当年的儿童会说,猫和狗都是动物。如果其刚刚学习标准是生物学,她可能还会见说猫和狗都是脊索门哺乳纲。于是,相似性被“类”马上同样种更胜品位的空洞表达取代,我们用JavaScript来叙述:

class Animal{
    eat(){}
    say(){}
    climb(){}
    ...
}
class Cat extends Animal{
    say(){return "喵"}
}
class Dog extends Animal{
    say(){return "汪"}
}

原型继承和类继承

所以,原型继承类继承大凡鲜种植认知模式,本质上都是为架空(复用代码)。相对于类,原型更初级且再度灵活。因此当一个系统内无最多干的东西之早晚,用原型明显比用类更灵活方便。

原型继承的便捷性表现在系面临目标比较少之时段,原型继承不待结构额外的抽象类和接口就足以兑现复用。(如网里仅来猫和狗两栽动物来说,没必要更为它组织一个浮泛的“动物看似”)

原型继承的油滑还显现于复用模式更加灵活。由于原型和类的模式不一致,所以本着复用的判断标准吧就不同等,例如将一个红色皮球当做一个阳光的原型,当然是可以的(反过来也实践),但肯定不克以“恒星类”当做太阳及红球的公共父类(倒是可以为此“球体”这个看似作为它们的集体父类)。

既是原型本质上是平等种认知模式可就此来复用代码,那我们为什么还要模仿“类继承”呢?在当时中间,我们就是得看原型继承来什么问题:

原型继承的题目

是因为我们刚刚前举例的猫和老虎的构造器没有参数,因此大家老可能无发现题目,现在咱们试验一个产生参数构造器的原型继承:

function Vector2D(x, y){
  this.x = x;
  this.y = y;
}
Vector2D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y);
}

function Vector3D(x, y, z){
  Vector2D.call(this, x, y);
  this.z = z;
}
Vector3D.prototype = new Vector2D();

Vector3D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}

var p = new Vector3D(1, 2, 3);
console.log(p.x, p.y, p.z, p.length(), p instanceof Vector2D);

上面这段代码里面我们看出我们因此 Vector2D 的实例作为 Vector3D 的原型,在
Vector3D 的构造器里面我们还可调用 Vector2D 的布局器来初始化 x、y。

但,如果认真钻研方面的代码,会发觉一个不怎么题目,在中间描述原型继承的早晚:

Vector3D.prototype = new Vector2D();

咱俩其实无论参数地调用了一如既往软 Vector2D 的构造器!

立马同破调用是不必要之,而且,因为我们的 Vector2D
的构造器足够简单而没有副作用,所以我们这次无谓的调用除了小粗消耗了性外,并无会见带动最好严重的题材。

可是于实际上项目蒙,我们来把组件的构造器比较复杂,或者操作DOM,那么这种状况下无谓多调用平等次等构造器,显然是发生或导致严重问题之。

遂,我们得想艺术克服这等同差剩余的构造器调用,而显,我们发现我们可以免必要及时同浅剩余的调用:

function createObjWithoutConstructor(Class){
    function T(){};
    T.prototype = Class.prototype;
    return new T();    
}

方的代码中,我们通过创设一个空的构造器T,引用父类Class的prototype,然后回new T( ),来都行地避开Class构造器的履行。这样,我们确实好绕开父类构造器的调用,并将其的调用时机延迟暨子类实例化的时(本来为应这么才合情合理)。

function Vector2D(x, y){
  this.x = x;
  this.y = y;
}
Vector2D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y);
}

function Vector3D(x, y, z){
  Vector2D.call(this, x, y);
  this.z = z;
}
Vector3D.prototype = createObjWithoutConstructor(Vector2D);

Vector3D.prototype.length = function(){
  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}

var p = new Vector3D(1, 2, 3);
console.log(p.x, p.y, p.z, p.length(), p instanceof Vector2D);

这么,我们缓解了父类构造器延迟构造的问题之后,原型继承就较适用了,并且这样概括处理以后,使用起来还不会见影响instanceof返回值的对,这是暨另模拟方式相比最酷之补益。

模拟类继承

终极,我们下这规律还可以兑现比较全面的切近继承:

(function(global){"use strict"

  Function.prototype.extend = function(props){
    var Super = this; //父类构造函数

    //父类原型
    var TmpCls = function(){

    }
    TmpCls.prototype = Super.prototype;

    var superProto = new TmpCls();

    //父类构造器wrapper
    var _super = function(){
      return Super.apply(this, arguments);
    }

    var Cls = function(){
      if(props.constructor){
        //执行构造函数
        props.constructor.apply(this, arguments);
      }
      //绑定 this._super 的方法
      for(var i in Super.prototype){
        _super[i] = Super.prototype[i].bind(this);
      }
    }
    Cls.prototype = superProto;
    Cls.prototype._super = _super;

    //复制属性
    for(var i in props){
      if(i !== "constructor"){
        Cls.prototype[i] = props[i];
      }
    }  

    return Cls;
  }

  function Animal(name){
    this.name = name;
  }

  Animal.prototype.sayName = function(){
    console.log("My name is "+this.name);
  }

  var Programmer = Animal.extend({
    constructor: function(name){
      this._super(name);
    },
    sayName: function(){
      this._super.sayName(name);
    },
    program: function(){
      console.log("I\"m coding...");
    }
  });
  //测试我们的类
  var animal = new Animal("dummy"),
      akira = new Programmer("akira");
  animal.sayName();//输出 ‘My name is dummy’
  akira.sayName();//输出 ‘My name is akira’
  akira.program();//输出 ‘I"m coding...’

})(this);

可较一下ES6底接近继承:

(function(global){"use strict"

  //类的定义
  class Animal {
    //ES6中新型构造器
      constructor(name) {
          this.name = name;
      }
      //实例方法
      sayName() {
          console.log("My name is "+this.name);
      }
  }

  //类的继承
  class Programmer extends Animal {
      constructor(name) {
        //直接调用父类构造器进行初始化
          super(name);
      }
      sayName(){
          super.sayName();
      }
      program() {
          console.log("I\"m coding...");
      }
  }
  //测试我们的类
  var animal = new Animal("dummy"),
      akira = new Programmer("akira");
  animal.sayName();//输出 ‘My name is dummy’
  akira.sayName();//输出 ‘My name is akira’
  akira.program();//输出 ‘I"m coding...’

})(this);

总结

原型继承和类继承是简单种不同的认知模式,原型继承在目标不是过多底略以模型里比类继承更加灵敏方便。然而JavaScript的原型继承在语法上有一个组织器额外调用的题材,我们若透过
createObjWithoutConstructor来延迟构造器的调用,就能化解之题目。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图