详解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 相关文章推荐
一句话JavaScript表单验证代码
Aug 02 Javascript
js类的静态属性和实例属性的理解
Oct 01 Javascript
Ext对基本类型的扩展 ext,extjs,format
Dec 25 Javascript
JavaScript判断一个URL链接是否有效的实现方法
Oct 08 Javascript
Jquery.addClass始终无效原因分析
Sep 08 Javascript
js拆分字符串并将分割的数据放到数组中的方法
May 06 Javascript
Bootstrap3.0建站教程(一)之bootstrap表单元素排版
Jun 01 Javascript
jQuery中show与hide方法用法示例
Sep 16 Javascript
angularjs的select使用及默认选中设置
Apr 08 Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
Aug 22 Javascript
解决vue2 在mounted函数无法获取prop中的变量问题
Nov 15 Javascript
解决包含在label标签下的checkbox在ie8及以下版本点击事件无效果兼容的问题
Oct 27 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
VFP与其他应用程序的集成
2006/10/09 PHP
MYSQL数据库初学者使用指南
2006/11/16 PHP
phpmyadmin MySQL 加密配置方法
2009/07/05 PHP
PHP统计目录下的文件总数及代码行数(去除注释及空行)
2011/01/17 PHP
php 求质素(素数) 的实现代码
2011/04/12 PHP
提升PHP性能的21种方法介绍
2013/06/25 PHP
php多用户读写文件冲突的解决办法
2013/11/06 PHP
功能强大的PHP发邮件类
2016/08/29 PHP
PHP面向对象自动加载机制原理与用法分析
2016/10/14 PHP
PHP简单实现循环链表功能示例
2017/11/10 PHP
不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象
2013/01/11 Javascript
js实现的切换面板实例代码
2013/06/17 Javascript
js实现页面跳转重定向的几种方式
2014/05/29 Javascript
有关easyui-layout中的收缩层无法显示标题的解决办法
2016/05/10 Javascript
jQuery 遍历map()方法详解
2016/11/04 Javascript
jquery简单实现纵向的无缝滚动代码实例
2019/04/01 jQuery
利用原生JavaScript实现造日历轮子实例代码
2019/05/08 Javascript
详解node和ES6的模块导出与导入
2020/02/19 Javascript
使用 UniApp 实现小程序的微信登录功能
2020/06/09 Javascript
[01:12](回顾)DOTA2国际邀请赛,全世界DOTAer的盛宴
2014/07/01 DOTA
Python计算程序运行时间的方法
2014/12/13 Python
python函数形参用法实例分析
2015/08/04 Python
python使用xpath中遇到:到底是什么?
2018/01/04 Python
对Python 多线程统计所有csv文件的行数方法详解
2019/02/12 Python
Python文件路径名的操作方法
2019/10/30 Python
Python类super()及私有属性原理解析
2020/06/15 Python
Python将字典转换为XML的方法
2020/08/01 Python
英国健身专家:WIT Fitness
2021/02/09 全球购物
什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?
2013/05/03 面试题
自考自我鉴定范文
2013/10/30 职场文书
英语系毕业生自荐信
2013/10/31 职场文书
教师党员思想汇报
2014/01/06 职场文书
寻找最美家庭活动方案
2014/08/20 职场文书
党支部季度考核意见
2015/06/02 职场文书
旅行社计调工作总结
2015/08/12 职场文书
Win10防火墙白名单怎么设置?Win10添加防火墙白名单方法
2022/04/06 数码科技