深入浅析javascript继承体系


Posted in Javascript onOctober 23, 2017

最近做web项目,接触了jquery等框架,虽然使用方便,但是还是想学习下Javascript,今天分享下最近对js原型继承的理解,不足之处欢迎指正。

一、构造器的原型属性与原型对象

刚接触js时通常依样画瓢,用函数new一个实例,也不知道其原因,只听说js中函数即对象。原来js中没有采用Java等语言中的类继承体系,而是使用原型对象(prototype)实现继承体系,具体说是利用“构造器”实现类的功能。

首先解释下原型继承中的两个重要概念:原型属性、原型对象(实例)。

就js对象系统而言,创建的每个函数(构造器)都有一个prototype原型属性,同时,通过构造器创建的每个对象实例也包含一个_proto_属性,prototype和_proto_属性是一个指针,指向原型对象。普通函数与构造函数的唯一区别就是,其原型属性prototype是不是一个有意义的值。

原型属性prototype所指向的原型是一个对象实例(Object instance)。具体如下图所示,若构造器Animal()有一个原型对象B,则由该构造器创建的实例都必然复制于B。即:Animal()的实例a1的_proto_属性也会指向原型对象B。因此,实例a1能够继承B的所有属性、方法和其他性质。

深入浅析javascript继承体系

图1 js对象实例化实现

二、空的对象

在javascript中,“空的对象”是整个原型继承体系的根基,是所有对象的基础。介绍“空的对象”之前,必须先介绍下“空对象(null)”。

空对象null

null不是“空的对象”,作为javascript中的一个保留字,其含义是:

(1)属于对象类型

(2)对象是空值

作为一个对象类型,可以使用for…in去列举它,但是作为一个空值,null没有任何方法和属性(包括constructor、_proto_等属性),因此列举不到任何内容。如下例所示:

var num=0;
for(var propertyName in null)

{

num++;

}

Alert(num);//显示值为0

最重要的一点是null没有原型,它并不是自Object()构造器(或其子类)实例化而来,对其进行instanceof 运算会返回false。

2.“空的对象”

“空的对象”是指一个标准的、通过Object()构造的对象实例。例如:

obj=new Object();或 obj={};

“空的对象”具有“对象”的一切特性,因此可以存取toString()、valueof等预定义的属性和方法。

3.“空的对象”与null的关系

如下图2中红线所示路径,当通过”Object.prototype._proto_”获取Object原型对象的-proto-属性时,将会得到”null”,由于null对象没有任何属性,也就是说”Object {}”

原型对象就是原型链的终点了。

深入浅析javascript继承体系

图2 js类继承体系

三、Javascript继承的实现以及原型链维护

(1)继承的实现

第一节说过javascript中类继承是通过修改构造函数的原型属性prototype实现的。如下代码所示:

function Animal() {
this.name = 'Animal';
};
function Dog() {
};
Dog.prototype = new Animal();
var d = new Dog();
console.log(d.name);//'Animal'

通过创建一个Animal类型的实例并将其赋值给构造函数Dog()的prototype属性,从而实现类型继承,即Animal是Dog的父类。这样Dog类型的实例d也能访问Animal类型的name属性。

(2)原型链

JS对象继承体系中有两种原型链:“内部原型链”和“构造器原型链”。如图3所示,黑色箭头指示路径是通过构造函数的prototype属性保持的“构造器原型链”。红色箭头指示路径是通过对象实例的_proto_属性保持的“内部原型链”。

深入浅析javascript继承体系

图3 原型链

(3)原型链维护

图3说明构造器通过显示的prototype构建了一个原型链,而对象实例也通过_ proto _属性构建了一个原型链。由于_ proto _是一个不可访问的内部属性(Chrome中可以查看对象_ proto _属性的值,但不可以修改),因此无法从子类(Dog)的实例dog1开始访问整个原型链。因此,我们需要从图3中的“内部原型链”和“构造器原型链”中找到一个连接点,使得实例不能访问obj._proto_的情况下通过构造器访问内部原型链(将两种原型链串联起来)。

若要从子类的实例开始访问整个原型链,需要使用实例的constructor属性维护原型链。

其实,JavaScript已经为构造器维护了原型属性,根据如下测试代码,当我们自定义一个构造器时,其原型对象是一个Object()类型的实例,但是其原型对象的constructor属性默认总是指向构造器自身,而非指向其父类Object。如图4中构造器实例中蓝色框中的constructor属性,该constructor属性继承自原型对象,因此可以得出一个自定义的构造器产生的实例,其constructor属性默认总是指向该构造器。

function Animal() {
};
var a = new Animal();
console.log(Animal.prototype);//Object(){}
console.log(Animal.prototype.constructor === Animal);//true//true

深入浅析javascript继承体系

图4

因此,在_proto_属性不可访问时,可通过a1.constructor.prototype获取实例a1的原型对象。然而,当我们自定义一个构造函数Dog(),并且手动指定其prototype属性值为Animal,即指定Dog的父类为Animal。此时访问d1.constructor值为Animal,而不是Dog;由图5可以看出,Dog的原型对象和dog分别由Animal()和Dog()两个不同的构造器产生,然而他们的constructor属性指向了相同的构造器(Animal),这样就与使用constructor属性串联两种原型链的设想冲突了。

