1、原型链继承

直接将子类型的原型指向父类型的实例,即“子类型.prototype = new 父类型();”,实现方法如下:

//父类构造函数
function father(name) {
this.name = name;
this.colors = ['red'];
}
//父类添加属性
father.prototype.sayName = function() {
console.log(this.name);
}
//子类构造函数(声明)
function son(name,age) {
this.age = age;
}
// 实现继承的关键步骤,子类型的原型指向父类型的实例
son.prototype = new father(); // 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,那么方法就为空(被父类型给覆盖了)
son.prototype.sayAge = function() {
console.log(this.age);
} var tmp1 = new son('try',18);
console.log(tmp1.colors); //'red'
tmp1.sayAge(); var tmp2 = new son();
tmp2.colors.unshift('yellow');
console.log(tmp1.colors); //'yellow','red'

以上代码不难看出,有两个问题

  1. 原型链方式可以实现所有属性方法共享,但无法做到属性、方法独享
  2. 在创建子类型的实例时,不能向父类型的构造函数中传递参数。实际上是没有办法在不影响所有对象实例的情况下,给父类型的构造函数传递参数

    基于此,实践中很少单独使用原型链。

2、借用构造函数

为了解决上面两个问题,出现了这种方法。在子类型的构造函数内调用父类型的构造函数,函数只不过是在特定环境中执行代码的对象,因此可以通过apply()或call()方法执行构造函数

除了能独享属性、方法外还能在子类构造函数中传递参数,但代码无法复用。

function father(name) {
this.name = name;
this.colors = ['red'];
this.test = function() {
console.log('test success');
}
}
father.prototype.sayName = function() {
console.log(this.name);
} function son(name,age) {
//就只是加了下面这句
father.apply(this);
this.age = age;
} var tmp1 = new son('try',18);
console.log(tmp1.colors); //'red'
tmp1.sayName(); //error!
tmp1.test(); //OK var tmp2 = new son();
tmp2.colors.unshift('yellow');
console.log(tmp1.colors); // 'red'

不难发现,这种方法也有一个超大的问题。子类只能调用父类构造函数里的函数(如上面的test),对于其后面定义在其属性里的函数(如上面的sayName)就无法调用了。因此函数复用就无从谈起了。

3、组合继承

顾名思义,组合,就是将上两种方式组合在一起,从而发挥二者之长的一种继承模式。使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现堆实例属性的继承

分别是 son.prototype = new father(); apply(this);

但混合模式也并非没有缺点,在继承方法的时候实际已经继承了父类型的属性,只不过此时对于引用类型属于共享的;

因此在子类型的构造函数内再次调用父类型的构造函数从而继承了父类型的属性而去覆盖了原型中所继承的属性。

即调用了两次父类构造函数


function father(name) {
this.name = name;
this.colors = ['red'];
this.test = function() {
console.log('test success');
}
}
father.prototype.sayName = function() {
console.log(this.name);
} function son(name,age) {
father.apply(this); //一次调用
this.age = age;
}
son.prototype = new father(); //两次调用
var tmp1 = new son('try',18);
console.log(tmp1.colors); //'red'
tmp1.sayName(); //error!
tmp1.test(); //OK var tmp2 = new son();
tmp2.colors.unshift('yellow');
console.log(tmp1.colors); // 'red'

4、原型式继承(寄生和这个差不多 不单独介绍了,但寄生有增强对象的过程 即构造函数指向自己)

和原型链唯一的不一样在于,原型式继承 就是不用实例化父类了,直接实例化一个临时副本实现了相同的原型链继承。(即子类的原型指向父类副本的实例从而实现原型共享)。

原型式继承并没有使用严格意义上的构造函数,而是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

当然,这种方式,包含引用类型值的属性时钟会共享相应的值。

//原型式继承
function object(o) {
function F() {}
F.prototype = o;
return new F();
} var father = {
name: 'try',
colors: ['red']
} //ECMAScript规范了原型式继承
var son1 = Object.create(father);
son1.name = 'rr';
son1.colors.push('yellow');
console.log(son1.colors); var son2 = Object.create(father);
console.log(son2.colors);

5、寄生组合式继承

完美的继承方式,重点掌握。寄生+借用构造,解决了之前需要调用两个父类构造函数的问题。

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

不必为例指定子类型的原型而调用父类型的构造函数,我们所需要的无非是父类型原型的一个副本而已。

本质上,就是使用寄生式继承来的父类型的原型,然后再将结果指定给子类型的原型。


function object(fa) {
//实际上是实行了一次浅复制
function F() {}; //为了得到fa的原型创造出的临时对象
F.prototype = fa; //获得原型
return new F();
}
function inheritPrototype(son, father) {
var prototype = object(father.prototype); //创建对象
prototype.constructor = son; //构造函数指向要创建的 即增强对象
son.prototype = prototype; //原型继承
} function father(name) {
this.name = name;
this.colors = ['red'];
}
father.prototype.sayName = function() {
console.log(this.name);
}
function son(name,age) {
father.call(this, name);
this.age = age;
}
inheritPrototype(son,father); var tmp1 = new son('try',19);
tmp1.colors.unshift('yellow');
var tmp2 = new son('tt',10);
console.log(tmp2.colors); //'red'
tmp2.sayName(); //tt

属性继承代码是SuperType.call(this,name);

原型继承代码是inheritPrototype(son,father);

参考《JavaScript高级程序设计第3版》。

JavaScript几种继承方式的总结的更多相关文章

  1. JavaScript之四种继承方式讲解

    在Javascript中,所有开发者定义的类都可以作为基类,但出于安全性考虑,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击. 选定基类后,就可 ...

  2. JavaScript几种继承方式

    我们先构建一个Person的构造函数 function Person(name) { this.name=name; } Person.prototype.sayHi=function () { co ...

  3. JavaScript五种继承方式详解

    本文抄袭仅供学习http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html 一. 构造函数绑定 ...

  4. Javascript的四种继承方式

    在Javascript中,所有开发者定义的类都可以作为基类,但出于安全性考虑,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击. 选定基类后,就可 ...

  5. JavaScript的3种继承方式

    JavaScript的继承方式有多种,这里列举3种,分别是原型继承.类继承以及混合继承. 1.原型继承 优点:既继承了父类的模板,又继承了父类的原型对象: 缺点:不是子类实例传参,而是需要通过父类实例 ...

  6. JavaScript 的对象继承方式,有几种写法?

    JavaScript 的对象继承方式,有几种写法? 一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Pa ...

  7. 架构师JavaScript 的对象继承方式,有几种程序写法?

    架构师JavaScript 的对象继承方式,有几种程序写法?   一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数, ...

  8. 【设计模式+原型理解】第三章:javascript五种继承父类方式

    [前言] 我们都知道,面向对象(类)的三大特征:封装.继承.多态 继承:子类继承父类的私有属性和公有方法 封装:把相同的代码写在一个函数中 多态: ->重载:JS严格意义上是没有重载,但可以通过 ...

  9. 都0202年了,你还不知道javascript有几种继承方式?

    前言     当面试官问你:你了解js哪些继承方式?es6的class继承是如何实现的?你心中有很清晰的答案吗?如果没有的话,可以通过阅读本文,帮助你更深刻地理解js的所有继承方式.       js ...

随机推荐

  1. FPGA实现-shift_ram_3x3矩阵

    shift_ram_3x3-FPGA实现 实现的方法为方法二,可以参考上一节关于中值滤波的介绍 shift_ram核介绍 https://www.cnblogs.com/ninghechuan/p/6 ...

  2. VSCode最强助攻

    VSCode最强助攻 VS Code是前端界必备的开发工具.页面仔小杨简单介绍几款高效.好用的插件,让原本单薄的VS Code如虎添翼,开发效率倍增. vscode-icons vscode-icon ...

  3. Day_12【集合】扩展案例1_利用集合的知识对长度为10的int数组进行去重,产生新数组,不能改变数组中原来数字的大小顺序

    分析以下需求,并用代码实现 1.定义一个长度为10的int数组,并存入10个int类型的数据,其中有一些数据是重复的 2.利用集合的知识对数组进行去重,产生新数组,不能改变数组中原来数字的大小顺序 3 ...

  4. STM32 外部中断详解(原理+配置代码)

    本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断 文章目录 1 前言 2 STM32的外部中断 3 中断服务函数的映射关系 4 外部中断的配置 5 寄存器的 ...

  5. [hdu5373 The shortest problem]模拟

    http://acm.hdu.edu.cn/showproblem.php?pid=5373 思路:按题意来即可. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  6. Appium自动化(10) - appium高级元素定位方式之 UI Automator API 的详解

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 前面介绍过根据id,clas ...

  7. 把iview中的table组件写成了一个公用组件,在另一个组件里去引用它的时候rander函数里的this指向不正确

    在vue项目里使用iview制作后台管理系统时,由于有多个页面都需要用到table组件,所以就把table写到了一个公共组件里,在其他页面去引用它,但是这时会发现一个问题,就是render函数里的th ...

  8. 微信小程序跑步计时器

    firstStep:run.wxml <view class="head" style="flex-direction:row;"> <ima ...

  9. asp中设置session过期时间方法总结

    http://www.jb51.net/article/31217.htm asp中设置session过期时间方法总结 作者: 字体:[增加 减小] 类型:转载   asp中默认session过期时间 ...

  10. 使用PHP得到所有的HTTP请求头

    作者:老王 在PHP里,想要得到所有的HTTP请求头,可以使用getallheaders方法,不过此方法并不是在任何环境下都存在,比如说,你使用fastcgi方式运行PHP的话,就没有这个方法,所以说 ...