如今的javascript再也不是以前被当做玩具的在网页上运行的花哨的脚本了。javascript已经逐渐标准化,作为一门真正的编程语言广泛地应用在web开发上。因此,越来越多的人开始重新认识这门脚本语言,并在不断地探索关于javascript核心思想和实现原理,过程中遇到了一些非常混淆的问题。本文着重解释一个比较常见但是非常容易使开发人员或者是初学javascript的人非常混淆的问题,那就是两个核心构造函数object和function,他们之间到底有什么关系?为何instanceof运算符的返回结果会让你感到混淆?本文将为你一一道来。不过在这之前,我们需要先了解一些javascript中的概念和基本的运行机制。
javascript的对象体系结构
其实在javascript语言中,整个核心的体系结构都围绕着两个构造函数object和function来构建的。我将引用来自mollypages.org的一张javascript对象体系结构图来说明。
instanceof 运算符
instanceof是一个二元运算符,如:a instanceof b. 其中,a必须是一个合法的javascript对象,b必须是一个合法的javascript函数 (function). 判断过程如下:
如果函数b在对象a的原型链 (prototype chain) 中被发现,那么instanceof操作符将返回true,否则返回false.
例如下面的代码会返回true.
// return true if specified function is found// in the object's prototype chain as a constructor.alert({} instanceof object);
javascript中的原型链(prototype chain)机制
这里简单概括一下,因为这个话题需要很大篇幅去讨论,本文只是引用了这个概念,重点并非详细讨论该机制。
javascript中的原型(prototype)是和函数(function)紧密相连的,因为每个函数默认都会有一个属性叫prototype, 每一个通过函数和new操作符生成的对象都具有一个属性__proto__, 这个属性保存了创建它的构造函数的prototype属性的引用。这个__proto__对象就是实现原型链的核心对象。javascript是一门面向对象的编程语言,它的继承特性其实就是通过原型链机制来实现的。同时,instanceof运算符也需要在原型链的支持。我们举例说明:
代码
复制代码 代码如下:
// create a custom constructor foo
function foo() {
}
// create an insatnce of foo
var foo = new foo();
// foo is an instance of foo
alert(foo instanceof foo);// true
// foo is also an instance of object because
// foo.prototype is an instance of object.
// the interpreter will find the constructor
// through the prototype chain.
alert(foo instanceof object);// true
// prototype chain of the object foo
//
// __proto__ __proto__ __proto__
// foo -----------> foo.prototype -----------> object.prototype -----------> null
// but foo is not an instance of function, because
// we could not find function.prototype in foo's
// prototype chain.
alert(foo instanceof function);// false
// however, its constructor foo is an instance of
// function.
alert(foo instanceof function);// true
// it's also an instance of object
alert(foo instanceof object);// true
// prototype chain of the constructor foo
//
// __proto__ __proto__ __proto__
// foo -----------> function.prototype -----------> object.prototype -----------> null
从上面的代码来分析,我们不难得出这样一个结论:任何对象的原型链最后都能追溯到object.prototype. 这也就是我们为什么说javascript中所有的对象都继承自object的原因了。
为何object instanceof function和function instanceof object都返回true?
object, function, array等等这些都被称作是构造“函数”,他们都是函数。而所有的函数都是构造函数function的实例。从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的function构造函数的构造原型function.protorype对象,所以:
alert(object instanceof function);// return true
与此同时,又因为function.prototype是一个对象,所以他的构造函数是object. 从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的object构造函数的构造原型object.prototype对象,所以:
alert(function instanceof object);// return true
有趣的是根据我们通过原型链机制对instanceof进行的分析,我们不难得出一个结论:function instanceof function 依然返回true, 原理是一样的
1. function是构造函数,所以它是函数对象
2. 函数对象都是由function构造函数创建而来的,原型链机制解释为:函数对象的原型链中存在function.prototype
3. instanceof查找原型链中的每一个节点,如果function.prototype的构造函数function的原型链中被查到,返回true
因此下面代码依然返回true
alert(function instanceof function);// still true
结论
1. 在javascript语言中,一切的一切都是对象,它们全部继承自object. 或者说所有对象的原型链的根节点都是object.prototype
2. 理解原型链机制在javascript中式如何工作的是非常重要的。掌握了它,不管一个对象多么复杂,你总能够轻而易举地将它攻破。