JavaScript变量提升(Hoisting)详解
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JavaScript变量提升(Hoisting)详解,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4644字,纯文字阅读大概需要7分钟。
内容图文
![JavaScript变量提升(Hoisting)详解](/upload/InfoBanner/zyjiaocheng/719/75789a0661c04fc5983a83199e2d4d8d.jpg)
文章出自个人博客https://knightyun.github.io/2019/09/02/js-hoisting,转载请申明。
概念
变量提升是 JavaScript 的一种执行机制,大致就是字面意思,将声明的变量提前,但并不是指在编译时改变语句的顺序,而是将变量提前放入内存中,供后续操作,下面通过实例进行分析;
函数申明
在 JavaScript 中,声明一个函数并执行的话,通常会是以下形式:
function fn() {
console.log('run');
}
fn(); // run
上面是正常的思维顺序,但是包括其他一些编程语言在内,通常会使用如下形式:
fn();
function fn() {
console.log('run');
}
// run
这样做在执行上是没用问题的,同时可以在包含大量语句和函数申明的情况下,也可以使用这种特性将普通语句和函数申明分开,提高可读性;
以上情况便是一种常见的提升(Hoisting),即编译时提前将当前执行上下文包含的申明的函数,提前放入内存中,供全文语句执行时调用,为了方便理解而抽象成一种提升行为;
但是如果使用下面的方式申明函数并执行:
fn();
var fn = function() {
console.log('run');
}
// TypeError: fn is not a function
这里就没有像上面一样的结果了,这属于下面将介绍的变量提升行为;
变量申明
当然函数只是一种类型的变量,还存在其他的变量类型,例如考虑以下语句:
var a = 1;
console.log(a);
// 1
逻辑和执行都是正常的,输出结果也是预期的,但是如果变一下顺序:
console.log(a);
var a = 1;
这种情况,通常可能会认为第一行调用了一个未定义的变量,然后输出 Uncaught ReferenceError: a is not defined
这样的错误,但是呢,并非如此,输出信息如下:
undefined
没错,就只有一个单独的 undefined
,这种输出情况就类似于以下代码的执行:
var a;
console.log(a);
// undefined
从这里便可以大致分析出,前面的顺序怪异的代码,相当于在编译时提前将后面出现的变量申明提前,然后执行就输出了一个已申明但未 初始化(赋值) 的值,这便是其他类型的变量的提升行为,即在当前执行上下文中,将后面申明的变量提前放入内存,供前面的语句调用;
注意,前面的代码最后一行的语句是 var a = 1
,即对变量进行了申明并赋值,但是最后输出仍然是 undefined
而不是 1
,证明变量提升行为只会对变量进行申明操作,并不会对其初始化赋值,不管原语句是否有赋值操作;
然后便能解释之前的代码:
fn();
var fn = function() {
console.log('run');
}
// TypeError: fn is not a function
这种情况便是将变量 fn
提升,值为 undefined
,所以执行 fn()
语句会提示 fn is not a function
而不是 fn is not defined
,与使用关键字 function
申明函数情况不一样;
var, let, const的区别
JavaScript 中申明变量的方式以及对应效果如下:
a = 0; // 全局变量
var b = 1; // 局部作用域变量(当前上下文)
let c = 2; // 块级作用域变量(当前块级上下文)
const d = 3; // 常量
作用域
这里解释一下,变量 a 申明时没有带任何关键字,默认其为全局变量;变量 b 申明带有关键字 var
,为当前上下文的局部作用域,如果用在全局则为全局变量;变量 c 使用关键字关键字 let
,d 使用关键字 const
,二者都是ES6中新增的块级作用域申明,只不过 const
申明的是常量,值不可更改;
通过例子看一下它们的区别;
var a = '全局';
function fn() {
var aa = '局部'
console.log(aa);
}
if (true) {
var b = '全局';
let bb = '块级';
const bbb = '块级';
}
for (i = 0; i < 1; i++) {
var c = '全局'
let cc = '块级';
const ccc = '块级';
}
console.log(a); // “全局”
fn(); // “局部”
console.log(aa); // aa is not defined
console.log(b, c); // “全局” “全局”
console.log(bb, cc); // bb is not defined cc is not defined
console.log(bbb, ccc); // bbb is not defined ccc is not defined
可以看出,var 的局部限于全局或者函数内部上下文,而 let 和 const 的块级的意思则是被 块(block) 所包含的上下文,也就是包含在花括号 {}
内部的作用域中,所以也包括函数在内,加上 if, for, while, switch 等情况,且不能被外部作用域访问;
全局变量提升
首先看申明全局变量时的提升行为:
console.log(a);
a = 0;
// ReferenceError: a is not defined
证明不带关键字的申明全局变量,似乎并没有执行变量的提升行为,与以下代码的执行无异:
console.log(a); // a 前面未申明
// ReferenceError: a is not defined
局部变量提升
使用关键字 var
申明的情况:
function fn() {
console.log(aa);
var aa = 1;
}
console.log(a);
var a = 1;
// undefined
fn();
// undefined
前面已解释,不再赘述,只是需要注意下面这种情况:
if (false) {
var a = 1;
}
console.log(a);
// undefined
正常思维可能会理解 if 条件判断为假所以不会执行内部语句,最后会输出 a is not defined
,然而并非如此,仍然将申明的变量执行了提升机制;这里可以简单理解为存在即提升,也就是为了避免以上问题的影响,所以出现了块级变量申明 let
与 const
;
块级变量提升
使用 let
与 const
的情况:
if (true) {
console.log(a);
let a = 1;
console.log(aa);
}
// ReferenceError: Cannot access 'a' before initialization
// ReferenceError: aa is not defined
if (true) {
console.log(b);
const b = 1;
console.log(bb);
}
// ReferenceError: Cannot access 'b' before initialization
// ReferenceError: bb is not defined
可以看出,块级变量申明似乎也执行了类似提升的机制,但是处理却与 var
有区别,这里是直接以错误的形式处理输出,提示该变量未进行初始化,而没有变量的申明语句的情况,则是提示未定义的错误,且 let
与 const
的处理情况一致;
![JavaScript变量提升(Hoisting)详解 - 文章图片](/upload/getfiles/0001/2021/5/3/20210503055652603.jpg)
![JavaScript变量提升(Hoisting)详解 - 文章图片](/upload/getfiles/0001/2021/5/3/20210503055653271.jpg)
内容总结
以上是互联网集市为您收集整理的JavaScript变量提升(Hoisting)详解全部内容,希望文章能够帮你解决JavaScript变量提升(Hoisting)详解所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。