详解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 相关文章推荐
动态加载script文件的两种方法
Aug 15 Javascript
js实现数组去重、判断数组以及对象中的内容是否相同
Nov 29 Javascript
javaScript对文字按照拼音排序实现代码
Dec 27 Javascript
javascript动态创建及删除元素的方法
Dec 22 Javascript
JS建造者模式基本用法实例分析
Jun 30 Javascript
jQuery插件EasyUI校验规则 validatebox验证框
Nov 29 Javascript
js 中获取制定的cook信息实现方法
Nov 19 Javascript
JSON键值对序列化和反序列化解析
Jan 24 Javascript
javascript 单例模式详解及简单实例
Feb 14 Javascript
详谈表单重复提交的三种情况及解决方法
Aug 16 Javascript
Vue组件间数据传递的方式(3种)
Jul 13 Javascript
vue 出现data-v-xxx的原因及解决
Aug 04 Javascript
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
PHP使用静态方法的几个注意事项
2014/09/16 PHP
浅谈PHP中的数据传输CURL
2016/09/06 PHP
laravel5.0在linux下解决.htaccess无效和去除index.php的问题
2019/10/16 PHP
ASP Json Parser修正版
2009/12/06 Javascript
Prototype源码浅析 Enumerable部分之each方法
2012/01/16 Javascript
动态的改变IFrame的高度实现IFrame自动伸展适应高度
2012/12/28 Javascript
javascript之Partial Application学习
2013/01/10 Javascript
jQuery实现下拉框左右选择的简单实例
2014/02/22 Javascript
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
jQuery 选择器(61种)整理总结
2016/09/26 Javascript
Vue中添加手机验证码组件功能操作方法
2017/12/07 Javascript
Windows下Node爬虫神器Puppeteer安装记
2019/01/09 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
[44:50]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 TNC vs VG
2018/04/02 DOTA
Python random模块常用方法
2014/11/03 Python
python追加元素到列表的方法
2015/07/28 Python
Python OpenCV中的resize()函数的使用
2019/06/20 Python
Python基于stuck实现scoket文件传输
2020/04/02 Python
Python内存映射文件读写方式
2020/04/24 Python
Python实现CAN报文转换工具教程
2020/05/05 Python
对python中list的五种查找方法说明
2020/07/13 Python
matplotlib.pyplot.plot()参数使用详解
2020/07/28 Python
python os.listdir()乱码解决方案
2021/01/31 Python
python如何发送带有附件、正文为HTML的邮件
2021/02/27 Python
HTML5 声明兼容IE的写法
2011/05/16 HTML / CSS
环境工程大学生自荐信
2013/10/21 职场文书
策划助理岗位职责
2013/11/18 职场文书
分厂厂长岗位职责
2013/12/29 职场文书
学生党支部先进事迹
2014/02/04 职场文书
干部作风建设年活动剖析材料
2014/10/23 职场文书
事业单位个人查摆问题及整改措施
2014/10/28 职场文书
2015年质检工作总结
2015/05/04 职场文书
新兵入伍决心书
2015/09/22 职场文书
2016大学生国家助学贷款承诺书
2016/03/25 职场文书
Python编写nmap扫描工具
2021/07/21 Python
Go并发4种方法简明讲解
2022/04/06 Golang