【Javascript】理解JS中变量及函数作用域的提升

在JavaScript 中,提升(hoisting) 是一个有趣的现象,它指的是变量或函数声明会被移动到它们所在作用域的顶部,在执行前就生效了。这意味着可以在声明之前就使用一个变量或函数。

var 提升变量

通过一个例子我们可以观察到提升行为是如何运作的,比如用 var 声明的变量。看看下面这段代码:

console.log(myVar); // 输出: undefined 

var myVar = 10; 

console.log(myVar); // 输出: 10 

初看之下,你可能会觉得 console.log(myVar) 在声明之前调用会抛出错误,因为此时 myVar 还没有被声明。但是由于提升的存在,myVar 的声明被移到了作用域的顶部,使得这段代码能顺利运行,不会报错。实际上,就像这样写了一样:

var myVar;

console.log (myVar); // 输出: undefined

myVar = 10;

console.log (myVar); // 输出: 10

只有 var myVar 的声明部分被提升了,而赋值语句 myVar = 10 并没有。所以当第一次打印变量时,它的值为 undefined,因为虽然变量名已经被声明了,但它还没有被赋予一个值。

var 的问题

var 存在一个问题是,它的作用域并不是局限于它被声明的那个块内。这可能会导致在循环或者像 if 语句这样的控制结构中出现一些非预期的行为。

if (true) {

    var testVar = "我在块内部";

}

console.log (testVar); // 输出: "我在块内部"

即使 testVar 是在“if 块”内声明的,它也能在外部被使用。正如前面提到的,var 缺乏块级作用域,而是具有函数级或全局的作用域。

使用 letconst 提升

为了克服 var 带来的问题,JavaScript 在 ES6 中引入了 letconst。这些关键字同样会被提升,但有一个显著的区别:它们的实际化是在程序需要变量的时候,也就是当它们的声明语句被执行时。在此之前,这些变量处于暂时性死区(TDZ),如果尝试访问它们会导致 Reference Error

让我们来看个例子:

console.log (myLet); // 参考错误: 在初始化前无法访问 'myLet'

let myLet = 5;

这里,let 被移动到了块的顶部;然而,直到执行到 let myLet = 5 时才对它进行赋值。这意味着尽管变量已经在作用域内——也就是说已经被声明了——但在给它赋值之前不能使用它。

const 也有同样的行为:

console.log (myConst); // 参考错误: 在初始化前无法访问 'myConst'

const myConst = 10;

在这个例子中,const 变量被声明了但没有定义,因此如果脚本试图在定义前使用它,就会抛出 Reference Error

letconst 实现块级作用域

如果你希望一个变量的作用域仅限于某个块内,那么推荐使用 letconst

if (true) {

    let blockVar = "我在块内部";

}

console.log (blockVar); // 参考错误: blockVar 没有被定义

在这个情况下,你只能在它最初声明的那个块内引用 blockVar。一旦试图在 if 块之外访问它,就会导致 Reference Error

函数的提升

JavaScript 中的 函数 也会被提升,但是在它们如何被提升方面,函数声明和函数表达式之间存在差异。

函数声明

对于函数声明来说,函数的名字以及函数体都会被提升到作用域的顶层。因此,即使在声明之前调用函数也是可以的:

Greet(); // 输出: "Hello, world!"

function Greet () {

    console.log ("Hello, world!") ;

}

在这个例子中,Greet 函数的标识符被提升到了最顶部,允许在运行时访问其定义。值得注意的是,函数调用出现在代码中的实际定义之前,但由于提升,这依然可以工作。

函数表达式

函数表达式则不会完全被提升,这意味着如果你试图在一个函数表达式在作用域内定义之前调用它,可能会遇到错误。具体来说,虽然分配函数的变量被提升了,但函数本身并没有。

sayHello (); // 类型错误: say Hello 不是一个函数

var sayHello = function () {
    console.log("Hello!");
};

这段代码表现得好像它是这样写的:

var sayHello;

sayHello (); // 类型错误: say Hello 不是一个函数

sayHello = function () {
    console.log("Hello!");
};

在上面的例子中,var sayHello 的声明被提升到了作用域的顶部。但是当我们尝试执行分配给 sayHello 的函数时,由于此时还没有赋值,就会导致 类型错误。因此,你不能在定义之前调用一个函数表达式。

总结

提升是 JavaScript 中一个有趣的概念,它既可以让你作为 JS 开发者的生活变得更简单,也可能更复杂。理解提升是如何在 varletconst 和函数声明之间工作的可以帮助你避免 JavaScript 代码中的棘手 bug。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值