作用域指的是一个变量的生命周期,也就是说,在代码中它是可见的。
在es5以前,是没有块级作用域的概念的,在es6中才引入进来的,在传统的java和c++中块级作用域是包裹在{ }里面的代码{//这里面的是块级作用域}复制代码
==//这边不是块级作用域==
以上所示是其他语言的块级作用域,以上可知,声明一个变量在块中,只能在块中可见和其他内嵌的块中可见
但是在es5中,只有两种作用域,就是全局作用域和函数作用域,所以,如果写
{ var a = "block";}console.log(a); //block复制代码
以上可以看出,变量a存在于全局范围内,所以作用范围也在全局。
在es5中,除了全局作用域,就是函数作用域了
function hello() { var a = "function";}hello();console.log(a); //a is not defined复制代码
报错是因为a变量声明在函数内部,所以作用范围只在函数内部,但是如果在函数体内部加上for循环的话
function hello() { var a = "function"; for (var i = 0; i < 10; i++) { var a = "block"; } console.log(a);}hello(); //block复制代码
没有块级作用域,但是有很多替代方案,大部分都是用闭包的原理,比如以下其中一种方案
==IIFE(Immediately Invoked Function Expression)自执行函数==function hello() { var a = "function"; for (var i=0; i<5; i++) { (function() { var a = "block"; })(); } console.log(a);}hello(); //function复制代码
以上就会打印出function
在es5中,使用块级作用域特别麻烦,直到es6中出现了let块级元素,可以用简短的写法就解决以上问题,同样上面的例子我们可以写为
function hello() { var a = "function"; for (var i = 0; i < 5; i++) { let a = "block"; } console.log(a);}hello(); //function复制代码
现在,for循环体中声明的a只存在于{ }里面,上面的代码片段按预期打印出函数。
在循环中使用letvar funcs = [];for (var i = 0; i < 5; i += 1) { var y = i; funcs.push(function () { console.log(y); })}funcs.forEach(function (func) { func() //4 4 4 4 4});复制代码
以上例子我们本来想输出0 1 2 3 4的,结果....当然也可以使用IIFE,但是那样太麻烦了,而使用let
var funcs = [];for (var i = 0; i < 5; i += 1) { let y = i; funcs.push(function () { console.log(y); })}funcs.forEach(function (func) { func()});复制代码
就直接得到了想要的结果0 1 2 3 4 以上无非就是想输出0 1 2 3 4,其实还有更简单的方法
var funcs = [];for (let i = 0; i < 5; i += 1) { funcs.push(function () { console.log(i); })}funcs.forEach(function (func) { func()});复制代码
上面在循环中声明i,所以i的作用域在循环内部,具体解释起为什么,还得涉及到域解析的过程; 还得注意的是let声明方式不能重复声明,如:
let a=10;let a=20;复制代码
这样会报错Identifier 'a' has already been declared