变量作用域
变量作用域与提升
传统的
作用域
作用域(Scope)即代码执行过程中的变量、函数或者对象的可访问区域,作用域决定了变量或者其他资源的可见性;计算机安全中一条基本原则即是用户只应该访问他们需要的资源,而作用域就是在编程中遵循该原则来保证代码的安全性。除此之外,作用域还能够帮助我们提升代码性能、追踪错误并且修复它们。
全局作用域
当我们在浏览器控制台或者
// the scope is by default global
const name = "Hammad";
定义在全局作用域中的变量能够被任意的其他作用域中访问:
const name = "Hammad";
console.log(name); // logs 'Hammad'
function logName() {
console.log(name); // 'name' is accessible here and everywhere else
}
logName(); // logs 'Hammad'
函数作用域
定义在某个函数内的变量即从属于当前函数作用域,在每次函数调用中都会创建出新的上下文;换言之,我们可以在不同的函数中定义同名变量,这些变量会被绑定到各自的函数作用域中:
// Global Scope
function someFunction() {
// Local Scope #1
function someOtherFunction() {
// Local Scope #2
}
}
// Global Scope
function anotherFunction() {
// Local Scope #3
}
// Global Scope
函数作用域的缺陷在于粒度过大,在使用闭包或者其他特性时导致异常的变量传递:
const callbacks = [];
// 这里的 i 被提升到了当前函数作用域头部
for (const i = 0; i <= 2; i++) {
callbacks[i] = function () {
return i * 2;
};
}
console.log(callbacks[0]()); //6
console.log(callbacks[1]()); //6
console.log(callbacks[2]()); //6
块级作用域
类似于
const callbacks = [];
for (const i = 0; i <= 2; i++) {
(function (i) {
// 这里的 i 仅归属于该函数作用域
callbacks[i] = function () {
return i * 2;
};
})(i);
}
callbacks[0]() === 0;
callbacks[1]() === 2;
callbacks[2]() === 4;
而在let
关键字达成这一点:
let callbacks = [];
for (let i = 0; i <= 2; i++) {
// 这里的 i 属于当前块作用域
callbacks[i] = function () {
return i * 2;
};
}
callbacks[0]() === 0;
callbacks[1]() === 2;
callbacks[2]() === 4;
词法作用域
词法作用域是
function foo() {
console.log(a); // 2 in Lexical Scope,But 3 in Dynamic Scope
}
function bar() {
const a = 3;
foo();
}
const a = 2;
bar();