这是我参与8月更文挑战的第4天,活动详情查看: 8月更文挑战
前言
最近看到同事分享的一个关于作用域的题目,看着挺简单的样子。然后就是hmmmm...我没答对,所以有了这篇文章。
题目大概长这样(我稍微改了下):
console.log(c in window, window.c, typeof c);
console.log(b in window, window.b, typeof b)
{
console.log(c in window, window.c, typeof c);
function c(){};
console.log(c in window, window.c, typeof c);
}
function b() {}
console.log(b in window, typeof b)
我第一感觉答案应该是:
false undefined "undefined"
true f b(){} "function"
true f c(){} "function"
true f c(){} "function"
true "function"
然后在浏览器跑了下,懵了:
我基本上完美的避开了所有的正确答案。
分析
in操作符
这里自己当时傻了,c in window中的c是个变量名,应该要找到它真正对应的值去判断才行。
函数名称保存着函数的引用地址,所以用in操作符会返回false。
但是为啥第一个c in window返回true了,还没想通。按道理函数声明提升不会提升到这一块,也做了下边的测试:
console.log(c in window, window.c, typeof c);
c();
{
function c(){};
}
结果如下:
c函数未定义,符合预期。看表现此时的c应该是undefined
果然c是undefined,但是我们知道,既然函数申明并没有提升到这块作用域,访问c浏览器应该会报错,但为啥是undefined呢??
我们知道ES5中,函数只能申明在顶层作用域和函数作用域中,不能在块级作用域中申明,但是ES6标准中,允许在块级作用域声明函数。在阮大的ECMAScript6入门中提到:针对块级作用域中申明函数的处理,浏览器是不遵守块级作用域的规定,它有自己的方式:
- 允许在块级作用域内申明函数
- 函数声明类似于var,会提升到全局作用域或函数作用域的头部
- 整个函数也会提升到所在块级作用域的头部
所以,上边的c函数就类似于:
var c;
console.log(c in window, window.c, typeof c); //true undefined "undefined"
{
function c(){};
}
函数声明提升
我们知道函数的声明是可以提升到当前函数的作用域的最前边。
所以b函数可以被window访问到,typeof b为‘function’无异议。好了重点来了,代码块中的c函数怎么解释呢??这里的window.c的表现好像跟标准说的不太一样啊~
{
console.log(c in window, window.c, typeof c); // false undefined "function"
function c(){};
console.log(c in window, window.c, typeof c); // false f c(){} "function"
}
在第二次输出的时候看到window.c已经是挂在全局的函数了,那是不是可以块级作用域外边访问呢??
现在块级作用域外也可以访问c函数了,所以为什么呢??暂时我也不知道(存疑)
严格模式
上边代码如果在严格模式下会怎么样呢??
'use strict'
console.log(c in window, window.c, typeof c);
{
console.log(c in window, window.c, typeof c);
function c(){
console.log(111)
};
console.log(c in window, window.c, typeof c);
}
c();
执行结果:
可以看到,严格模式下,函数声明只在块级作用域内部生效。
node环境
console.log(c in global, typeof c);
console.log(b in global) //false
{
console.log(c in global, typeof c);
function c(){
console.log('1111')
};
console.log(c in global, typeof c);
}
c();
function b() {}
console.log(b in global)
运行结果:
符合预期结果,看一下严格模式:
可以看出严格模式下的node是完全遵从ES6标准的,申明在块级作用域的函数只能在块级作用域内访问。