详解JavaScript中基于原型prototype的继承特性


Posted in Javascript onMay 05, 2016

JavaScript 中的继承比较奇葩,无法实现接口继承,只能依靠原型继承。

原型链
原型就是一个对象,通过构造函数创建出来的实例会有指针指向原型得到原型的属性和方法。这样,实例对象就带有构造函数的属性方法和原型的属性方法,然后将需要继承的构造函数的原型指向这个实例,即可拥有这个实例的所有属性方法实现继承。
看下面演示代码:

//声明超类,通过构造函数和原型添加有关属性和方法
function Super(){
  this.property = true;
}
Super.prototype.getSuperValue = function() {
  return this.property;
};

//声明子类的构造函数
function SubType() {
  this.subproperty = false;
}
//将子类的原型指向超类的实例,得到超类的一切
SubType.prototype = new Super();
SubType.prototype.constructor = SubType;
SubType.prototype.getSubValue = function(){
  return this.subproperty;
};
//由子类创建对象,测试是否继承超类方法和属性
var instance = new SubType();
console.log(instance.getSuperValue());

所有函数的默认原型都是 Object 的实例,因此默认原型都会包含一个内部指针,指向 Object.prototype。
使用 instanceof 和 isPrototypeOf 可以确定原型和实例的关系:

instance instanceof Object;
Object.prototype.isPrototypeOf(instance);

使用原型链的时候,需要谨慎的定义方法。子类需要重写超类型的某个方法或者扩充,一定要放在替换原型的语句后面,这样才能生效。此外,通过原型链实现继承时,不能使用对象字面量创建原型方法,这样会重写原型链:

......
SubType.prototype = new Super();
SubType.prototype = {
  ....
};

这会更换指针指向新对象,从而重写了原型链。
原型链的继承方法是有缺陷的,主要有两个问题:
1,来自包含引用类型值的原型,会被所有实例共享。
前面文章介绍过包含引用类型值的原型属性会被所有实例共享,一个实例修改,其他实例会随之改变,因此需要在构造函数中定义属性。而原型链继承的时候,无论超类中属性是在构造函数还是原型中定义,全部都变成了实例对象被子类继承,从而对子类的实例产生影响。
2,创建子类型的实例时,不能向超类型的构造函数中传递参数。
原型链的继承,直接将子类原型指向超类的实例,这时候可以向超类传递参数。但是当子类创建实例的时候,只能向子类的构造函数传递参数,而不能向超类的构造函数传递参数。
因此实际应用中,很少单独使用原型链。

相关的一些代码实践

鉴别一个原型属性

function hasPrototypeProperty(object, name) {
  return name in object && !object.hasOwnProperty(name);
}

在构造函数中使用原型对象

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

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

  }
};

