Javascript继承机制的设计思想分享


Posted in Javascript onAugust 28, 2011

我一直很难理解Javascript语言的继承机制。

它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。

我花了很多时间,学习这个部分,还做了很多笔记。但是都属于强行记忆,无法从根本上理解。

Javascript继承机制的设计思想分享

直到昨天,我读到法国程序员Vjeux的解释,才恍然大悟,完全明白了Javascript为什么这样设计。

下面,我尝试用自己的语言,来解释它的设计思想。彻底说明白prototype对象到底是怎么回事。其实根本就没那么复杂,真相非常简单。

一、从古代说起

要理解Javascript的设计思想,必须从它的诞生说起。

1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。这是历史上第一个比较成熟的网络浏览器,轰动一时。但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。比如,如果网页上有一栏"用户名"要求填写,浏览器就无法判断访问者是否真的填写了,只有让服务器端判断。如果没有填写,服务器端就返回错误,要求用户重新填写,这太浪费时间和服务器资源了。

Javascript继承机制的设计思想分享

因此,网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。工程师Brendan Eich负责开发这种新语言。他觉得,没必要设计得很复杂,这种语言只要能够完成一些简单操作就够了,比如判断用户有没有填写表单。

Javascript继承机制的设计思想分享

1994年正是面向对象编程(object-oriented programming)最兴盛的时期,C++是当时最流行的语言,而Java语言的1.0版即将于第二年推出,Sun公司正在大肆造势。

Brendan Eich无疑受到了影响,Javascript里面所有的数据类型都是对象(object),这一点与Java非常相似。但是,他随即就遇到了一个难题,到底要不要设计"继承"机制呢?

二、Brendan Eich的选择

如果真的是一种简易的脚本语言,其实不需要有"继承"机制。但是,Javascript里面都是对象,必须有一种机制,将所有对象联系起来。所以,Brendan Eich最后还是设计了"继承"。

但是,他不打算引入"类"(class)的概念,因为一旦有了"类",Javascript就是一种完整的面向对象编程语言了,这好像有点太正式了,而且增加了初学者的入门难度。

他考虑到,C++和Java语言都使用new命令,生成实例。
C++的写法是:

ClassName *object = new ClassName(param);

Java的写法是:

Foo foo = new Foo();

因此,他就把new命令引入了Javascript,用来从原型对象生成一个实例对象。但是,Javascript没有"类",怎么来表示原型对象呢?

这时,他想到C++和Java使用new命令时,都会调用"类"的构造函数(constructor)。他就做了一个简化的设计,在Javascript语言中,new命令后面跟的不是类,而是构造函数。

举例来说,现在有一个叫做DOG的构造函数,表示狗对象的原型。

function DOG(name){

this.name = name;

}

对这个构造函数使用new,就会生成一个狗对象的实例。

var dogA = new DOG('大毛');

alert(dogA.name); // 大毛

注意构造函数中的this关键字,它就代表了新创建的实例对象。

三、new运算符的缺点

用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。

比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species。

function DOG(name){

this.name = name;

this.species = '犬科';

}

然后,生成两个实例对象:

var dogA = new DOG('大毛');

var dogB = new DOG('二毛');

这两个对象的species属性是独立的,修改其中一个,不会影响到另一个。

dogA.species = '猫科';

alert(dogB.species); // 显示"犬科",不受dogA的影响

每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。

四、prototype属性的引入

考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。

这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。

还是以DOG构造函数为例,现在用prototype属性进行改写:

function DOG(name){

this.name = name;

}

DOG.prototype = { species : '犬科' };

var dogA = new DOG('大毛');

var dogB = new DOG('二毛');

alert(dogA.species); // 犬科

alert(dogB.species); // 犬科

现在,species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响到两个实例对象。

DOG.prototype.species = '猫科';

alert(dogA.species); // 猫科

alert(dogB.species); // 猫科

五、总结

由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。

这就是Javascript继承机制的设计思想。不知道我说清楚了没有,继承机制的具体应用方法,可以参考我写的系列文章

