详解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 相关文章推荐
单独使用CKFinder选择图片的方法
Aug 21 Javascript
Jquery下attr和removeAttr的使用方法
Dec 28 Javascript
关于Javascript与iframe的那些事儿
Jul 04 Javascript
jquery如何通过name名称获取当前name的value值
Dec 20 Javascript
JS脚本defer的作用示例介绍
Jan 02 Javascript
js中window.open()的所有参数详细解析
Jan 09 Javascript
javascript中HTMLDOM操作详解
Dec 11 Javascript
分享一则javascript 调试技巧
Jan 02 Javascript
jQuery动态效果显示人物结构关系图的方法
May 07 Javascript
浅谈react前后端同构渲染
Sep 20 Javascript
详解vue-cli 脚手架 安装
Apr 16 Javascript
微信小程序实现一张或多张图片上传(云开发)
Sep 25 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
在apache下限制每个虚拟主机的并发数!!!!
2006/10/09 PHP
解析php函数method_exists()与is_callable()的区别
2013/06/21 PHP
php生成二维码图片方法汇总
2016/12/17 PHP
php微信公众号开发之图片回复
2018/10/20 PHP
tp5框架前台无限极导航菜单类实现方法分析
2020/03/29 PHP
document.designMode的功能与使用方法介绍
2007/11/22 Javascript
获取URL地址中的文件名和参数的javascript代码
2009/09/02 Javascript
js 强制弹出窗口代码研究-又一款代码
2010/03/20 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
jquery左边浮动到一定位置时显示返回顶部按钮
2014/06/05 Javascript
JavaScript实现向OL列表内动态添加LI元素的方法
2015/03/21 Javascript
javascript显示上周、上个月日期的处理方法
2016/02/03 Javascript
JS引用传递与值传递的区别与用法分析
2018/06/01 Javascript
浅谈angular2子组件的事件传递(任意组件事件传递)
2018/09/30 Javascript
Angular父子组件通过服务传参的示例方法
2018/10/31 Javascript
React路由鉴权的实现方法
2019/09/05 Javascript
[03:12]2016完美“圣”典风云人物:单车专访
2016/12/02 DOTA
Python文件去除注释的方法
2015/05/25 Python
Python自动化测试ConfigParser模块读写配置文件
2016/08/15 Python
python爬取NUS-WIDE数据库图片
2016/10/05 Python
Python中一些不为人知的基础技巧总结
2018/05/19 Python
python3爬取数据至mysql的方法
2018/06/26 Python
Python datetime和unix时间戳之间相互转换的讲解
2019/04/01 Python
教你如何编写、保存与运行Python程序的方法
2019/07/12 Python
python requests更换代理适用于IP频率限制的方法
2019/08/21 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
python实现udp聊天窗口
2020/03/31 Python
澳大利亚珍珠首饰购物网站:Vayo Pearls
2019/03/11 全球购物
土建工程师岗位职责
2014/06/10 职场文书
法制宣传口号
2014/06/16 职场文书
五一口号
2014/06/19 职场文书
2014年置业顾问工作总结
2014/11/17 职场文书
父亲节活动总结
2015/02/12 职场文书
运动会广播稿300字
2015/08/19 职场文书
2016年领导干部廉政承诺书
2016/03/24 职场文书
Python必备技巧之函数的使用详解
2022/04/04 Python