var person1 = new Person('Nicholas');
var person2 = new Person('Greg);

console.log(person1 instanceof Person); // true
console.log(person1.constructor === Person); // true
console.log(person1.constructor === Object); // false

console.log(person2 instanceof Person); // true
console.log(person2.constructor === Person); // true
console.log(person2.constructor === Object); // false

对象继承

var person1 = {
  name: 'Nicholas',
  sayName: function () {
    console.log(this.name);
  }
};

var person2 = Object.create(person1, {
  name: {
    configurable: true,
    enumerable: true,
    value: 'Greg',
    writable: true
  }
});

person1.sayName(); // Nicholas
person2.sayName(); // Greg

console.log(person1.hasOwnProperty('sayName')); // true
console.log(person1.isPropertyOf(person2)); // true
console.log(person2.hasOwnProperty('sayName')); // false

模块模式

var person = (function () {
  var age = 25;

  function getAge() {
    return age;
  }

  function growOlder() {
    age++;
  }

  return {
    name: 'Nicholas',
    getAge: getAge,
    growOlder: growOlder
  };
}());

作用域的构造函数

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

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

var person1 = Person('Nicholas');

console.log(person1 instanceof Person); // false
console.log(typeof person1); // undefined
console.log(name); // Nicholas
Javascript 相关文章推荐
angularJS结合canvas画图例子
Feb 09 Javascript
用window.onerror捕获并上报Js错误的方法
Jan 27 Javascript
在页面中输出当前客户端时间javascript实例代码
Mar 02 Javascript
详解Jquery实现ready和bind事件
Apr 14 Javascript
AngularJS使用指令增强标准表单元素功能
Jul 01 Javascript
jQuery中deferred对象使用方法详解
Jul 14 Javascript
js document.getElementsByClassName的使用介绍与自定义函数
Nov 25 Javascript
vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】
Mar 16 Javascript
Vue 嵌套路由使用总结(推荐)
Jan 13 Javascript
vue项目打包后提交到git上为什么没有dist这个文件的解决方法
Sep 16 Javascript
Java 生成随机字符的示例代码
Jan 13 Javascript
vue使用echarts画组织结构图
Feb 06 Vue.js
5个最顶级jQuery图表类库插件【jquery插件库】
May 05 #Javascript
javaScript中的原型解析【推荐】
May 05 #Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
May 05 #Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
May 05 #Javascript
详解Backbone.js框架中的模型Model与其集合collection
May 05 #Javascript
基于jQuery实现动态搜索显示功能
May 05 #Javascript
jQuery插件ajaxfileupload.js实现上传文件
Oct 23 #Javascript
You might like
德生1994机评
2021/03/02 无线电
php 判断访客是否为搜索引擎蜘蛛的函数代码
2011/07/29 PHP
遭遇php的in_array低性能问题
2013/09/17 PHP
php递归创建目录的方法
2015/02/02 PHP
PHPMailer使用QQ邮箱实现邮件发送功能
2017/08/18 PHP
解决laravel上传图片之后,目录有图片,但是访问不到(404)的问题
2019/10/14 PHP
javascript 写类方式之六
2009/07/05 Javascript
浏览器打开层自动缓慢展开收缩实例代码
2013/07/04 Javascript
利用javascript实现web页面中指定区域打印
2013/10/30 Javascript
webapp框架AngularUI的demo改造之路
2014/12/21 Javascript
js带点自动图片轮播幻灯片特效代码分享
2015/09/07 Javascript
谈谈Jquery ajax中success和complete有哪些不同点
2015/11/20 Javascript
jQuery中ajax的load()与post()方法实例详解
2016/01/05 Javascript
JavaScript实战之菜单特效
2016/08/16 Javascript
javascript设计模式之模块模式学习笔记
2017/02/15 Javascript
node文件批量重命名的方法示例
2017/10/23 Javascript
[02:06]2018完美世界全国高校联赛秋季赛开始报名(附彩蛋)
2018/09/03 DOTA
一个基于flask的web应用诞生 使用模板引擎和表单插件(2)
2017/04/11 Python
Python计时相关操作详解【time,datetime】
2017/05/26 Python
Python实现的HMacMD5加密算法示例
2018/04/03 Python
手把手教你使用Python创建微信机器人
2019/04/29 Python
python中时间转换datetime和pd.to_datetime详析
2019/08/11 Python
使用python matplotlib 画图导入到word中如何保证分辨率
2020/04/16 Python
HTML5 Canvas API中drawImage()方法的使用实例
2016/03/25 HTML / CSS
在HTML5 Canvas中放入图片和保存为图片的方法
2014/05/03 HTML / CSS
详解HTML5 录音的踩坑之旅
2017/12/26 HTML / CSS
HTML5中的websocket实现直播功能
2018/05/21 HTML / CSS
Bed Bath & Beyond加拿大官网:购买床上用品、浴巾、厨房电器等
2019/10/04 全球购物
土木建筑学生自我评价
2014/01/14 职场文书
医药类个人求职的自我评价
2014/02/12 职场文书
网络工程师自荐书范文
2014/04/01 职场文书
副董事长岗位职责
2014/04/02 职场文书
乡镇党的群众路线教育实践活动剖析材料
2014/10/09 职场文书
婚礼答谢礼品
2015/01/20 职场文书
2015年学校团委工作总结
2015/05/26 职场文书
2016春季运动会开幕词
2016/03/04 职场文书