//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function fn(obj){
return {
//test whether exists a local variable "outerVar" on obj
exists: Object.prototype.hasOwnProperty.call(obj, "outerVar"),
//test the value of the variable "outerVar"
value: obj.outerVar
};
}
var result1 = fn(window);
var outerVar = "WWW";
var result2 = fn(window);
document.write(result1.exists + " " + result1.value); //result: true undefined
document.write("<br />");
document.write(result2.exists + " " + result2.value); //result: true WWWresult1调用的地方,outerVar声明和赋值的语句还没有被执行,但是测试结果window对象已经拥有一个本地属性outerVar,其值为undefined。result2的地方outerVar已经赋值,所以window.outerVar的值已经有了。实际使用中不要出现这种先使用,后定义的情况,否则某些情况下会有问题,因为会涉及到一些规范中没有提及,不同厂商实现方式上不一致的地方。
一些特殊处理
1. with(obj) { ... }这个语法的实现方式,是在当前的Scope Chain最前面位置插入obj这个对象,这样就会先在obj上搜索是否有相应名字的属性存在。其它类似的还有catch语句。
2. 前面对arguments对象的详细说明中,提到了对函数递归调用的支持问题,了解到了匿名函数使用arguments.callee来实现引用自己,而命名函数可以在函数体内引用自己,根据上面Scope Chain的工作原理我们还无法解释这个现象,因为这里有个特殊处理。
任何时候创建一个命名函数对象时,JavaScript引擎会在当前执行上下文Scope Chain的最前面插入一个对象,这个对象使用new Object()方式创建,并将这个Scope Chain传给Function的构造函数[[Construct]],最终创建出来的函数对象内部[[Scope]]上将包含这个object对象。创建过程返回之后,JavaScript引擎在object上添加一个属性,名字为函数名,值为返回的函数对象,然后从当前执行上下文的Scope Chain中移除它。这样函数对象的Scope Chain中第一个对象就是对自己的引用,而移除操作则确保了对函数对象创建处Scope Chain的恢复。
this关键字处理
执行上下文包含的另一个概念是this关键字。
Global Code中this关键字为Global Object;函数调用时this关键字为调用者,例如obj1.fn1(),在fn1中this对象为obj1;Eval Code中this关键字为当前执行上下文的Variable Object。
在函数调用时,JavaScript提供一个让用户自己指定this关键字值的机会,即每个函数都有的call、apply方法。例如:
fn1.call(obj1, arg1, arg2, ...)或者fn1.apply(obj1, argArray),都是将obj1作为this关键字,调用执行fn1函数,后面的参数都作为函数fn1的参数。如果obj1为null或undefined,则Global Object将作为this关键字的值;如果obj1不是Object类型,则转化为Object类型。它们之间的唯一区别在于,apply允许以数组的方式提供各个参数,而call方法必须一个一个参数的给。
前面的测试示例代码中有多处运用到了这个方法。例如window对象并没有hasOwnProperty方法,使用Object.prototype.hasOwnProperty.call(window, "propertyName")也可以测试它是否拥有某个本地属性。
JavaScript中的闭包Closures
示例:
复制代码 代码如下: