javascript 中的继承实例详解


Posted in Javascript onMay 05, 2017

javascript 中的继承实例详解

阅读目录

  • 原型链继承
  • 借用构造函数
  • 组合继承
  • 寄生组合式继承
  • 后记

继承有两种方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。

由于函数没有签名,在ECMAScript中无法实现接口继承。ECMAScript只支持实现继承,而且实现继承主要依靠原型链来实现。

下面介绍几种js的继承:

原型链继承

原型链继承实现的本质是重写原型对象,代之以一个新类型的实例。代码如下:

function SuperType() {
  this.property = true;
}

SuperType.prototype.getSuperValue = function() {
  return this.property;
};

function SubType() {
  this.subproperty = false;
}

// 继承了SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
  return this.subproperty;
};

var instance = new SubType();

console.log(instance.getSuperValue()); // true

可以看到instance调用了父级的getSuperVlue()方法,实现了继承。

原型链的继承有如下问题:

  1. 包含引用类型值的原型时,在改变原型的引用类型时,会全部改了
  2. 在创建子类型的实例时,没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数

示例代码如下:

function SuperType1() {
  this.colors = ['red', 'blue', 'green'];
}
function SubType1() {

}
SubType1.prototype = new SuperType1();
var instance1 = new SubType1();
instance1.colors.push('black');
console.log(instance1.colors); // [ 'red', 'blue', 'green', 'black' ]

var instance2 = new SubType1();
console.log(instance2.colors); // [ 'red', 'blue', 'green', 'black' ]

可以发现,instance1和instance2的colors属性是共享的,这就出问题了,同时也能够看出,在new一个新的方法时,如果传值的话,是传不到父级的。

借用构造函数

原理是在子类型构造函数的内部调用超类型构造函数,因为函数只不过是在特定环境中执行代码的对象,这样就可以获取父级的方法和属性了。

代码如下:

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

function SubType(name) {
  // 继承了SuperType,同时还传递了参数
  SuperType.call(this, name);

  // 实例属性
  this.age = 29;
}

var instance = new SubType('Bob');

console.log(instance.name); // Bob
console.log(instance.age); // 29

可以看出,调用构造函数继承解决了向父类型传参的问题,但调用构造函数也有其自身的问题:

  1. 方法都在构造函数中,函数复用没有了。
  2. 超类型的原型中定义的方法,对子类型而言是不可见的。

第一个问题很明显,针对第二个问题的解释是,由于只是执行了一次函数,并没有new出新对象,故而父类prototype中的方法对子类是不可见的。

组合继承

由于原型链继承和借用构造函数继承都有缺陷,故而在实际中一般不会单独使用。

组合继承是借用其两者的优点而产生的继承方法。

其原理是使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。

代码如下:

function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

SuperType.prototype.sayName = function() {
  console.log(this.name);
};

function SubType(name, age) {
  // 继承属性
  SuperType.call(this, name);

  this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
  console.log(this.age);
};

var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black');

console.log(instance1.colors); // [ 'red', 'blue', 'green', 'black' ]
instance1.sayName(); // Nicholas
instance1.sayAge(); // 29

var instance2 = new SubType('Greg', 27);

console.log(instance2.colors); // [ 'red', 'blue', 'green' ]
instance2.sayName(); // Greg
instance2.sayAge(); // 27

组合继承能够解决上面两种继承方式带来的问题,但是组合继承也有其自身的小问题,那就是会调用两次超类型构造函数,通过分析便可知道 一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

寄生组合式继承

寄生组合式继承的原理为通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路是不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。

代码如下:

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;
}

function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

SuperType.prototype.sayName = function() {
 console.log(this.name);
};

function SubType(name, age) {
  SuperType.call(this, name);

  this.age = age;
}

// 继承的关键
inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {
  console.log(this.age);
};

var instance = new SubType('天涯', 23);
instance.sayName();
instance.sayAge();

