JavaScript |吊装
在 JavaScript 中,提升是在代码执行之前将所有声明移动到作用域顶部的默认行为。基本上,它为我们提供了一个优势,即无论函数和变量在何处声明,它们都会被移动到其作用域的顶部,而不管它们的作用域是全局的还是局部的。
它允许我们在将函数写入代码之前调用它们。
注意: JavaScript 只提升声明,而不是初始化。
JavaScript 在执行之前为程序中定义的所有变量和函数分配内存。
让我们了解这到底是什么:
以下是变量声明和初始化发生的顺序。
声明 -> 初始化/分配 -> 使用
// Variable lifecycle
let a; // Declaration
a = 100; // Assignment
console.log(a); // Usage
然而,由于 JavaScript 允许我们同时声明和初始化变量,这是最常用的模式:
let a = 100;
注意:永远记住,Javascript 在后台首先声明变量,然后初始化它们。知道在执行任何代码之前处理变量声明也是一件好事。
但是,在 javascript 中,未声明的变量在执行分配它们的代码之前不存在。因此,将值赋给未声明的变量会在执行赋值时隐式地将其创建为全局变量。这意味着所有未声明的变量都是全局变量。
Javascript
// hoisting
function codeHoist(){
a = 10;
let b = 50;
}
codeHoist();
console.log(a); // 10
console.log(b); // ReferenceError : b is not defined
Javascript
// var code (global)
console.log(name); // undefined
var name = 'Mukul Latiyan';
Javascript
//how interpreter sees the above code
var name;
console.log(name); // undefined
name = 'Mukul Latiyan';
Javascript
//function scoped
function fun(){
console.log(name);
var name = 'Mukul Latiyan';
}
fun(); // undefined
Javascript
//function scoped
function fun(){
var name;
console.log(name);
name = 'Mukul Latiyan';
}
fun(); // undefined
Javascript
//in order to avoid it
function fun(){
var name = 'Mukul Latiyan';
console.log(name); // Mukul Latiyan
}
fun();
Javascript
//let example(global)
console.log(name);
let name='Mukul Latiyan'; // ReferencError: name is not defined
输出:
说明:在上面的代码示例中,我们创建了一个名为 codeHoist() 的函数,其中我们有一个未使用 let/var/const 声明的变量和一个 let 变量 b。未声明的变量由 javascript 分配了全局范围,因此我们可以在函数外部打印它,但是在变量 b 的情况下,范围被限制并且它在外部不可用并且我们得到一个 ReferenceError。
注意: ReferenceError 和未定义的错误是有区别的。当我们有一个未定义或明确定义为未定义类型的变量时,会发生未定义错误。尝试访问以前未声明的变量时会引发 ReferenceError。
ES5
当我们谈论 ES5 时,我们脑海中浮现的变量是 var。与 let/const 相比,使用 var 进行提升有些不同。让我们使用 var 看看提升是如何工作的:
Javascript
// var code (global)
console.log(name); // undefined
var name = 'Mukul Latiyan';
输出:
说明:在上面的代码中,我们试图控制在使用它之后声明和分配的变量名称,编译器给了我们undefined ,这是我们没有预料到的,因为我们应该得到ReferenceError ,因为我们甚至在尝试使用 name 变量之前宣布它。
但是解释器对此的看法不同,上面的代码是这样的:
Javascript
//how interpreter sees the above code
var name;
console.log(name); // undefined
name = 'Mukul Latiyan';
输出:
函数作用域变量
让我们看看函数作用域变量是如何提升的。
Javascript
//function scoped
function fun(){
console.log(name);
var name = 'Mukul Latiyan';
}
fun(); // undefined
输出:
这里没有区别,因为与我们在全局声明变量的代码相比,我们得到 undefined,因为解释器看到的代码是:
Javascript
//function scoped
function fun(){
var name;
console.log(name);
name = 'Mukul Latiyan';
}
fun(); // undefined
输出:
为了避免这个陷阱,我们可以确保在使用它之前同时声明和分配变量。像这样的东西:
Javascript
//in order to avoid it
function fun(){
var name = 'Mukul Latiyan';
console.log(name); // Mukul Latiyan
}
fun();
输出:
ES6
让
我们知道用 let 关键字声明的变量是块作用域而不是函数作用域,因此在提升时这不是任何问题。
例子:
Javascript
//let example(global)
console.log(name);
let name='Mukul Latiyan'; // ReferencError: name is not defined
输出:
像以前一样,对于 var 关键字,我们希望日志的输出是未定义的。然而,由于 es6 let 不善待我们使用未声明的变量,解释器显式地吐出一个引用错误。这确保我们总是首先声明我们的变量。
当涉及到提升时, const的行为类似于 let。