深入浅析javascript继承体系

图5

是构造器出问题还是原型出了问题?图5可以看出,原型继承要求的“复制行为”已经正确实现,能够从子类实例中访问原型对象属性,问题是在给子类构造器Dog()赋予一个原型对象时应该“修正”该原型对象的构造属性值(constructor)。ECMAScript 3标准提供的方法是:保持原型的构造器属性,在子类构造器中初始化其实例对象的构造属性。代码如下: 

function Dog () {
//初始化constructor属性

 this.constructor=Dog; //或 this.constructor=arguments.callee;

};

Dog.prototype = new Animal();//赋予原型对象,实现继承

深入浅析javascript继承体系

图6

对constructor属性“修正”后效果如图6所示,在子类构造器Dog中初始化其实例对象的constructor属性后,Dog的实例对象的constructor都指向Dog,而Dog的原型对象的constructor仍然指向父类型构造器Animal。这样就可以实现利用constructor属性串联起原型链,可以从子类实例开始回溯整个原型链。

总结

以上所述是小编给大家介绍的javascript继承体系的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Prototype1.6 JS 官方下载地址
Nov 30 Javascript
url 特殊字符 传递参数解决方法
Jan 01 Javascript
理解Javascript_13_执行模型详解
Oct 20 Javascript
基于Jquery+Ajax+Json的高效分页实现代码
Oct 29 Javascript
js调用css属性写法
Sep 21 Javascript
JavaScript设置首页和收藏页面的小例子
Nov 11 Javascript
JavaScript实现跨浏览器的添加及删除事件绑定函数实例
Aug 04 Javascript
js实现适用于素材网站的黑色多级菜单导航条效果
Aug 24 Javascript
JavaScript事件详细讲解
Jun 27 Javascript
详解基于Node.js的HTTP/2 Server实践
May 31 Javascript
Node.js HTTP服务器中的文件、图片上传的方法
Sep 23 Javascript
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
Nov 20 Vue.js
Vue.js组件通信的几种姿势
Oct 23 #Javascript
Vue2.0+ElementUI实现表格翻页的实例
Oct 23 #Javascript
JavaScript之创意时钟项目(实例讲解)
Oct 23 #Javascript
浅谈js的解析顺序 作用域 严格模式
Oct 23 #Javascript
基于Vue2.0+ElementUI实现表格翻页功能
Oct 23 #Javascript
React操作真实DOM实现动态吸底部的示例
Oct 23 #Javascript
利用pm2部署多个node.js项目的配置教程
Oct 22 #Javascript
You might like
windows xp下安装pear
2006/12/02 PHP
php实现自动获取生成文章主题关键词功能的深入分析
2013/06/03 PHP
PHP 验证登陆类分享
2015/03/13 PHP
PHP中$_SERVER使用说明
2015/07/05 PHP
PHP XML Expat解析器知识点总结
2019/02/15 PHP
一个加密JavaScript的开源工具PACKER2.0.2
2006/11/04 Javascript
JSONP 跨域访问代理API-yahooapis实现代码
2012/12/02 Javascript
缓动函数requestAnimationFrame 更好的实现浏览器经动画
2012/12/07 Javascript
JavaScript栏目列表隐藏/显示简单实现
2013/04/03 Javascript
JS保存、读取、换行、转Json报错处理方法
2013/06/14 Javascript
jQuery在线选座位插件seat-charts特效代码分享
2015/08/27 Javascript
jQuery实现仿美橙互联两级导航菜单效果完整实例
2015/09/17 Javascript
JS简单去除数组中重复项的方法
2016/09/13 Javascript
JavaScript队列、优先队列与循环队列
2016/11/14 Javascript
JavaScript实现移动端轮播效果
2017/06/06 Javascript
laydate日历控件使用方法详解
2017/11/20 Javascript
JavaScript实现更换背景图片
2019/10/18 Javascript
jQuery+PHP+Ajax实现动态数字统计展示功能
2019/12/25 jQuery
node.js 微信开发之定时获取access_token
2020/02/07 Javascript
ES6 Iterator遍历器原理,应用场景及相关常用知识拓展详解
2020/02/15 Javascript
[01:34]DAC2018主赛事第四日五佳镜头 Gh巨牙海民助Miracle-死里逃生
2018/04/07 DOTA
Python自定义进程池实例分析【生产者、消费者模型问题】
2016/09/19 Python
Python学习思维导图(必看篇)
2017/06/26 Python
Python2与python3中 for 循环语句基础与实例分析
2017/11/20 Python
用python做游戏的细节详解
2019/06/25 Python
python验证码图片处理(二值化)
2019/11/01 Python
Python values()与itervalues()的用法详解
2019/11/27 Python
CSS3弹性伸缩布局之box布局
2016/07/12 HTML / CSS
美国专业消费电子及摄影器材网站:B&H Photo Video
2019/12/18 全球购物
个人实用简单的自我评价
2013/10/19 职场文书
自荐信要包含哪些内容
2013/11/06 职场文书
安全协议书
2014/04/23 职场文书
甜品蛋糕店创业计划书
2014/09/21 职场文书
招商引资工作汇报材料
2014/10/28 职场文书
中学总务处工作总结
2015/08/12 职场文书
安全责任协议书范本
2016/03/23 职场文书