最近看到一个面试题如下:
var x=10; function fn() { console.log(x); } function show(f) { var x=20; (function() { f(); })(); } show(fn); //10
最后的输出结果是10而不是20,是不是很差异,不是有作用域链吗,不是内部函数有权访问外部函数的变量吗,世界怎么了,之前的理论都崩塌了吗??囧。。。
其实不是的,之前的理论没错,只是自己的理解有问题。函数执行时确实是沿着作用域链查找变量的,问题是什么是作用域链?红宝书上的解释:其实作用域链在函数定义时已经确定了,作用域链是和函数定义时的位置相关的。在函数创建的时候创建一个包含外部对象(包括全局对象和所有包含自己的对象)的作用域链,储存在内部[[scope]]属性中。函数执行的时候会创建一个执行环境,通过复制[[scope]]属性中的对象,构建执行环境的作用域链,并把自己的活动对象推向当前作用域链的前端以此形成完整的作用域链。[[scope]]属性中保存的是对可访问变量对象的引用,而不是值得复制。
所以作用域链是和函数创建时的位置相关的:
var x=10; function fn(){ console.log(x); } function show() { var x=20; fn(); } show(); //输出10 ----------------------- var x=10; function show() { var x=20; function fn(){// 这里定义的fn函数,定义时的作用域链已经确定保存在[[Scope]]属性中,包括show函数中的变量对象和全局变量对象 console.log(x); } fn(); } show(); //输出20