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