JavaScript中的几个关键概念的理解-原型链的构建


Posted in Javascript onMay 12, 2011

Javascript中所有function中都有一个prototype属性,并且这个prototype属性是一个object类型的对象,所有由该function构造出来的对象都具有这个prototype上的特性,也就是说可以用构造出来的对象直接访问prototype上的属性和方法。
下面一段代码演示prototype的使用方法:

function Staff(name) { 

this.name = name; 

} 

Staff.prototype.say = function() { 

alert(this.name + " say hello"); 

} 

var staff1 = new Staff("hunter"); 

var staff2 = new Staff("dangjian"); 

staff1.say(); 

staff2.say();

运行如上的程序,可知prototype上的属性和方法可以通过创建的对象之间调用,更重要的是prototype中的属性和方法是在同类型的对象中是共享的
alert( staff1.say == staff2.say);

prototype另外一个常用的特性是通过prototype构建对象的继承关系,通过把基类对象赋给子类的prototype的方式可以模拟面向对象中的继承关系,这就是大家经常说的JavaScript的面向对象机制。如下的代码段演示了利用这一特性构建对象的继承关系:

function Staff(name) { // 基类 

this.name = name; 

} 

Staff.prototype.say = function() { 

alert(this.name + " say hello"); 

} 

function ManStaff(name, age) { // 子类 

this.name = name; 

this.age = age; 

} 

ManStaff.prototype = new Staff(); // 建立继承关系 

var manStaff1 = new ManStaff("hunter", 22); 

var manStaff2 = new ManStaff("dangjian", 32); 

manStaff1.say(); 

manStaff2.say();

