以问题开始:
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”。
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继承,下面会讲到。
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”
2, 给Base附上__proto__属性,让它等于Function这个构造器的prototype(也是预定义好的)。这是很重要的一步,也是规律性的一步。(规律:)在执行任意类似varx = new X()时,都会把X的prototype赋给x的__proto__,也就是说,x.__proto__和X.prototype此时会指向同一个对象。
3, 为Base创建call属性,该属性是个function。因此我们可以这样写:Base.Call()
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。
原型链
再来分析下第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.