说说你对javascript的作用域的理解
-
- javascript有全局作用域和函数作用域,全局最大的作用域是script标签包裹的部分,函数作用域可以访问全局作用域的变量,全局作用域不能访问函数作用域的变量。
-
- 全局作用域。这个没啥说的,就是在顶层环境中申明的变量都是全局作用域,他们的属性其实都在window对象下面。
2.函数作用域。在函数内部定义的变量都是函数作用域,只能在函数中访问到,当然也可以通过闭包来访问。除此之外,在其他地方是没法访问函数内部的变量的。 - 局部作用域。es6中新增的特性,弥补了以前只能使用匿名及时运行函数来创建局部变量的缺陷。使用很简单,直接用let来申明变量就行。也可以使用const来申明变量,表明这是常数。
- 作用域链。要说清这个,需要首先明白javascript的代码运行过程。假设现在有个函数funcA,在该函数内部申明了一个局部变量a,在函数内部又定义了一个函数funcB,在函数B中申明了变量b。如下:
function funcA () {
let a;
function funcB () {
let b;
}
}
当进入funcA时,这时候会把变量a压入当前的作用域A中,并且将作用域A入栈,当进入funcB时,则会把变量b压入当前的作用域B中,并且将作用域B入栈,那么这时候栈中就有了作用域A和作用域B,当在funcB中查找某个变量时,会先从当前的作用域B中查找,如果没有的话,那么就根据栈中的作用域依次往上查找,这就是作用域链。
- 全局作用域。这个没啥说的,就是在顶层环境中申明的变量都是全局作用域,他们的属性其实都在window对象下面。
-
补充一下:
- js是使用的词法作用域,所以当代码被加载时作用域已经被限定。
- 作用域只会引用当前作用域用到的 上层作用域的变量 其他没用到的将会随该函数一起推出调用栈
-
在 ES5 之前,javascript 只有函数作用域而没有块级作用域的。即,在
if
或者for
花括号中的变量实际在外层是可以被访问的。for(var i = 0; i < 10; i++){var j=123} console.log(j) // 123;
不过使用 ES6 的
let
和const
之后,就可以实现块级作用域了。而函数作用域通过其作用域链的关系,可以实现变量的封装防止污染。子层的函数可以访问父级以及全局的的变量,但反过来则不行。这样子层函数中的变量就与外层隔绝开了。
var a = 1; function b(){ var b = 2; console.log(a); function c(){ // 内部可以访问外部,而外层访问不到内部 var a = 4; var c = 3; console.log(a); // 4 不会污染 console.log(b); // 2 } c(); } console.log(b()); console.log(a);
-
作用域
作用域是一组规则,决定了一个变量(标识符)在哪里和如何被查找。
查找变量用于赋值,变量是一个 LHS(左手边)引用;查找变量用于取值,变量是一个 RHS(右手边)引用。
LHS 和 RHS 引用查询都从当前执行中的作用域开始,它们会在嵌套的作用域中一路向上,一次一个作用域(层)地查找这个标识符,直到它们到达全局作用域(顶层)并停止,既可能找到也可能没找到。
未找到的 RHS 引用会导致 ReferenceError 被抛出。
未找到的 LHS 引用会导致一个自动的,隐含地创建的同名全局变量(如果不是“Strict模式”),或者一个 ReferenceError(“Strict模式”)。
词法作用域
js采用词法作用域,意味着作用域是由编写时函数被声明的位置决定。编译器的词法分析阶段实质上可以知道所有的标识符是在哪里和如何声明的,并在执行期间预测它们将如何被查询。(例外是eval(),with,不推荐使用)
函数作用域和块作用域
在 JavaScript 中函数是最常见的作用域单位。在另一个函数内部声明的变量和函数,实质上对任何外围“作用域”都是“隐藏的”,这是优秀软件的一个有意的设计原则。
但是函数绝不是唯一的作用域单位。块儿作用域指的是这样一种想法:变量和函数可以属于任意代码块(一般来说,就是任意的 { .. }。
从 ES3 开始,try/catch 结构在 catch 子句上拥有块儿作用域。
在 ES6 中,引入了 let 关键字(var 关键字的表兄弟)允许在任意代码块中声明变量。if (..) { let a = 2; } 将会声明变量 a,而它实质上劫持了 if 的 { .. } 块儿的作用域,并将自己附着在这里。
https://github.com/getify/You-Dont-Know-JS/tree/1ed-zh-CN/scope%20%26%20closures -
- 全局作用域 (哪哪都能访问到)
- 函数作用域(函数内)
- 块级作用域(es2015)
函数作用域内可以访问全局作用域的变量,全局作用域不能访问函数作用域的变量。
函数也不能访问函数内的函数的作用域(闭包)