有个document里定义了一个函数func(),同时在document里嵌入了一个iframe,在这个iframe里调用父窗口的方法:parent.func(),本来我以为这个函数的运行环境是在这个iframe自己里面,测试发现虽然是在iframe里面调用的这个函数,但是运行环境依然是在父窗口里。
所以也验证了JS权威指南中的:js函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。
又比如
var a=1; function f1(){console.log(a);}; function f2(i){var a=2;f1();} f2();//----1
当代码运行到调用某个函数时,作用域会切换到这个函数自身的作用域里,当这个函数调用完毕会再切换会原来的作用域,这两个作用域链是独立的,一个函数的作用域链由它被定义在哪决定。也正是因为函数运行在它们被定义的作用域里,才导致闭包可用。
本质解释:
ECMA-262标准:
在一个函数被定义的时候, 会将它定义时刻的scope chain链接到这个函数对象的[[scope]]属性。
在一个函数对象被调用的时候,会创建一个活动对象(也就是一个对象), 然后对于每一个函数的形参和局部变量,都命名为该活动对象的命名属性, 然后将这个活动对象做为此时的作用域链(scope chain)最前端, 并将这个函数对象的[[scope]]加入到scope chain中。
比如上例中的f1和f2被定义时,[[scope]]里都只有window对象这一级作用域,
调用f2()时,创建了一个活动对象,这个活动对象包括i和a两个属性,此时f2的[[scope]]包括活动对象和之前的window对象两级作用域;
调用f1()时创建的活动对象是空的。
所以当运行f2()时,能访问到的变量是:{i:undefined,a:2}---->window对象{a:1,f1:...,f2:..., ......},
在f2()里面运行f1()能访问到的变量是:window对象{a:1,f1:...,f2:..., ......},
所以此时访问到的a是属于window对象的,而无法访问到f2作用域链里的局部变量a。