亚洲城88娱乐官网:寄生组合,寄生组合式

一篇文章领悟JS继承——原型链/构造函数/组合/原型式/寄生式/寄生组合/Class extends

2018/08/02 · JavaScript
· 继承

原稿出处:
这是您的玩具车吗   

说实在话,以前笔者只供给理解“寄生组合继承”是最好的,有个祖传代码模版用就行。如今因为一些工作,多少个星期以来间接心心念念想整理出来。本文以《JavaScript高级程序设计》上的情节为骨架,补充了ES6
Class的相干内容,从本人觉着更便于明白的角度将一连那件事叙述出来,希望大家能有所收获。

JavaScript继承的6种方法

JavaScript继承基础讲解(原型链、借用构造函数、混合情势、原型式继承、寄生式继承、寄生组合式继承),javascript构造函数

说好的讲解JavaScript继承,不过迟迟到前几天教学。废话不多说,直接进入正题。

  既然您想询问继承,注解你对JavaScript面向对象已经有早晚的问询,如还有怎么样不精通的能够参见《面向对象JS基础讲解,工厂形式、构造函数情势、原型形式、混合形式、动态原型方式》,接下去讲一般通过那个方法成功JavaScript的一而再。

  原型链

  JavaScript中落实持续最简便的法门正是使用原型链,将子类型的原型指向父类型的实例即可,即“子类型.prototype
= new 父类型();”,完毕格局如下:

// 为父类型创建构造函数
function SuperType() {
  this.name = ['wuyuchang', 'Jack', 'Tim'];
  this.property = true;
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType() {
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 实现继承的关键步骤,子类型的原型指向父类型的实例
SubType.prototype = new SuperType();

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType();
instance1.name.push('wyc');
instance1.test.push('h5');
alert(instance1.getSuerperValue());    // true
alert(instance1.getSubValue());      // false
alert(instance1.name);          // wuyuchang,Jack,Tim,wyc
alert(instance1.test);          // h1,h2,h3,h4,h5


var instance2 = new SubType();
alert(instance2.name);          // wuyuchang,Jack,Tim,wyc
alert(instance2.test);          // h1,h2,h3,h4

能够观察如上的代码便是经过原型链达成的3个简约的持续,但看到测试代码示例中要么存在些难点。相信看了自作者的博文《面向对象JS基础讲解,工厂形式、构造函数格局、原型格局、混合形式、动态原型格局》的童鞋一定知道原型链代码存在的率先个难题是由于子类型的原型是父类型的实例,也正是子类型的原型中蕴藏的父类型的特性,从而导致引用类型值的原型属性会被有着实例所共享。以上代码的instance1.name.push(‘wyc’);就足以印证此难题的留存。而原型链的第1个难点正是:在创制子类型的实例时,不可能向超类型的构造函数中传送参数。因此大家在其实费用中,很少单独行使原型链。 

   借用构造函数

  为了消除原型链中存在的三个难题,开发职员开始应用一种叫做借用构造函数的技术来缓解原型链中存在的题材。那种技能的兑现思路也挺不难,只须求在子类型的构造函数内调用父类型的构造函数即可。别忘了,函数只不过是在一定环境中推行代码的对象,由此能够由此apply()或call()方法执行构造函数。代码如下:

// 为父类型创建构造函数
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
// alert(instance1.getSuerperValue());    // error 报错
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
// alert(instance2.getSuerperValue());    // error 报错
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

能够看来以上代码中子类型SubType的构造函数内经过调用父类型”SuperType.call(this,
name);”,从而实现了质量的接轨,也得以在子类型成立实例的时候为父类型传递参数了,但新的难题又来了。可以看出自家在父类型的构造函数中定义了多个艺术:testFun,在父类型的原型中定义了1个艺术:getSuperValue。然则在实例化子类型后如故是力不从心调用父类型的原型中定义的点子getSuperValue,只好调用父类型中构造函数的措施:testFun。那就同创设对象中只行使构造函数方式一样,使得函数没有复用性可言。考虑到这个题材,借用构造函数的技术也是很少单独行使的。

组成继承(原型链+借用构造函数)

  顾名思义,组合继承正是组成使用原型链与借用构造函数的长处,组合而成的1个形式。完成也很简单,既然是结合,那自然结合了两方的亮点,即原型链继承方法,而在构造函数继承属性。具体代码达成如下:

// 为父类型创建构造函数
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

SubType.prototype = new SuperType();

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
alert(instance1.getSuerperValue());      // true
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
alert(instance2.getSuerperValue());      // true
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

如上代码通过SuperType.call(this,
name);继承父类型的习性,通过SubType.prototype = new
SuperType();继承父类型的方法。以上代码很方便的化解了原型链与借用构造函数所碰着的标题,成为了JavaScript中最为常用的实例继承的点子。但混合形式也毫不没有缺陷,能够观望在上述代码中在继续方法的时候其实已经一而再了父类型的特性,只可是此时对此引用类型属于共享的,由此在子类型的构造函数内在次调用父类型的构造函数从而继续了父类型的性质而去覆盖了原型中所继承的性质,那样调用两回构造函数字展现然没有须要,但有啥办法能够消除呢?在缓解此题材时先看以下四个情势。

原型式继承

  原型式继承的的贯彻格局与一般继承的贯彻情势区别,原型式继承并从未采取严酷意义上的构造函数,而是依靠原型能够依据已有个别对象创造新目的,同时还不用由此创设自定义类型。具体代码如下:

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

代码示例:

/* 原型式继承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Tim']
}

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Bob');

var anotherPerson2 = object(person);
anotherPerson2.name = 'Jack';
anotherPerson2.friends.push('Rose');

alert(person.friends);  // wyc,Nicholas,Tim,Bob,Rose

寄生式继承

/* 寄生式继承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

亚洲城88娱乐官网,接纳示例:

/* 原型式继承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

/* 寄生式继承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Rose']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

寄生组合式继承

  前边说过了JavaScrip中结成方式达成持续的瑕疵,以后我们就来缓解它的毛病,达成思路是,对于构造函数继承属性,而原型链的混成方式继续方法,即不用在持续方法的时候实例化父类型的构造函数。代码如下:

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

/* 寄生组合式继承 */
function inheritPrototype(subType, superType) {
  var prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

而在运用时只供给将结合格局中的“SubType.prototype = new
SuperType();”这行代码替换到inheritPrototype(subType,
superType);即可。寄生组合式继承的高效用映以往它只调用了叁次父类型构造函数,防止了成立不必要的或多余的习性。与此同时,原型链还可以够维持不变,由此,仍可以够健康使用instanceof和isPrototypeof()。那也是时下的话最地道的接轨形式了,方今也在向那种形式转型。(YUI也利用了那种形式。)

此博文参考《JavaScript高级程序设计第②版》,代码为通过改写,更具体,并加了诠释使大家更易懂。如对JS继承方面有独到见解的童鞋不别吝啬,回复您的视角供我们参考!

比方你不是张无忌,有寒冰绵掌护体,那么圣火神功的确不是一炷香的时刻就能练到九重的。

1. 无冕分类

先来个完整印象。如图所示,JS中继续能够依照是不是利用object函数(在下文中会提到),将一而再分成两有的(Object.create是ES5新增的不二法门,用来规范化那一个函数)。

当中,原型链继承和原型式继承有相同的利弊,构造函数继承与寄生式继承也相互照应。寄生组合继承基于Object.create,
同时优化了整合继承,成为了周全的接续格局。ES6 Class
Extends的结果与寄生组合继承基本一致,不过贯彻方案又略有不相同。

上边霎时进入正题。

亚洲城88娱乐官网 1

1,原型链继承

2,借用构造函数继承

3,组合继承(原型+借用构造)

4,原型式继承

5,寄生式继承

6,寄生组合式继承

在JavaScript的原型链继承方式中,为什么子类在调用父类的构造函数时不得以传参数?

先河动和自动己在看书时也遇上过如此的题材,找了好多资料都尚未显明的诠释。
自身觉着,并不是语法上不能够实现对构造函数的参数字传送递,而是那样做不适合面向对象编制程序的规则:对象(实例)才是性质的拥有者。
假如在子类定义时就将属性赋了值,对象实例就无法再变更本身的性质了。那样就成为了类具有属性,而不是目的具备属性了。
举个例证,子类 Children 继承父类 Parents,Parents 构造函数:
亚洲城88娱乐官网:寄生组合,寄生组合式。function Parents(name){ this.name=name; }
利用原型链并给父类构造函数字传送参数:
Children.prototype=new Parents(“Hello”);
那正是说此时,Children 类就有着了 name=“Hello” 属性,而 Children
类的实例对象 c一 、c贰 、c3 等等只好被迫接受那几个 name 属性。Children 是
“Hello” 的拥有者而 c① 、 c② 、c3不是!
如此那般写完全失去了面向对象编制程序的意思,所以在原型链继承格局中规定不能够对父类构造函数字传送递参数。也因为这一个缘故,原型链继承情势并不实用。
 

记得多少个月在此之前照旧看不懂高程上的原型一章的,不是没仔细看,相反,作者当机不断看了少数遍,每看三次都深感自信心受到了打击。。。。明日莫名打通任督二脉=

2. 接续格局

上海体育场地上半区的原型链继承,构造函数继承,组合继承,网上内容比较多,本文不作详细描述,只提议重点。那里给出了自身以为最简单了然的一篇《JS中的继承(上)》。假如对上半区的始末目生,能够先看那篇小说,再重回继续读书;假若已经比较熟知,那有的能够长足略过。另,上半区大气借出了yq前端的一篇三番五次小说[1]。

1.原型链继承.

JS 类继承与原型继承分裂

类式继承就像java的延续一样,思想也比较不难:在子类型构造函数的内部调用超类型构造函数。

原型式继承是借助已有的对象创造新的对象,将子类的原型指向父类,就一定于进入了父类那条原型链

而你的 上边那段代码不是严苛意义上的类式继承,根据NicholasC.扎卡s的布道,那些应该称为组合式继承。它调用了四回parent2()。第三遍是
child2.prototype=new parent2(‘param’);
child2就会获取三个属性param,getParam(),他们都以parent2的性质,不过他们在child2的原型中。第三回是parent2.call(this,cparam);
这一次又在新对象上创办了实例属性param,getParam()。于是,那多个属性就屏蔽了原型中的七个同名属性。那有何样便宜呢,正是您在创设1个child3时也延续parent2()的习性,仍是能够定义自个儿的性子。与此同时他长的就和她兄弟分化了,但又有同等的“血统(使用父类的法门)”。

纯手打,欢迎继续研讨
 

说好的讲解Java…

写在前边

先是考虑1个标题,大家精通通过构造函数和new操作符能够创建二个新的靶子,并且同叁个构造函数能够创设出相同属性和方法的对象,那就是prototype所做的(使用原型对象的好处是可以让全部实例共享它所包蕴的特性和措施)。并且,在别的构造函数中通过call和apply,调用其余构造函数不就能够兑现持续了啊,那大家还要prototype做怎么样?


缘由是,其实new操作符生成的指标并不可能共享属性和形式,每回new二个新的对象时,都要为这些指标开辟二个新的长空来存放在它的属性和办法,而且,在构造函数中,每一趟想要修改有些属性和措施时,就要重复生成全数的实例,对财富造成了非常的大的浪费!!!
ok,因为不想浪费,所以我引入了原型

2.1 原型式继承

主导:将父类的实例作为子类的原型

SubType.prototype = new SuperType() //
全数涉及到原型链继承的接轨情势都要修改子类构造函数的针对,否则子类实例的构造函数会指向SuperType。
SubType.prototype.constructor = SubType;

1
2
3
SubType.prototype = new SuperType()
// 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。
SubType.prototype.constructor = SubType;

可取:父类方法能够复用

缺点:

  • 父类的引用属性会被有着子类实例共享
  • 子类构建实例时不可能向父类传递参数
<script type="text/javascript">
    function Person(name,sex)
    {
        this.name=name;
        this.sex=sex;
        this.friends=['李四'];
        this.getName=function(){
            alert(this.name);
        }
    }
   Person.prototype.id=1;

    function Boy(age)
    {
        this.age=age;
        this.getAge=function(){
            alert(this.age);
        }

    }
    //继承
    Boy.prototype=new Person("张三","男");


    var boy=new Boy(16);

    alert(boy.name);              //张三
    boy.getAge();               //16
    alert(boy.id);                 //1


    //属性共享问题
    console.log(boy.friends);            //李四

    var boy2=new Boy(17);
    boy2.friends.push('王五');  //修改boy2的friends属性的同时也影响了boy的属性

    console.log(boy.friends);            //李四 王五

    //验证能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //true
    console.log(Person.prototype.isPrototypeOf(boy));   //true
</script>
注:部分例证摘自JS高程

2.2 构造函数继承

着力:将父类构造函数的剧情复制给了子类的构造函数。那是独具继续中唯一三个不涉及到prototype的后续。

SuperType.call(SubType);

1
SuperType.call(SubType);

亮点:和原型链继承完全翻转。

  • 父类的引用属性不会被共享
  • 子类创设实例时能够向父类传递参数

缺点:父类的点子不能够复用,子类实例的主意每一趟都以单身创制的。

 

领会原型对象

遵守以下多少个规则
1,
大家创制的每一种函数都有贰个prototype属性,那些性子是三个指针,指向二个对象,而那些{…}(对象,也正是原型对象)包括了拥有实例共享的习性和方法。
哦,函数拥有prototype指针,指向原型对象
2,
原型对象除了1所说包涵全部实例的共享的属性和办法,还有二个constructor指针指向构造函数,对的,构造函数和原型对象互指,通过prototype和constructor
3,
实例:当构造函数为空,仅在构造函数的原型对象上有属性和函数时,此构造函数所开创的实例本质上唯有多少个名为proto的指针,全体实例的这些指针统统指向原型对象,由此他们才有了共享的习性和章程,而且尚未独立开发本身的上空,节省了能源
看个例证,掌握那三条

function animal(){
}
animal.prototype.name = "Tom"
animal.prototype.say = function(){
      alert('喵喵喵?')
}
var cat = new animal()
console.log(cat.name) //"Tom"
console.log(cat.say) //"喵喵喵?"

ok,解释一下。上边代码中
1,
构造函数为aniaml,当我们创制了这些构造函数时,他现已包罗了三个原型属性
prototype
2, 该构造函数的原型对象
console.log(animal.prototype) //返回一个对象,即原型对象,该对象包含一个name属性,一个say函数
3, 该实例
cat.__prpto__ == animal.prototype //true
都针对原型对象


在那一个事例中,构造函数自己为空,在构造函数的原型对象上开创了贰性子质和章程,他们被抱有实例所共享,因为实例中有proto指南针指向了该原型对象。不过只要应用那种方式,我们在构造函数内写的性质和章程不是都能够转到prototype上啊,那还要构造函数干什么?
因为,此处是指针式的获取到了原型上的多寡,当那些数额为引用型数据(也是指针式)(如数组时),大家在实例上改变那一个数组,会影响原型对象上的那一个数组属性,从而影响全数实例。因而,构造函数也有它的必不可少用途,函数原型上一般只定义函数和非引用型数据。

2.3 组合继承

主干:原型式继承和构造函数继承的结合,兼具了双边的优点。

function SuperType() { this.name = ‘parent’; this.arr = [1, 2, 3]; }
SuperType.prototype.say = function() { console.log(‘this is parent’) }
function SubType() { SuperType.call(this) // 第②次调用SuperType }
SubType.prototype = new SuperType() // 第贰回调用SuperType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function SuperType() {
    this.name = ‘parent’;
    this.arr = [1, 2, 3];
}
 
SuperType.prototype.say = function() {
    console.log(‘this is parent’)
}
 
function SubType() {
    SuperType.call(this) // 第二次调用SuperType
}
 
SubType.prototype = new SuperType() // 第一次调用SuperType

优点:

  • 父类的形式能够被复用
  • 父类的引用属性不会被共享
  • 子类营造实例时得以向父类传递参数

缺点:

调用了一次父类的构造函数,第三回给子类的原型添加了父类的name,
arr属性,第二次又给子类的构造函数添加了父类的name,
arr属性,从而覆盖了子类原型中的同名参数。那种被覆盖的情况导致了品质上的荒废。

特点:既连续了父类的沙盘,又一而再了父类的原型对象。

组合使用构造函数和原型形式

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby","Court"];
}

Person.prototype = {
    constructor : Person,
    sayName : function(){
        alert(this.name);
    }
}

var person1 = new Person("Nicholas",29,"Software");
var person2 = new Person("Greg",27,"Doctor");

perons1.frineds.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //“Shelby,Count”

在这么些例子中,构造函数中定义实例属性,原型对象上定义方法和共享属性。
历次调用构造函数,给新的靶子开辟一个新的半空中,此时的实例上的friends属性是全新的,非proto针对的,拥有独立空间的,所以每一种空间的friends数组是单独互不影响的,因而在person1对象中添加3个friends后,person2的friends属性并未改观,而person1和person2都足以共享sayName函数,还有name,age,job等质量。

2.4 原型式继承

基本:原型式继承的object方法本质上是对参数对象的二个浅复制。

可取:父类方法能够复用

缺点:

  • 父类的引用属性会被全部子类实例共享
  • 子类营造实例时不能够向父类传递参数

function object(o){ function F(){} F.prototype = o; return new F(); }
var person = { name: “Nicholas”, friends: [“Shelby”, “Court”, “Van”]
}; var anotherPerson = object(person); anotherPerson.name = “Greg”;
anotherPerson.friends.push(“Rob”); var yetAnotherPerson =
object(person); yetAnotherPerson.name = “Linda”;
yetAnotherPerson.friends.push(“Barbie”); alert(person.friends);
//”Shelby,Court,Van,Rob,Barbie”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
 
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
 
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
 
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
 

ECMAScript 5 通过新增
Object.create()方法规范化了原型式继承。那一个格局接收多少个参数:二个用作新对象原型的指标和(可选的)四个为新对象定义额外属性的靶子。在传诵2个参数的意况下,
Object.create()与 object()方法的行为等同。——《JAVASCript高级编制程序》

所以上文中代码能够转移为

var yetAnotherPerson = object(person); => var yetAnotherPerson =
Object.create(person);

1
var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);

缺陷:只可以在父类设置有个别参数,子类无法灵活传参,不切合面向对象的思考,包涵引用类型值的性子始终都会共享相应的值。

那种构造函数与原型形式混成的形式,是眼下在ECMAScript中应用最广大的、认可度最高的一种成立自定义类型的不二法门。那是用来定义引用类型的一种暗中同意形式。

2.5 寄生式继承

主干:使用原型式继承取得一个对象对象的浅复制,然后增强那些浅复制的力量。

利弊:仅提供一种思路,没什么优点

function createAnother(original){ var clone=object(original);
//通过调用函数创制三个新目的 clone.sayHi = function(){
//以某种方式来增强那一个指标 alert(“hi”); }; return clone; //重返这几个指标} var person = { name: “Nicolas”, friends: [“Shelby”, “Court”, “Van”]
}; var anotherPerson = createAnother(person); anotherPerson.sayHi();
//”hi”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function createAnother(original){
    var clone=object(original);    //通过调用函数创建一个新对象
    clone.sayHi = function(){      //以某种方式来增强这个对象
        alert("hi");
    };
    return clone;                  //返回这个对象
}
 
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
 
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

 亚洲城88娱乐官网 2

