📜  JavaScript |吊装

📅  最后修改于: 2022-05-13 01:58:10.626000             🧑  作者: Mango

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。