咱们首先来回顾一下,咱们在客户端浏览器学的关于作用域的东西,回忆一下,作用域有几种当时学的?恩,对,有二种,一种叫全局作用域,一种叫函数作用域,也叫局部作用域:
<script>
var a = 123;//这个变量a是全局级别的作用域
var fn = function(){//函数fn属于全局作用域级下面的函数
//这里是属于局部作用域,下面的a,b变量是属于当前这个局部作用域的变量
var a = 234;
var b = 344;
}
</script>
关于全局作用域的变量或函数使用原则是:”’代码从上往下执行,只要在上面的代码定义过某全局变量或函数,那么在任何地方都可以使用这个全局的变量或函数”’。
关于局部作用域的变量或函数使用原则是:”’当前这个函数被调用或叫被使用的时候,在当前局部作用域里定义的变量可以在当前作用域被使用,超出这个作用域范围之后是访问不到这个变量或函数的”’。
<script>
var a = 100;
var fn = function(){
console.log("fn函数被调用");
}
var fn1 = function(){
var b = 123;
console.log(b);//b是属于当前这个函数级作用域
console.log(a);//在函数级作用域里也可以使用全局变量a
fn();//在函数级作用域里也可以使用全局函数fn
}
fn1();
console.log(b);//会报错,因为我们只有在fn1函数级作用域里定义过变量b
</script>
另外,不是说在局部作用域里定义的变量或函数就一定是属于当前这个作用域,我们还可以通过代理global的全局最大对象window来在局部作用域里面定义全局变量或函数:
<script>
var fn = function(){
window.a = 123;
window.fn1 = function(){
console.log("fn1函数被调用");
}
}
fn();
console.log(a);//结果是123
fn1();
</script>
当然,作用域嵌套作用域的情况又会产生一个好玩的东西叫闭包:
<script>
function fn(a){
var b = 100;
var fn1 = function(){
b++;
console.log(a + b);
}
return fn1;
}
var myFn = fn(100);
myFn();
myFn();
</script>
到此为止咱们就复习完了咱们的客户端浏览器端学习的作用域的知识,现在咱们再继续学一些其他类型的作用域的知识:
咱们来看一下咱们的node.js,在咱们的node.js里面学过一个东西叫模块,模块的思想其实是来源于生活的,咱们在平时的情况下有时候处理一个东西太复杂了,不太好研究,咱们会习惯性的把这个事物这个东西分成一块一块的来研究,最常见的就是比如人,咱们就会把一个人分为免疫系统、血液系统等各个系统,或者像咱们的汽车,咱们会把它分成发动机啊、车胎啊之类的。在咱们的node.js这个平台里面,咱们会把一个js文件(node文件、json文件)当成一个模块。这时候就会出现一种新的作用域叫模块级别的作用域。
然后,除了模块级作用域之外,在ES3和ES5里面,咱们想定义一个变量一般会采用的是:
var a = 100;
但是这样定义一个变量会有问题的,什么情况下会出现问题呢?咱们可以看一下面的这段代码:
"use strict";
if(false){
var a = 1;
}
console.log(a);
虽然if里的条件表达式的值是false,但是咱们打印a却不会报错,结果是undefined,这个原因在这里也不细究了(大家可以复习一下预解析相关的知识点的内容)。
所以,为了避免这个问题,在ES6中就有了一个新的用来定义一个变量的关键字叫let,比如下面的这段代码:
"use strict";
if(false){
let a = 1;
}
console.log(a);
这个时候就会报错,因为这时候不会有一个变量叫a,因为不存在变量作用域提升了。不但如此,咱们再看一段代码如下:
"use strict";
if(true){
let a = 1;
}
console.log(a);
这段代码 也是报错,这个原因就是因为如果用了let关键字以后呢,就会出现一种新的作用域叫块级作用域,块级作用域只会存在于当前这个花括号内部。
块级作用域和let个人觉得最有用的应该是在好多情况下本来需要闭包,现在不需要了,可以简化代码:
"use strict";
for(let i=0;i<5;i++){
setTimeout(function(){
console.log(i);
},100);
}