在es6 之前,javascript 定义一个变量一直都是使用var
来进行定义的,字es6 之后,javascript 大家才开始使用let
和const
来进行定义变量。在es6 之前的,变量的作用域只有函数作用域和全局作用域。在es6 之后才引入的了块级作用域。
作用域是程序中定义的变量所作用的范围。也就是说我定义了一个变量,我在哪个范围内可以使用,这个范围就是常说的作用域。
就比如说
var a = 12;
function fun () {
var b = 2111;
console.log(a);
console.log(b);
}
fun();
console.log(a);
在上面的代码中,变量a
的作用范围就是全局的,所谓的全局就是在程序的任何地方都是能够使用的,就算我们是在其他的函数内部,也能够使用的。变量b
的作用域是在函数fun的内部,即b只能在函数fun中可以使用,在外面是不能够使用的。因此,我们很轻松就能知道上面的代码输出的结果就是:
12
2111
12
在上面也说了,全局作用域就是:他任何位置使用var声明的的变量,函数除外,那么这个变量就是全局变量,全局变量可以在页面的任何位置使用。就比如说上面这个例子中的变量a
。在网页端,如果页面不关闭,该变量就会一直存在着。也同样会占用着内存,不会进行释放。
关于全局作用域,其实就是说我们在使用var
进行声明的时候,其实是给window
这个对象添加了一个成员a
,我们可以在页面中的任何地方通过window.a
来进行使用这个值,这个变量会跟随window
这个变量一直存在着,直到window
对象销毁,该变量也会随着销毁。
有关函数作用域,上面也说到了,就是在函数内部进行声明的,仅仅可只能在函数内部进行使用的变量,如果在别的地方进行使用,则会报错。我们先看一个例子:
function fun () {
var b = 123;
console.log('inner function value:', b);
}
fun();
console.log('outer function value:', b);
我们将上面的代码贴在浏览器里面,能够看到输出的结果为:
给出的报错内容是变量b
没有进行定义(此定义非undefied)。从上面的实验结果来看,这个变量b
是定义在函数fun内部,如果在函数内部,则可以随便使用。如果跳出来则不能够进行使用。
自es6
以来,引入了块级作用域。所谓的块级作用域也就是所在一个代码块内(即一对花括号内)能够使用,而跳出这个代码块将不能够进行使用(但是在js中由于要兼容老的作用域的规则,因此,使用var
定义的变量在块级之外可能够使用,而使用let
定义的变量在块级之外就不能使用)。就比如说下面这段代码:
{
var _varNum = 123;
let _letNum = 456;
}
console.log('_varNum:', _varNum);
console.log('_letNum:', _letNum);
其输出的结果如下图:
我们看到了在控制台中输出的结果如上图所示,仅仅输出的_varNum
的值,而在输出_letNum
的值的时候却报错了。报错的结果根上面我们在函数外使用在函数内容定义的变量是一样的。
我梦再看一个例子:
var a = 'a';
function fun () {
var b = 'b';
if (true) {
var c = 'c';
let d = 'd';
}
for (var e = 0; e < 0; e++ ) {
}
for (let f = 0; f < 0; f++) {
}
console.log('a:', a); // 输出 a
console.log('b:', b); // 输出 b
console.log('c:', c); // 输出 c
console.log('d:', d); // 报错
console.log('e:', e); // 输出 0
console.log('f:', f); // 报错
}
fun();
在上面的例子中我们看到的输出的结果。可能会有点疑问,为什么会输出变量c
,又为什么不会输出f
呢。当然,对于为什么会输出变量c
,这个很好解释,我们定义通过var
定义的变量c
,虽说这个变量c
是在if
后的一对儿花括号中,但是但是就像我们上面说的一样js中的var
是不具备块级作用域的,因此,这个变量c
的作用域是在函数fun
中的。当然对于为什么输出变量f
的时候报错,是因为定义变量f
是在for
中进行定义的,因此这个变量f
仅仅只作用于这个for
循环中。
首先来确定一下概念相关的内容,什么是变量提升。对于个一个变量,我们在别的语言中(C, C++, C#, java)中,如果想要使用一个变量,必须先声明,然后才能够使用,但是在js中,我们可以先使用,然后再在与该变量相同的作用域中进行声明该变量。这就是变量的提升。举个例子:
console.log(a);
var a = 123;
console.log(a);
在上面的这段代码中,我们先是输出了变量a
,然后在后面进行声明了变量,该代码执行并为报错,反而输出的内容如下:
undefined
123
也就是说,第一次使用的变量是声明过的。
虽说js是存在有变量提升的,但是js并没有存在函数提升,也就是先使用,后声明的函数。如下所示:
fun();
function fun() {
console.log('fun');
}
上面这段代码会在执行的时候报错。
但是对于es6 中的let
和const
来说,是不存在变量提升的概念的,就比如说上面的代码中,我们将定义变量a
的关键字var
换成let
或者是const
则执行的过程中是会报错的。报错的内容就是变量a
未进行声明。接着再来看一个例子。
console.log(a);
function fun() {
console.log(a);
var a = 3333;
}
fun();
var a = 1111;
console.log(a);
fun();
对于这个例子,输出的结果就是
undefined
undefined
1111
undefined
因为在这个例子中,输出第一个为undefined这个我们很好理解,在调用函数fun
的输出中,由于这个函数中有对变量a
的声明,因此在函数调用中输出的变量a
都是限制在函数fun
的作用域中的变量提升。
好了,上面就是我对作用域的一点小小的理解。
原文:https://www.cnblogs.com/ShuiNian/p/11430857.html