Javascript之旅 对象的原型链之由来


Posted in Javascript onAugust 25, 2010

以问题开始:

function Base(){}var base = new Base()
上面两行代码会创建几个对象(object)?

要回答这个问题,先明确一下Javascript里object的概念。

Objects

在Javascript里,几乎一切都是object(Arrays、Functions、Numbers、Objects……),而没有C#里的class的概念。object的本质是一个name-value pairs的集合,其中name是string类型的,可以把它叫做“property”,value包括各种objects(string,number,boolean,array,function…),指的是property的值。

typeof

既然object包含Arrays、Functions、Numbers、Objects……,那怎么区分这些呢?答案是typeof。 typeof返回一个字符串,如typeof(Null) = “object”,typeof(false) = “Boolean”, typeof(1) = “number”。既然总是返回字符串,那么对于typeof (typeof x),不管x是什么,总是返回”string”。

Javascript之旅 对象的原型链之由来

Constructor

JS里没有class,也就没有class里的构造函数,那么object是怎么被创建的呢?用构造器:constructor。constructor其实就是Function,因此本身也是object。开头的function Base(){}就是一个构造器,var b = new Base()就是用这个构造器(通过关键字new)创建了一个叫b的object。至此我们可以得出结论,开头的两行代码至少创建了2个object:一个是Base,类型为function的object,一个是base,类型为object的object。

 

Function()和Object()

这是两个重要的预定义好的构造器。一切function(比如开头的Base())都是由Function()构造出来的;而Object的prototype将会被所有object继承,下面会讲到。

Javascript之旅 对象的原型链之由来

 

Function的创建过程

当执行function Base(){this.a = 1}时,相当于var Base = new Function(“this.a = 1”),也就是说,这行代码本身,将使用预定义好的Function() constructor,来构造一个function型object(即Base)出来。在这个创建过程中,js将做哪些事呢?

1, 首先当然会创建一个object起来,Base指向这个object。typeof 这个object = “function”

 Javascript之旅 对象的原型链之由来

2, 给Base附上__proto__属性,让它等于Function这个构造器的prototype(也是预定义好的)。这是很重要的一步,也是规律性的一步。(规律:)在执行任意类似varx = new X()时,都会把X的prototype赋给x的__proto__,也就是说,x.__proto__和X.prototype此时会指向同一个对象。

 Javascript之旅 对象的原型链之由来

3, 为Base创建call属性,该属性是个function。因此我们可以这样写:Base.Call()

 Javascript之旅 对象的原型链之由来

4, 为Base创建Construct属性,该属性也是个function。在执行var base = new Base()时,即会调用这个Construct属性。

5, 为Base创建Scope,Length等属性,略。

6, 为Base创建prototype属性:先用new Object()创建一个对象,为这个对象创建一个属性叫constructor,该属性值设置为Base。再把Base的prototype设置为这个新创建的对象。伪代码如下:

var x = new Object();
x.constructor = Base;
Base.prototype = x;

 

先把关注点放到2和6。

 

__proto__和prototype

从2可以看出来,任意一个用构造器构造出来的object(包括Objects和Functions),都会有__proto__属性,指向该构造器的prototype属性。注意__proto__是个私有属性,在IE上是看不到的,我用的是chrome,可以看到。

从6可以看出,任意一个用new Function()构造出来的functions,都会有prototype属性,该属性是用new Object()构建出来的,初始公开属性只有一个constructor。

Javascript之旅 对象的原型链之由来

 

原型链

再来分析下第6步的伪代码,也就是为function创建prototype的这一步:

var x = new Object(); // 参见2中的规律,会有x.__proto__= Object.prototype。
x.constructor = Base;
Base.prototype = x;

此时我们用Base()构造一个对象出来:

var base= new Base(); // 参见2中的规律,会有base.__proto__ = Base.prototype,也就是 = x。


  // 因此有base.__proto__.__proto__ = x.__proto__

 // 而x.__proto__ = Object.prototype(见上一个代码片段)
 // 所以,base.__proto__.__proto__ = Object.prototype.

__proto__.__proto__,这就是传说中JS对象的原型链!由于用Function()创建构造器时的关键的第6步,保证了所有object的原型链的顶端,最终都指向了Object.prototype。

Javascript之旅 对象的原型链之由来

 

Property Lookup

而我们如果要读某个object的某个属性,JS会怎么做呢?

比如有个object叫xxx,我们执行alert(xxx.a),也就是读取xxx的a属性,那么JS首先会到xxx本身去找a属性,如果没找到,则到xxx.__proto__里去找a属性,由此沿着原型链往上,找到即返回(没找到,则返回undefined)。可以来看个例子:

Javascript之旅 对象的原型链之由来

上图得知:base本身是没有constructor属性的,但是base.constructor确实能返回Base这个函数,原因就在于base.__proto__有这个属性。(base.__proto__是啥?就是Base.prototype,上面构建Function的第6步的伪代码里,为Base.prototype.constructor赋值为Base本身。)

 

Object作为“基类”

另外,由于任意object的原型链的顶端都是Object.prototype。所以,Object.prototype里定义的属性,就会通过原型链,被所有的object继承下来。这样,预定义好的Object,就成了所有对象的“基类”。这就是原型链的继承。

Javascript之旅 对象的原型链之由来

看上图,Object.prototype已经预定义好了一些属性,我们再追加一条属性叫propertyA,那么这个属性和预定义属性一样,都可以从base上读到。

 

原型继承

已经得知,

对于 var xxx =new Object(); 有xxx.__proto__= Object.prototype;

对于 var xxx =new Base(); 有xxx.__proto__.__proto__= Object.prototype;

