详解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 相关文章推荐
28个JS验证函数收集
Mar 02 Javascript
原生js 秒表实现代码
Jul 24 Javascript
动态加载script文件的两种方法
Aug 15 Javascript
javascript完美拖拽的实现方法
Sep 29 Javascript
利用javascript实现全部删或清空所选的操作
May 27 Javascript
基于jquery实现简单的分页控件
Mar 17 Javascript
jquery使用Cookie和JSON记录用户最近浏览历史
Apr 19 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
Apr 26 Javascript
JS实现显示带倒影的图片横排居中放大展示特效实例【测试可用】
Aug 23 Javascript
javascript阻止事件冒泡和浏览器的默认行为
Jan 21 Javascript
vue货币过滤器的实现方法
Apr 01 Javascript
vue实现随机验证码功能的实例代码
Apr 30 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(2)
2006/10/09 PHP
php使用ob_start()实现图片存入变量的方法
2014/11/14 PHP
Yii2中YiiBase自动加载类、引用文件方法分析(autoload)
2016/07/25 PHP
PHP CodeIgniter分页实例及多条件查询解决方案(推荐)
2017/05/20 PHP
thinkPHP5框架闭包函数与子查询传参用法示例
2018/08/02 PHP
ECMAScript 基础知识
2007/06/29 Javascript
Javascript Global对象
2009/08/13 Javascript
js最简单的拖拽效果实现代码
2010/09/24 Javascript
JavaScript版TAB选项卡效果实例
2013/08/16 Javascript
jQuery中DOM树操作之复制元素的方法
2015/01/23 Javascript
基于jQuery实现表格内容的筛选功能
2016/08/21 Javascript
angularjs实现首页轮播图效果
2017/04/14 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
微信小程序开发之改变data中数组或对象的某一属性值
2018/07/05 Javascript
如何将HTML字符转换为DOM节点并动态添加到文档中详解
2018/08/19 Javascript
如何从0开始用node写一个自己的命令行程序
2018/12/29 Javascript
vue中$nextTick的用法讲解
2019/01/17 Javascript
详解一个基于react+webpack的多页面应用配置
2019/01/21 Javascript
vue - vue.config.js中devServer配置方式
2019/10/30 Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
2020/07/21 Javascript
Vue实现开关按钮拖拽效果
2020/09/22 Javascript
python实现的一个火车票转让信息采集器
2014/07/09 Python
使用Python开发SQLite代理服务器的方法
2018/12/07 Python
Joie官方网上商店:购买服装和女装配饰
2018/06/05 全球购物
StubHub中国:购买和出售全球活动门票
2020/01/01 全球购物
环境科学专业大学生自荐信格式
2013/09/21 职场文书
护士思想汇报
2014/01/12 职场文书
大学校园毕业自我鉴定
2014/01/15 职场文书
小学教师党员承诺书
2015/04/27 职场文书
高中班长竞选稿
2015/11/20 职场文书
2016应届毕业生自荐信范文
2016/01/28 职场文书
OpenCV-Python实现人脸磨皮算法
2021/06/07 Python
低门槛开发iOS、Android、小程序应用的前端框架详解
2021/10/16 Javascript
vue实现移动端div拖动效果
2022/03/03 Vue.js
Android存储中最基本的文件存储方式
2022/04/30 Java/Android
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL