作用域是什么?
作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对 变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。赋值操作符会导致 LHS 查询。 的赋值操作。 =操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。
var a; // 声明阶段,在作用域中创建新的变量。在代码执行前声明;
然后执行 a = 3; // 就是进行(LHS),对变量a进行赋值操作;
console.log(a); // 就是(RHS)查询了,会去作用域中查询a变量的值。
举个栗子看看:
function fn(a) {
var b = a + 1;
reutnr a + b;
}
var c = fn(1);
找找里面进行了3次LHS和4次RHS。
- RHS:
fn(1)
查询了一次fn函数; - RHS:
var b = a + 1
查询了变量a; - RHS:
return a + b
查询了变量a; - RHS:
return a + b
查询了变量b; - LHS:
fn(1)
对变量a进行了赋值a = 1; - LHS:
var b = a + 1
对变量b进行了赋值; - LHS:
var c = fn(1)
对变量c进行了赋值。
接下来让我们看看一些异常情况的RHS和LHS
console.log(b); // ReferenceError
let b = 2;
// 如果是使用var声明的话,就不会出现ReferenceError
console.log(a); // undefined
var a = 3;
这就涉及到函数作用域和块级作用域的问题了,那为什么要声明作用域呢?肯定是有什么优势的,作用域有以下几点好处:
- 减少了命名的冲突;
- 增强了代码的复用性;
- 增强了代码的可维护性;
- 增强了代码的可读性;
函数作用域和块级作用域
通常情况下,函数创建就会生出一个作用域,作用域里面的变量无法被函数外面访问,所以函数作用域也起到了一个局部作用域的效果。比如下面一个例子:
var a = 1;
function fn() {
var b = 3;
console.log(b); // 3
}
fn();
console.log(a); // 1
console.log(b); // ReferenceError
上面的写法,就把变量b声明在函数fn内部作用域,全局访问变量b就会报错。
但是函数并不是唯一的作用域单元,作用域指的是一个代码块,可以是一个简单的{...}
。
当然有些情况下他又不是一个作用域,比如:
var a = 4;
if (a === 4) {
var b = 2;
console.log(a); // 4
}
console.log(b); // 2
这个时候if里面包含的{...}
不能算是一个作用域,但是我们也可以使用es6的语法对他进行一点修改,比如:
var a = 4;
if (a === 4) {
let b = 2;
console.log(a); // 4
}
console.log(b); // ReferenceError
这里我们在{...}
里面使用了let
,会声明一个劫持了 if
的 {...}
块的变量,并且将变量添加到这个块 中。
关于闭包的问题我想有了很多人已经讲过了,我就不多做介绍了,只要记住什么情况会产生闭包就行:当函数可以记住并访问所在的词法作用域时,就产生了闭包。
网友评论