看上去很像什么呢?从c#角度看,很像Base是Object的子类,也就是说,由Base()构造出来的object,比由Object()构造出来的object,在原型链上更低一个层级。这是通过把Base.prototype指向由Object()创建的对象来做到的。那么自然而然,如果我想定义一个继承自Base的构造器,只需把改构造器的prototype指向一个Base()构造出来的对象。

function Derived(){}
var base = new Base();
Derived.prototype = base;
var d = newDerived(); //很容易推算出:d.__proto__.__proto__.__proto__ = Object.prototype.

推算过程:d.__proto__指向Derived.prototype,也就是base;则__proto__.__proto__指向base.__proto__,也就是Base.prototype,也就是某个new object()创建出来的东东,假设是o;则__proto__.__proto__.__proto__指向o.__proto__,也就是Object.prototype。

 

回答开头的问题,以及几个新的问题

那两行代码至少创建了三个对象:Base、base、Base.prototype。顺便说说,base是没有prototype属性的,只有function类型的object,在被构建时才会被创建prototype属性。

Javascript之旅 对象的原型链之由来

 

d.constructor会返回什么呢?

构造器Base()和Derived()里都是空的,如果有代码,将会怎么被执行呢?

……

待续。见下篇

Javascript 相关文章推荐
从新浪弄下来的全屏广告代码 与使用说明
Mar 15 Javascript
Jquery实现无刷新DropDownList联动实现代码
Mar 08 Javascript
jQuery截取指定长度字符串代码
Aug 21 Javascript
javascript密码强度校验代码(两种方法)
Aug 10 Javascript
在Ubuntu系统上安装Node.JS的教程
Oct 15 Javascript
jQuery UI结合Ajax创建可定制的Web界面
Jun 22 Javascript
第一次接触神奇的Bootstrap导航条
Aug 09 Javascript
使用jQuery的toggle()方法对HTML标签进行显示、隐藏的方法(示例)
Sep 01 Javascript
静态页面实现 include 引入公用代码的示例
Sep 25 Javascript
Angular搜索 过滤 批量删除 添加 表单验证功能集锦(实例代码)
Oct 25 Javascript
js隐式转换的知识实例讲解
Sep 28 Javascript
js动态获取时间的方法分析
Aug 02 Javascript
Javascript new关键字的玄机 以及其它
Aug 25 #Javascript
jquery下组织javascript代码(js函数化)
Aug 25 #Javascript
jquery实现居中弹出层代码
Aug 25 #Javascript
jquery下实现overlay遮罩层代码
Aug 25 #Javascript
在网页中使用document.write时遭遇的奇怪问题
Aug 24 #Javascript
javascript下string.format函数补充
Aug 24 #Javascript
javascript下利用arguments实现string.format函数
Aug 24 #Javascript
You might like
php调用方法mssql_fetch_row、mssql_fetch_array、mssql_fetch_assoc和mssql_fetch_objcect读取数据的区别
2012/08/08 PHP
浅析使用Turck-mmcache编译来加速、优化PHP代码
2013/06/20 PHP
javascript知识点收藏
2007/02/22 Javascript
JavaScript 三种不同位置代码的写法
2009/10/25 Javascript
jQuery实现自动与手动切换的滚动新闻特效代码分享
2015/08/27 Javascript
JavaScript几种数组去掉重复值的方法推荐
2016/04/12 Javascript
webuploader模态框ueditor显示问题解决方法
2016/12/27 Javascript
在百度搜索结果中去除掉一些网站的资料(通过js控制不让显示)
2017/05/02 Javascript
bootstrap警告框示例代码分享
2017/05/17 Javascript
微信小程序组件之srcoll-view的详解
2017/10/19 Javascript
详解VSCode配置启动Vue项目
2019/05/14 Javascript
react+redux仿微信聊天界面
2019/06/21 Javascript
详解JavaScript 的执行机制
2020/09/18 Javascript
python修改字典内key对应值的方法
2015/07/11 Python
Python中扩展包的安装方法详解
2017/06/14 Python
Python正则表达式分组概念与用法详解
2017/06/24 Python
Django渲染Markdown文章目录的方法示例
2019/01/02 Python
Python中字符串与编码示例代码
2019/05/20 Python
selenium处理元素定位点击无效问题
2019/06/12 Python
python使用Thread的setDaemon启动后台线程教程
2020/04/25 Python
python使用requests库爬取拉勾网招聘信息的实现
2020/11/20 Python
CSS3 旋转立方体问题详解
2020/01/09 HTML / CSS
详解CSS3媒体查询响应式布局bootstrap 框架原理实战(推荐)
2020/11/16 HTML / CSS
使用phonegap查找联系人的实现方法
2017/03/31 HTML / CSS
Max&Co官网:意大利年轻女性时尚品牌
2017/05/16 全球购物
帕克纽约:PARKER NY
2018/12/09 全球购物
WEB控件可以激发服务端事件,请谈谈服务端事件是怎么发生并解释其原理?自动传回是什么?为什么要使用自动传回?
2012/02/21 面试题
质量月活动策划方案
2014/03/10 职场文书
旅游管理毕业生自荐信范文
2014/03/19 职场文书
2014年党务工作总结
2014/11/25 职场文书
校运会宣传稿大全
2015/07/23 职场文书
2015年财务人员个人工作总结
2015/07/27 职场文书
思品教学工作总结
2015/08/10 职场文书
pytorch 如何使用float64训练
2021/05/24 Python
只需要100行Python代码就可以实现的贪吃蛇小游戏
2021/05/27 Python
Python实现双向链表
2022/05/25 Python