详解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中“过于”犀利地for/in循环使用示例
Oct 22 Javascript
如何使用AngularJs打造权限管理系统【简易型】
May 09 Javascript
jQuery中值得注意的trigger方法浅析
Dec 12 Javascript
vue.js  父向子组件传参的实例代码
Oct 29 Javascript
详解封装基础的angular4的request请求方法
Jun 05 Javascript
vue移动端监听滚动条高度的实现方法
Sep 03 Javascript
微信小程序实现tab左右切换效果
Nov 15 Javascript
Angular7.2.7路由使用初体验
Mar 01 Javascript
详解vue移动端项目代码拆分记录
Mar 15 Javascript
百度小程序自定义通用toast组件
Jul 17 Javascript
微信小程序实现图片翻转效果的实例代码
Sep 20 Javascript
利用node.js开发cli的完整步骤
Dec 29 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中的内存管理问题
2011/08/31 PHP
php添加文章时生成静态HTML文章的实现代码
2013/02/17 PHP
PHP的变量类型和作用域详解
2014/03/12 PHP
thinkphp循环结构用法实例
2014/11/24 PHP
twig模板常用语句实例小结
2016/02/04 PHP
CakePHP框架Model函数定义方法示例
2017/08/04 PHP
PHP底层运行机制与工作原理详解
2020/07/31 PHP
THINKPHP5分页数据对象处理过程解析
2020/10/28 PHP
5款Javascript颜色选择器
2009/10/25 Javascript
告诉你什么是javascript的回调函数
2014/09/04 Javascript
jQuery实现统计输入文字个数的方法
2015/03/11 Javascript
Javascript中this关键字的一些小知识
2015/03/15 Javascript
JavaScript实现搜索框的自动完成功能(一)
2016/02/25 Javascript
jQuery基于扩展实现的倒计时效果
2016/05/14 Javascript
js 获取元素所有兄弟节点的实现方法
2016/09/06 Javascript
Vue获取DOM元素样式和样式更改示例
2017/03/07 Javascript
Three.js加载外部模型的教程详解
2017/11/10 Javascript
详解javascript replace高级用法
2019/02/17 Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
2020/07/21 Javascript
原生JavaScript实现换肤
2021/02/19 Javascript
[07:37]DOTA2-DPC中国联赛2月2日Recap集锦
2021/03/11 DOTA
CentOS6.5设置Django开发环境
2016/10/13 Python
利用python获取Ping结果示例代码
2017/07/06 Python
Python中的__slots__示例详解
2017/07/06 Python
3分钟学会一个Python小技巧
2018/11/23 Python
8种用Python实现线性回归的方法对比详解
2019/07/10 Python
Python读取yaml文件的详细教程
2020/07/21 Python
Windows环境下Python3.6.8 importError: DLLload failed:找不到指定的模块
2020/11/01 Python
Python实现钉钉/企业微信自动打卡的示例代码
2021/02/02 Python
HTML5地理定位实例
2014/10/15 HTML / CSS
黑猩猩商店:The Chimp Store
2020/02/12 全球购物
业务助理岗位职责
2013/11/18 职场文书
夫妻双方自愿离婚协议书
2014/10/24 职场文书
办公室文员岗位职责
2015/02/04 职场文书
2015年统战工作总结
2015/05/19 职场文书
决心书格式及范文
2019/06/24 职场文书