寄生组合式继承只有在调用构造函数时执行了一遍超类型,解决了组合继承的小问题。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
JS TextArea字符串长度限制代码集合
Oct 31 Javascript
jquery的flexigrid无法显示数据提示获取到数据
Jul 19 Javascript
关闭页面window.location事件未执行的原因及解决方法
Sep 01 Javascript
JavaScript italics方法入门实例(把字符串显示为斜体)
Oct 17 Javascript
javascript简单实现图片预加载
Dec 03 Javascript
javascript单例模式的简单实现方法
Jul 25 Javascript
jQuery实现非常实用漂亮的select下拉菜单选择效果
Nov 06 Javascript
原生js实现弹出层效果
Jan 20 Javascript
小程序实现搜索界面 小程序实现推荐搜索列表效果
May 18 Javascript
vue更改数组中的值实例代码详解
Feb 07 Javascript
vue 实现动态路由的方法
Jul 06 Javascript
Flexible.js可伸缩布局实现方法详解
Nov 13 Javascript
JavaScript函数表达式详解及实例
May 05 #Javascript
Node.js中的http请求客户端示例(request client)
May 04 #Javascript
Bootstrap布局之栅格系统学习笔记
May 04 #Javascript
vue.js开发环境搭建教程
May 04 #Javascript
jQuery使用JSONP实现跨域获取数据的三种方法详解
May 04 #jQuery
详解webpack es6 to es5支持配置
May 04 #Javascript
angular 基于ng-messages的表单验证实例
May 04 #Javascript
You might like
2个比较经典的PHP加密解密函数分享
2014/07/01 PHP
PHP动态规划解决0-1背包问题实例分析
2015/03/23 PHP
基于PHP实现假装商品限时抢购繁忙的效果
2015/10/16 PHP
PHP数据库表操作的封装类及用法实例详解
2016/07/12 PHP
Windows平台实现PHP连接SQL Server2008的方法
2017/07/26 PHP
PHP命名空间与自动加载类详解
2018/09/04 PHP
jQuery表单验证插件formValidator(改进版)
2012/02/03 Javascript
Javascript控制页面链接在新窗口打开具体方法
2013/08/16 Javascript
JQuery判断子iframe何时加载完成解决方案
2013/08/20 Javascript
浅谈Jquery为元素绑定事件
2015/04/27 Javascript
使用Angular和Nodejs、socket.io搭建聊天室及多人聊天室
2015/08/21 NodeJs
node.js连接mongoDB数据库 快速搭建自己的web服务
2016/04/17 Javascript
基于bootstrap实现广告轮播带图片和文字效果
2016/07/22 Javascript
深入理解jQuery layui分页控件的使用
2016/08/17 Javascript
微信小程序 引入es6 promise
2017/04/12 Javascript
微信小程序教程系列之新建页面(4)
2017/04/17 Javascript
Vue.js递归组件构建树形菜单
2017/12/24 Javascript
转换layUI的数据表格中的日期格式方法
2019/09/19 Javascript
js实现开关灯效果
2020/03/30 Javascript
快速解决Vue、element-ui的resetFields()方法重置表单无效的问题
2020/08/12 Javascript
javascript实现简易计算器功能
2020/09/23 Javascript
python基础教程之自定义函数介绍
2014/08/29 Python
Python爬取数据保存为Json格式的代码示例
2019/04/09 Python
对Django的restful用法详解(自带的增删改查)
2019/08/28 Python
PyCharm第一次安装及使用教程
2020/01/08 Python
css3实现简单的白云飘动背景特效
2020/10/28 HTML / CSS
面向对象编程是如何提高软件开发水平的
2014/05/06 面试题
为什么在使用动态 SQL 语句时必须为低层数据库对象授予权限
2012/12/13 面试题
化学相关工作求职信
2013/10/02 职场文书
财务经理的岗位职责
2013/12/17 职场文书
秦兵马俑教学反思
2014/02/07 职场文书
普通大学毕业生自荐信范文
2014/02/23 职场文书
2015年护士医德医风自我评价
2015/03/03 职场文书
2016元旦文艺汇演主持词(开场白+结束语)
2015/12/03 职场文书
Python带你从浅入深探究Tuple(基础篇)
2021/05/15 Python
python munch库的使用解析
2021/05/25 Python