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 相关文章推荐
javascript引用对象的方法代码
Aug 13 Javascript
js实现倒计时(距离结束还有)示例代码
Jul 24 Javascript
js实现使用鼠标拖拽切换图片的方法
May 04 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
Apr 18 Javascript
jQuery实现布局高宽自适应的简单实例
May 28 Javascript
AngularJS自定义服务与fliter的混合使用
Nov 24 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
Apr 13 Javascript
React Native react-navigation 导航使用详解
Dec 01 Javascript
angularjs结合html5实现拖拽功能
Jun 25 Javascript
javascript闭包的使用之按钮切换功能
Aug 30 Javascript
Vue项目部署的实现(阿里云+Nginx代理+PM2)
Mar 26 Javascript
Js实现粘贴上传图片的原理及示例
Dec 09 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
session在php5.3中的变化 session_is_registered() is deprecated in
2013/11/12 PHP
php使浏览器直接下载pdf文件的方法
2013/11/15 PHP
使用PHP实现阻止用户上传成人照片或者裸照
2014/12/25 PHP
php实现的RSS生成类实例
2015/04/23 PHP
PHP模拟QQ登录的方法
2015/07/29 PHP
js计算页面刷新的次数
2009/07/20 Javascript
js实现兼容IE6与IE7的DIV高度
2010/05/13 Javascript
通过DOM脚本去设置样式信息
2010/09/19 Javascript
jQuery在iframe中无法弹出对话框的解决方法
2014/01/12 Javascript
JQuery删除DOM节点的方法
2015/06/11 Javascript
JQuery fileupload插件实现文件上传功能
2016/03/18 Javascript
全面了解函数声明与函数表达式、变量提升
2016/08/09 Javascript
JS实现拖动滚动条评分的效果代码分享
2016/09/29 Javascript
详解在Vue中有条件地使用CSS类
2017/09/30 Javascript
jquery实现购物车基本功能
2019/10/25 jQuery
vue跳转同一个组件,参数不同,页面接收值只接收一次的解决方法
2019/11/05 Javascript
微信浏览器左上角返回按钮监听的实现
2020/03/04 Javascript
Python time模块详解(常用函数实例讲解,非常好)
2014/04/24 Python
理解Python中的With语句
2016/03/18 Python
Python 由字符串函数名得到对应的函数(实例讲解)
2017/08/10 Python
python 日志增量抓取实现方法
2018/04/28 Python
Python利用PyExecJS库执行JS函数的案例分析
2019/12/18 Python
洲际酒店集团英国官网:IHG英国
2019/07/10 全球购物
创意爱尔兰礼物:Creative Irish Gifts
2020/01/29 全球购物
Pandora西班牙官方商店:PandoraShop.es
2020/10/05 全球购物
日本亚马逊官方网站:Amazon.co.jp
2020/04/14 全球购物
写给女生的道歉信
2014/01/08 职场文书
会议开场欢迎词
2014/01/15 职场文书
我们的节日清明节活动方案
2014/03/05 职场文书
圣诞节活动策划方案
2014/06/09 职场文书
新闻报道策划方案
2014/06/11 职场文书
综治工作汇报材料
2014/10/27 职场文书
大学推普周活动总结
2015/05/07 职场文书
2016大学生国家助学贷款承诺书
2016/03/25 职场文书
深度学习小工程练习之垃圾分类详解
2021/04/14 Python
python获取淘宝服务器时间的代码示例
2021/04/22 Python