在JavaScript中有函数作用域、全局作用域与块级作用域
1、函数作用域:该作用域中的变量只生存在函数代码块中,但是如果使用隐式声明变量,该变量会成为全局变量,作用域为全局作用域(查看文章中的LHS查询机制就可以明白为什么会变成全局作用域)
2、全局作用域:在代码中隐式声明的变量都会成为全局变量(非严格模式下),可以用window.变量来获取该全局变量
3、块作用域:有人认为JS中没有块作用域(因为在if、for等代码块中声明的变量都是可以在外部进行访问的),其实不然,JS中的with关键字(不建议使用,详情请参考这篇文章中的词法作用域)所创建出来的作用域只能在with声明中而非外部作用域中有效;在JS的ES3规范中规定的try/cathy中的cathy分句会声明块级作用域,在里面所声明的变量只能在cathy内使用;在ES6规范中引入了let关键字,该关键字会将变量绑定在所属的块级作用域
关于作用域中的坑
for循环
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i); //10
},100)
}
上面代码会打印什么?0-9?错了,打印的结果是10个10,因为在定时器开始工作打印时,循环早就结束了,而循环的10个 i 变量使用var声明,都属于同一个作用域,在下一次循环的时候,i 会把前面一个 i 覆盖了,导致最后输出的 i 值为最后一次循环的 i 值;
如何让代码最后输出想要的0-9?最简单的就是把变量 i 用let声明就可以解决了,因为使用let声明的每个变量都有自己会块级作用域,相互之间不受影响,所以后面循环的 i 不会覆盖前面的 i ;
for(let i=0;i<10;i++){
setTimeout(function(){
console.log(i); //0-9
},100)
}
代码块(if关键字创建的代码块也一样)
console.log(test); //undefined
console.log(a); //undefined
{
function test(){
console.log("1231");
}
var a=100;
}
这个涉及到变量提升以及函数提升(提升就是代码在执行前会先查找变量声明以及函数声明,并把它们放在代码块的前面最先解析),因为 { }不属于块级作用域,所以变量提升时,把变量声明放在了外面,所以打印时为undefined,没有不会报错,但是并不能把函数的内容放在 { } 外面,所以函数text也打印了undefined,没有报错,如果把两个打印放在代码块的后面,就可以正常打印了
{
function test(){
console.log("1231");
}
var a=100;
}
console.log(test); //[Function: test]
console.log(a); //100
结束分号与IIFE(立即执行函数)
在JS中,大多数人的习惯都忽略一行程序结束的尾巴( ; ),但是有时候却会产生意想不到的bug
var aa=100
(
function (){
console.log(aa);
}()
)
上面的代码,你会得到什么?得到的是一个错误(100 is not a function),在第一行的末尾没有加上分号,导致编译错误