详解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 对象定义方法 简单易学
Mar 22 Javascript
jquery 锁定弹出层实现代码
Feb 23 Javascript
学习JavaScript设计模式之观察者模式
Apr 22 Javascript
jQuery 选择同时包含两个class的元素的实现方法
Jun 01 Javascript
EasyUI的doCellTip实现鼠标放到单元格上提示单元格内容
Aug 24 Javascript
理解AngularJs篇:30分钟快速掌握AngularJs
Dec 23 Javascript
JQ中$(window).load和$(document).ready区别与执行顺序
Mar 01 Javascript
js最简单的双向绑定实例讲解
Jan 02 Javascript
JS中常用的消息框总结
Feb 24 Javascript
vue-router的两种模式的区别
May 30 Javascript
Vue快速实现通用表单验证的方法
Feb 24 Javascript
微信小程序基于ColorUI构建皮皮虾短视频去水印组件
Nov 04 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
ZF等常用php框架中存在的问题
2008/01/10 PHP
php运行出现Call to undefined function curl_init()的解决方法
2010/11/02 PHP
PHP+jQuery+Ajax实现分页效果 jPaginate插件的应用
2015/10/09 PHP
Laravel5.1 框架控制器基础用法实例分析
2020/01/04 PHP
用js脚本控制asp.net下treeview的NodeCheck的实现代码
2010/03/02 Javascript
javascript倒计时功能实现代码
2012/06/07 Javascript
js由下向上不断上升冒气泡效果实例
2015/05/07 Javascript
Bootstrap栅格系统的使用和理解2
2016/12/14 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
2016/12/20 Javascript
基于jQuery实现照片墙自动播放特效
2017/01/12 Javascript
angular实现商品筛选功能
2017/02/01 Javascript
Javascript中数组去重与拍平的方法示例
2017/02/03 Javascript
jQuery返回定位插件详解
2017/05/15 jQuery
vue项目实现github在线预览功能
2018/06/20 Javascript
JS获取指定月份的天数两种实现方法
2018/06/22 Javascript
TypeScript中的方法重载详解
2019/04/12 Javascript
微信小程序实现的一键复制功能示例
2019/04/24 Javascript
在Python中调用ggplot的三种方法
2015/04/08 Python
Python计算三角函数之asin()方法的使用
2015/05/15 Python
Django+Celery实现动态配置定时任务的方法示例
2020/05/26 Python
深入了解Python enumerate和zip
2020/07/16 Python
python修改微信和支付宝步数的示例代码
2020/10/12 Python
python实现银行账户系统
2021/02/22 Python
彪马加拿大官网:PUMA加拿大
2018/10/04 全球购物
Nixon手表英国官网:美国尼克松手表品牌
2020/02/10 全球购物
护士在校生自荐信
2014/02/01 职场文书
机关出纳岗位职责
2014/04/03 职场文书
村容村貌整治方案
2014/05/21 职场文书
毕业生银行实习自我鉴定
2014/10/14 职场文书
2014年世界艾滋病日宣传活动总结
2014/11/18 职场文书
2014年车间工作总结
2014/11/21 职场文书
高中生自我评价范文2015
2015/03/03 职场文书
整脏治乱工作简报
2015/07/21 职场文书
2015年圣诞节寄语
2015/08/17 职场文书
CSS几步实现赛博朋克2077风格视觉效果
2021/06/16 HTML / CSS
Redis入门教程详解
2021/08/30 Redis