【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。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值