global object, global objects, Object object


首先来看global object, 当你在用window对象的时候你所用的就是这个global object, 但是同时也可以说window是global object的一个属性, 这叫做"self referencing".假如用g表示这个global object, 那么 g === window , g.window === g , g.window.window === g ...

global objects就是javascript内置的对象例如Array, Boolean, Date之类的, 虽然一般都称之为object但是typeof其中任何一个得到的都是"function", 所以Array, Date之类的都可以直接当成函数来调用, 那么和普通的函数就没什么区别了例如parseInt:

>>> Array();
    []
>>> parseInt('123');
    123
>>> Date();
    "Sun Feb 26 2012 19:58:59 GMT+0800 (China Standard Time)"

反正javascript里面函数也是对象, 说他们是object也不算错.但是这些对象和普通的函数如parseInt并不完全一样, 例如new一个对象:

>>> var new Array();
    undefined
>>> a
    []
>>> var new parseInt();
    TypeErrorfunction parseInt() { [native code] } is not a constructor

展开这两个函数, 发现了一些区别, Array有一个属性叫做prototype, 里面有一个叫做constructor的函数, Array同时还有一个__proto__属性,里面也有一个叫做constructor的函数, 而parseInt只有一个__proto__, 那么上面错误的意思很明显就是因为parseInt没有prototype.constructor

那么哪样的函数会有prototype.constructor,哪样的函数没有? 当直接用function关键字定义一个函数的时候,这个函数有prototype.constructor:

var func function () {alert('123');}

funcfunction () {alert('123');}
  arguments:null
  ...
  prototypeObject
  __proto__:function Empty() {}

凡是用function定义的函数都会有prototype属性, 可是parseInt没有, 怎样定义一个没有prototype属性的函数?

在ECMA中找到一些描述:

内置的对象中有一些是函数, 可以被调用, 其中一些是constructor , 可以用对其使用new操作符....当一个constructor被作为函数调用的时候,实际调用construcotr的内部的call方法, 而作为new表达式的一部分的时候,用的是其内部的constructor方法.

这说的很清楚, 函数是对象的一种, constructor是函数的一种, 有些函数不是constructor而是普通函数, 显然用function关键字定义的函数都是constructor , 都可以用new表达式.

Array是一个constructor, parseInt是一个普通函数, 这就是区别. 网络上的资料好像没有一个很好的区分这两个概念, 甚至有些地方说每一个js对象都有prototype属性, 这是误导.

目前好像除了global内置的一些普通函数, 在用户的代码中没有办法创建一个不是constructor的函数.

网络上的资料大都不注意这一点, 里面说到的所谓"普通函数","一般函数",构造函数,匿名函数实际上是一回事, 即用function关键字定义的函数, 全部都是constructor. 而这些划分却让人误以为真的有这些不同类型的函数. 划分的标准往往是使用的方式而不是定义的方式, 用来调用的就被划为普通函数,用来new操作的就被划分为构造函数. 好像一杯水, 不管是喝掉还是倒掉, 他都是同一杯水.

原因可能是非constructor的函数根本不可能被用户写出来, 至少目前只在内置函数中见到其身影, 所以当他们谈论普通函数的时候, 谈的其实是constructor, 当他们谈论构造函数的时候,所指的也是constructor.

刚想停笔有又看到一个说法:

在JavaScript中,函数对象对应的类型是Function,正如数组对象对应的类型
是Array,日期对象对应的类型是Date一样, 可以通过new Function()来创建
一个函数对象,也可以通过function关键字来创建一个对象。

这里错的更加离谱, 但是看起来却好像有几分道理. 首先js是一个弱类型的语言, 没有所谓Date类型或者Array类型, 再者, Date Array都是构造函数, 而不是一个类型.

还有一个问题没谈, 那就是Object object, 本质上Object和 Array Date这些内置对象没什么区别也是一个constructor, 但是关于他还是有一些特殊的地方, 下次再讲.

关于Object object的最重要一点就是 Object.prototype.__proto__ === null .

同时要想解释清楚Object object, 还必须搞清楚Function object, Function和Object一样是全局对象的成员, 即内置对象. 但是比Object object更加特殊.

下面的网上的一张图, 不过附带我自己的解释.

看图必须搞清楚3点: 假设有一个对象A

  • 1.A.prototype ,对象的原型, 并不是每个对象都有此属性, 非函数的对象没有, 函数中不能使用new操作符的没有, 所以只有constructor才有这个属性, 有了这个属性才能用new.
  • 2.A.__proto__ , 隐式原型, 每个对象都必有这个属性, prototype也是一个对象,因此prototype也有__proto__. 实际上prototype和__proto__的命名是有问题的, 因为__proto__才是一个对象的原型, 所谓原型就是从别处继承来的, 而prototype也可以叫做原型但不是当前对象的原型, 而被被继承者的原型, A.__proto__ === B.prototype , 这里B.prototype叫做A的原型, 这是原型的真实意义. 当查找原型链的时候是沿着__proto__查找,而不是prototype.
  • 3.A.prototype.__proto__ 之前说过了constructor的prototype也是一个对象, 再加上每个对象都有__proto__, 所以X.prototype.__proto__必然存在. 这是什么? 我们可以称之为prototype的原型, 假设这个prototpe是B的原型, A.prototype.__proto__就是B的原型的原型. 原型链就是B.__proto__.__proto__.__proto__.__proto__.....这样一直追溯, 直到null,这个null就是Object.prototype.__proto__, 可以从上图中任何一个对象出发,沿着这条轨迹追溯, 最后的结果都是这个null.

Function的特殊之处就在于, 如图所示的:Function.__proto__ === Function.prototype.所有其他对象的__proto__都是另外某个对象的prototype, Function的__proto__是他自己的prototype ! 这是很难理解的地方: 一个对象的原型怎么可以是他自己.

每一个constructor, 包括Function本身, 他们的__proto__都指向Function.prototype. 这才应该是constructor的准确定义. 刚才又发现一种类型的函数:不能被调用的函数!

>>> Attr
    function Attr() { [native code] }
>>> typeof(Attr)
    "function"

>>> Attr()
    TypeErrorIllegal constructor
>>> var new Attr();
    TypeErrorIllegal constructor

现在我们有了三种类型的函数:1.可以被调用, 不可以使用new, 没有prototype属性, 2.可以被调用,可以使用new, 有prototype属性, 3.不能被调用, 不能使用new, 有prototype属性.

第4种:不可以被调用, 可以使用new, 有prototype属性.

>>> ArrayBuffer()
    SyntaxErrorDOM object constructor cannot be called as a function.
>>> var bb  new ArrayBuffer();
    undefined
>>> bb
    ArrayBuffer

写这篇文章之前, 真的不知道会有这么多种不同的函数.

看起来DOM好像实现了一个自己的prototype系统, 这里暂不讨论, 继续将Object object讲完.

Function和Object之间形成了一个循环:Function.__proto__.__proto__.constructor.__proto__.constructor->循环. 所有的对象都会继承Object的prototype, 包括Function, 所以说Function继承Object没错, 而Object是由Function构造的, 是一个constructor, 事实上Object的原型就是Function.prototype, 那么Object继承了Function也没有错.

原型链的机制的基础就是Function和Object两个对象的特殊性.