详解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 相关文章推荐
看了就知道什么是JSON
Dec 09 Javascript
js 创建快捷方式的代码(fso)
Nov 19 Javascript
jQuery使用CSS()方法给指定元素同时设置多个样式
Mar 26 Javascript
JavaScript Window浏览器对象模型方法与属性汇总
Apr 20 Javascript
最全的Javascript编码规范(推荐)
Jun 22 Javascript
JS实现环形进度条(从0到100%)效果
Jul 05 Javascript
BootStrap中Datepicker控件带中文的js文件
Aug 10 Javascript
javascript实现瀑布流动态加载图片原理
Aug 12 Javascript
JS 实现可停顿的垂直滚动实例代码
Nov 23 Javascript
JS实用的带停顿的逐行文本循环滚动效果实例
Nov 23 Javascript
纯js实现隔行变色效果
Nov 29 Javascript
vuex与组件联合使用的方法
May 10 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
APMServ使用说明
2006/10/23 PHP
PHP校验ISBN码的函数代码
2011/01/17 PHP
PHP无法访问远程mysql的问题分析及解决
2013/05/16 PHP
php实现session自定义会话处理器的方法
2015/01/27 PHP
CodeIgniter与PHP5.6的兼容问题
2015/07/16 PHP
php数据访问之查询关键字
2016/05/09 PHP
JavaScript 学习点滴记录
2009/04/24 Javascript
JQuery select标签操作代码段
2010/05/16 Javascript
基于Jquery的跨域传输数据(JSONP)
2011/03/10 Javascript
jQuery动态添加的元素绑定事件处理函数代码
2011/08/02 Javascript
jQuery渐变发光导航菜单的实例代码
2013/03/27 Javascript
JQuery中$.ajax()方法参数详解及应用
2013/12/12 Javascript
jquery中子元素和后代元素的区别示例介绍
2014/04/02 Javascript
JavaScript观察者模式(经典)
2015/12/09 Javascript
jQuery动态添加及删除表单上传元素的方法(附demo源码下载)
2016/01/15 Javascript
JavaScript的ExtJS框架中数面板TreePanel的使用实例解析
2016/05/21 Javascript
详解Node.js中的事件机制
2016/09/22 Javascript
nodejs 图片预览和上传的示例代码
2017/09/30 NodeJs
使用Vue-Router 2实现路由功能实例详解
2017/11/14 Javascript
Javascript实现秒表倒计时功能
2018/11/17 Javascript
微信小程序云开发实现增删改查功能
2019/05/17 Javascript
vue移动端城市三级联动组件使用详解
2019/07/26 Javascript
vue使用高德地图点击下钻上浮效果的实现思路
2019/10/12 Javascript
js实现图片无缝循环轮播
2019/10/28 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
[01:22:42]2014 DOTA2华西杯精英邀请赛 5 24 DK VS LGD
2014/05/26 DOTA
Tornado Web服务器多进程启动的2个方法
2014/08/04 Python
python合并同类型excel表格的方法
2018/04/01 Python
树莓派+摄像头实现对移动物体的检测
2019/06/22 Python
基于virtualenv创建python虚拟环境过程图解
2020/03/30 Python
python爬虫学习笔记之pyquery模块基本用法详解
2020/04/09 Python
python3判断IP地址的方法
2021/03/04 Python
微软澳洲官方网站:Microsoft Australia
2017/01/10 全球购物
接口的多继承会带来哪些问题
2015/08/17 面试题
最美家庭活动方案
2014/08/31 职场文书
Python实战之实现康威生命游戏
2021/04/26 Python