原型链继承

在java等oop语言中再三再四由class和extend关键字来贯彻,而在ES5中绝非那个根本字(
ES6有
),因而不得不通过使子函数的原型对象等于父函数的实例来落到实处链式继承。看例子

function SuperType(){
    this.color = ['red', 'blue' , 'yellow'];
}

function SubType(){}

SubType.prototype = new SuperType(); //子函数的原型对象等于父函数的实例

var instance1 = new SubType();
instance1.color.push ('white');
alert(instance1.color); // red,blue,yellow,white

var instance2 = new SubType();
alert(instance2.color); // red,blue,yellow,white

子函数的原型对象等于父函数的实例,此时子函数SubType的原型被改写,成为了SuperType的实例,而地点讲了实例拥有多少个proto个性(指针)指向原型对象,因而那么些SubType的原型对象上的proto天性指向了SuperType的原型对象。然后当大家制造了SubType的实例instance时,instance中也有叁个proto指南针,而它指向SubType.prototype,SubType.prototype上的proto指南针,指向SuperType.prototype,其实再往上,SuperType.prototype也是指标的一种,因而它也是Object的1个实例,SuperType.prototype的proto指南针指向Object.prototype。(顶层)(原型链的中坚正是proto指针)

2.6 寄生组合继承

刚刚说到组合继承有一个会两遍调用父类的构造函数造成浪费的缺陷,寄生组合继承就足以缓解那个难点。

function inheritPrototype(subType, superType){ var prototype =
object(superType.prototype); // 创造了父类原型的浅复制
prototype.constructor = subType; // 改正原型的构造函数 subType.prototype
= prototype; // 将子类的原型替换为这些原型 } function SuperType(name){
this.name = name; this.colors = [“red”, “blue”, “green”]; }
SuperType.prototype.sayName = function(){ alert(this.name); }; function
SubType(name, age){ SuperType.call(this, name); this.age = age; } //
大旨:因为是对父类原型的复制,所以不分包父类的构造函数,也就不会调用五次父类的构造函数造成浪费
inheritPrototype(SubType, SuperType); SubType.prototype.sayAge =
function(){ alert(this.age); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype); // 创建了父类原型的浅复制
    prototype.constructor = subType;             // 修正原型的构造函数
    subType.prototype = prototype;               // 将子类的原型替换为这个原型
}
 
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
 
SuperType.prototype.sayName = function(){
    alert(this.name);
};
 
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
// 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
    alert(this.age);
}

利弊:那是一种完美的后续情势。

2.借出构造函数继承

那种实例与原型的链条,就叫做原型链

2.7 ES6 Class extends

骨干:
ES6继承的结果和寄生组合继承相似,本质上,ES6后续是一种语法糖。可是,寄生组合继承是先创造子类实例this对象,然后再对其压实;而ES6先将父类实例对象的性质和艺术,加到this下边(所以必须先调用super方法),然后再用子类的构造函数修改this。

class A {} class B extends A { constructor() { super(); } }

1
2
3
4
5
6
7
class A {}
 
class B extends A {
  constructor() {
    super();
  }
}

ES6贯彻一而再的现实性原理:

class A { } class B { } Object.setPrototypeOf = function (obj, proto) {
obj.__proto__ = proto; return obj; } // B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {
}
 
class B {
}
 
Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}
 
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
 
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);
 

ES6持续与ES5持续的异同:

相同点:本质上ES6三番五次是ES5一而再的语法糖

不同点:

  • ES6卫冕合中学子类的构造函数的原型链指向父类的构造函数,ES5中行使的是构造函数复制,没有原型链指向。
  • ES6子类实例的创设,基于父类实例,ES5中不是。
<script type="text/javascript">
      //父类
    function Person(name,sex)
    {
        this.name=name;
        this.sex=sex;
        this.friends=['李四'];
    }
    Person.prototype.id=1;
    //子类
    function Boy(name,sex,age)
    {

        //借用
        Person.call(this,name,age);

        this.age=age;
        this.getAge=function(){
            alert(this.age);
        }

    }


    var boy=new Boy("张三","男",16);
    alert(boy.name);  //张三

    boy.getAge();        //16

    alert(boy.id);  //undefined  没有继承父类的原型对象


    //属性共享问题 ————不会有共享


    //验证能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //false
    console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>

整合继承

上述的SubType.prototype = new SuperType(); //子函数的原型对象等于父函数的实例确实落成了三番八次,不过当SuperType构造函数中有引用型数据时,即此时SubType.prototype上也有了引用类型,今后又出现了上面提过的难点,在sub的实例中改变引用类型的值会反映到拥有实例中。
其次点,在成立子类型的实例时不可能给超类型的构造函数字传送递参数。

发表评论

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

网站地图xml地图