Javascript 相关文章推荐
JS 文件传参及处理技巧分析
May 13 Javascript
原生javaScript实现图片延时加载的方法
Dec 22 Javascript
基于javascript实现窗口抖动效果
Jan 03 Javascript
JS设置cookie、读取cookie
Feb 24 Javascript
浅析函数声明和函数表达式——函数声明的声明提前
May 03 Javascript
使用Bootstrap4 + Vue2实现分页查询的示例代码
Dec 21 Javascript
利用adb shell和node.js实现抖音自动抢红包功能(推荐)
Feb 22 Javascript
解决iView中时间控件选择的时间总是少一天的问题
Mar 15 Javascript
在小程序Canvas中使用measureText的方法示例
Oct 19 Javascript
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
May 07 Javascript
Vuex中的Mutations的具体使用方法
Jun 01 Javascript
vue2实现provide inject传递响应式
May 21 Vue.js
有关JavaScript的10个怪癖和秘密分享
Aug 28 #Javascript
JS面向对象编程浅析
Aug 28 #Javascript
用JS实现一个TreeMenu效果分享
Aug 28 #Javascript
JS target与currentTarget区别说明
Aug 28 #Javascript
IE6,IE7,IE8下使用Javascript记录光标选中范围(已补全)
Aug 28 #Javascript
range 标准化之获取
Aug 28 #Javascript
dojo学习第一天 Tab选项卡 实现
Aug 28 #Javascript
You might like
一个目录遍历函数
2006/10/09 PHP
php使用google地图应用实例
2014/12/31 PHP
百度地图经纬度转换到腾讯地图/Google 对应的经纬度
2015/08/28 PHP
WordPress中转义HTML与过滤链接的相关PHP函数使用解析
2015/12/22 PHP
PHP实现基于面向对象的mysqli扩展库增删改查操作工具类
2017/07/18 PHP
jquery 事件执行检测代码
2009/12/09 Javascript
js中escape对应的C#解码函数 UrlDecode
2012/12/16 Javascript
动态的改变IFrame的高度实现IFrame自动伸展适应高度
2012/12/28 Javascript
jquery实现的带缩略图的焦点图片切换(自动播放/响应鼠标动作)
2013/01/23 Javascript
主页面中的两个iframe实现鼠标拖动改变其大小
2013/04/16 Javascript
JavaScript中的索引数组、关联数组和静态数组、动态数组讲解
2014/11/08 Javascript
拥有一个属于自己的javascript表单验证插件
2016/03/24 Javascript
AngularJS使用ng-repeat指令实现下拉框
2016/08/23 Javascript
jquery根据一个值来选中select下的option实例代码
2016/08/29 Javascript
jQuery使用animate实现ul列表项相互飘动效果示例
2016/09/16 Javascript
js实现百度登录框鼠标拖拽效果
2017/03/07 Javascript
原生js简单实现放大镜特效
2017/05/16 Javascript
通过fastclick源码分析彻底解决tap“点透”
2017/12/24 Javascript
vue 监听某个div垂直滚动条下拉到底部的方法
2018/09/15 Javascript
详解Vue CLI 3.0脚手架如何mock数据
2018/11/23 Javascript
JavaScript实现身份证验证代码实例
2019/08/26 Javascript
ES6 class类链式继承,实例化及react super(props)原理详解
2020/02/15 Javascript
Node.js设置定时任务之node-schedule模块的使用详解
2020/04/28 Javascript
javascript中闭包closure的深入讲解
2021/03/03 Javascript
[02:12]2015国际邀请赛 SHOWOPEN
2015/08/05 DOTA
python采用django框架实现支付宝即时到帐接口
2016/05/17 Python
Django使用HttpResponse返回图片并显示的方法
2018/05/22 Python
Django框架下静态模板的继承操作示例
2019/11/08 Python
使用python实现哈希表、字典、集合操作
2019/12/22 Python
Tensorflow实现在训练好的模型上进行测试
2020/01/20 Python
工厂保洁员岗位职责
2013/12/04 职场文书
创建省级文明单位实施方案
2014/02/27 职场文书
施工单位安全责任书
2014/07/24 职场文书
2016寒假假期总结
2015/10/10 职场文书
团支部书记竞选稿
2015/11/21 职场文书
Win10开机修复磁盘错误怎么跳过?Win10关闭开机磁盘检查的方法
2022/09/23 数码科技