运行代码可知,ManStaff对象中具有了基类Staff中的Say方法,这种继承方式在JavaScript中是通过prototype链来实现的。大家可能熟悉以上的prototype用法,可是作为程序员,我们不光要知道其用法,我们更应该理解其可是prototype的内部机制。下面我们来分析prototype的原理以及prototype链的实现。
要理解prototype的机制就必须要了解JavaScript中function的创建方式。
当代码执行到function Staff(name) {this.name = name;}时,相当于执行var Staff = new Function(“name”, "this.name = name”)解释器将使用预定义好的Function() constructor,来创建一个function类型的object出来,即Staff。

随后给创建好的Staff对象添加__proto__属性,并赋值为Function的构造器的prototype,这一步是所有对象创建过程中都有的步骤,在执行类似var x = new X()方式是,都会把X的prototype赋值给x的__proto__,类似如下的赋值:

Staff.__proto__ = Function.prototype;

接下来给Staff创建prototype属性,这一步是创建function类型的对象具有的步骤,创建的过程如下伪代码:
var o = new Object(); 

o.constructor = Base; 

Staff.prototype = o;

如上的分析我们可知,当创建对象时,会创建一个私有属性__proto__,当创建function是会创建一个prototype属性。因为Staff是一个function类型的对象,所以会同时具有这两个属性。
这两个属性是构建原型链的关键属性。我们来分析执行代码 var staff1 = new Staff(“hunter”)时,原型是如何传递的。
根据如上分析,staff1.__proto__ = Staff.prototype,而Staff.prototype又是一个由Object创建的对象,即Staff.prototype.__proto__ = Object.prototype,所以staff1.__proto__ .__proto__ 指向的是Object.prototype,即staff1.__proto__ .__proto__ == Object.prototype,这就是原型链,当要读取某个对象的属性时,JS首先找对象本身是否有这个属性,如果没有就会顺着原型链一直寻找这个属性。
知道了原型链的原理,那么就很容易根据这个原理来构建Javascript中的对象继承。
由如上的分析,我们可知原型链的顶端都是Object.prototype,这就意味着在构建的继承关系中Object是所有对象的基类,可以运行如下的代码验证。
Object.prototype.location = "China"; 

function Staff(name) { // 基类 

this.name = name; 

} 

Staff.prototype.say = function() { 

alert(this.name + " say hello"); 

} 

var ManStaff1 = new Staff("hunter"); 

var ManStaff2 = new Staff("dangjian"); 

alert(ManStaff1.location); 

alert(ManStaff2.location);

运行结果知道,Object是Staff的基类,那么要如何构建一个Staff的子类呢?
理解了上面函数的建立原理,我们很容易写出如下的代码:
function Staff(name) { // 基类 

this.name = name; 

} 

Staff.prototype.say = function() { 

alert(this.name + " say hello"); 

} 

function ManStaff(name, age) { // 子类 

Staff.call(this,name); 

this.age = age; 

} 

ManStaff.prototype = new Staff(); // 建立继承关系 

var ManStaff1 = new ManStaff("hunter", 22); 

var ManStaff2 = new ManStaff("dangjian", 32); 

ManStaff1.say(); 

ManStaff2.say();

建立继承关系的就是这句:ManStaff.prototype = new Staff(); ,继承关系推算如下:ManStaff1.__proto__ = =ManStaff.prototype, ManStaff.prototype.__proto__ = Staff.prototype, Staff.prototype.__proto__ == Object.prototype;则ManStaff1.__proto__.__proto__.__proto__ == Object.prototype。
javascript中的这种继承关系比较传统面向对象的继承关系更松散,构建方式也比较难以理解,但是作为脚本语言,其功能已经是非常强大了。
Javascript 相关文章推荐
在myeclipse中如何加入jquery代码提示功能
Jun 03 Javascript
js和jquery设置disabled属性为true使按钮失效
Aug 07 Javascript
Windows下用PyCharm和Visual Studio开始Python编程
Oct 26 Javascript
AngularJS 基础ng-class-even指令用法
Aug 01 Javascript
JS数组去掉重复数据只保留一条的实现代码
Aug 11 Javascript
JS控制页面跳转时未请求要跳转的地址怎么回事
Oct 14 Javascript
html+javascript+bootstrap实现层级多选框全层全选和多选功能
Mar 09 Javascript
JS正则验证多个邮箱完整实例【邮箱用分号隔开】
Apr 19 Javascript
Webpack优化配置缩小文件搜索范围
Dec 25 Javascript
Vue.js特性Scoped Slots的浅析
Feb 20 Javascript
vue实现直播间点赞飘心效果的示例代码
Sep 20 Javascript
vue中实现回车键登录功能
Feb 19 Javascript
Jqyery中同等与js中windows.onload的应用
May 10 #Javascript
JQuery 1.6发布 性能提升,同时包含大量破坏性变更
May 10 #Javascript
JavaScript中为元素加上name属性的方法
May 09 #Javascript
JavaScript 放大镜 移动镜片效果代码
May 09 #Javascript
JavaScript 放大镜 放大倍率和视窗尺寸
May 09 #Javascript
关于JavaScript的with 语句的使用方法
May 09 #Javascript
JavaScript的parseInt 取整使用
May 09 #Javascript
You might like
实用函数3
2007/11/08 PHP
PHP合并数组+与array_merge的区别分析
2010/08/01 PHP
解析PHP跳出循环的方法以及continue、break、exit的区别介绍
2013/07/01 PHP
php实现扫描二维码根据浏览器类型访问不同下载地址
2014/10/15 PHP
PHP从FLV文件获取视频预览图的方法
2015/03/12 PHP
thinkPHP5.0框架自动加载机制分析
2017/03/18 PHP
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
JS 按钮点击触发(兼容IE、火狐)
2013/08/07 Javascript
js获取腾讯视频ID的方法
2016/10/03 Javascript
jquery实现(textarea)placeholder自动换行
2016/12/22 Javascript
js将字符串中的每一个单词的首字母变为大写其余均为小写
2017/01/05 Javascript
详解node+express+ejs+bootstrap构建项目
2017/09/27 Javascript
微信小程序实现简单input正则表达式验证功能示例
2017/11/30 Javascript
react router4+redux实现路由权限控制的方法
2018/05/03 Javascript
vue.js实现的全选与全不选功能示例【基于elementui】
2018/12/03 Javascript
jQuery访问json文件中数据的方法示例
2019/01/28 jQuery
细说webpack6 Babel的使用详解
2019/09/26 Javascript
[50:29]2014 DOTA2华西杯精英邀请赛 5 24 DK VS iG
2014/05/26 DOTA
让python json encode datetime类型
2010/12/28 Python
利用python如何处理nc数据详解
2018/05/23 Python
python实现人民币大写转换
2018/06/20 Python
windows下python虚拟环境virtualenv安装和使用详解
2019/07/16 Python
python 字典 setdefault()和get()方法比较详解
2019/08/07 Python
Python手绘可视化工具cutecharts使用实例
2019/12/05 Python
python wxpython 实现界面跳转功能
2019/12/17 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
Python GUI之tkinter窗口视窗教程大集合(推荐)
2020/10/20 Python
Python中openpyxl实现vlookup函数的实例
2020/10/28 Python
XML文档面试题
2015/08/05 面试题
宝宝周岁宴答谢词
2014/01/26 职场文书
法定代表人授权委托书
2014/04/04 职场文书
2014国庆节餐厅促销活动策划方案
2014/09/16 职场文书
2014院党委领导班子及其成员群众路线对照检查材料思想汇报
2014/10/04 职场文书
团队会宣传标语
2014/10/09 职场文书
2015年党风廉政承诺书
2015/01/22 职场文书
就业推荐表自我评价范文
2015/03/02 职场文书