博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【前端笔记】彻底理解变量与函数的声明提升
阅读量:6604 次
发布时间:2019-06-24

本文共 1806 字,大约阅读时间需要 6 分钟。

变量声明

先来看两段代码,正确的运行结果已经给出,

a = 2;var a;console.log(a); // 2复制代码
console.log(a); // undefinedvar a = 2;复制代码

直觉上会认为 JavaScript 代码在 执行时 是由上到下一行一行执行的,但实际上这并不完全正确。

JS 引擎会在解释 JavaScript代码之前首先对其进行编译。 编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。

第一个代码片段会以如下形式进行处理:

var a;a = 2;console.log(a);复制代码

第二个代码片段实际是按照以下流程处理的:

var a;console.log(a);a = 2;复制代码

正确的思考思路是,

包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
这意味着无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,每个作用域都会进行提升操作。

当你看到 var a = 2; 时,可能会认为这是一个声明

但实际上 JavaScript 引擎会将其看成:
var a;a = 2;,当作两个单独的声明
第一个定义声明是在编译阶段进行的。
第二个赋值声明则是执行阶段的任务。

函数声明会被提升,但是函数表达式却不会被提升。

函数声明

foo();function foo() {  console.log(a); // undefined  var a = 2;}复制代码

这段代码foo 函数的声明被提升了,因此第一行中的调用可以正常执行。

下面是处理流程。

function foo() {  var a;  console.log(a); // undefined  a = 2;}foo();复制代码

函数表达式

foo(); // TypeErrorbar(); // ReferenceErrorvar foo = function bar() {  // ...};复制代码

这段代码的变量标识符 foo 被提升并分配给所在作用域(在这里是全局作用域),

因此 foo() 不会导致 ReferenceError
但是 foo 此时并没有赋值(如果它是一个函数声明而不是函数表达式,那么就会赋值)。
foo() 由于对 undefined 值进行函数调用而导致非法操作,因此抛出 TypeError 异常。

同时也要记住,即使是具名的函数表达式(如上:bar),名称标识符在赋值之前也无法在所在作用域中使用。

JS 引擎理解为如下形式:

var foo;foo(); // TypeErrorbar(); // ReferenceErrorfoo = function() {  var bar = ...self... // ...}复制代码

函数优先

函数声明和变量声明都会被提升,函数会首先被提升,然后才是变量。

foo(); // 1var foo;function foo() {  console.log(1);}foo = function() {  console.log(2);};复制代码

JS 引擎理解为如下形式:

function foo() {  console.log(1);}foo(); // 1foo = function() {  console.log(2);};复制代码

var foo 尽管出现在 function foo()... 声明之前,但它是重复的声明(因此被忽略了),因为函数声明会被提升到普通变量之前。

尽管重复的 var 声明会被忽略掉,但出现在后面的函数声明还是可以覆盖前面的,比如下面一段代码:

foo(); // 3function foo() {  console.log(1);}var foo = function() {  console.log(2);};function foo() {  console.log(3);}复制代码

总结

声明本身(变量声明和函数声明)会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。

要注意避免重复声明,特别是当普通的var声明函数声明混合在一起的时候,否则会引起很多危险的问题!

原文参考:《你不知道的 JavaScript》(上卷)第一部分 第四章。

转载地址:http://igfso.baihongyu.com/

你可能感兴趣的文章
他山之石,可以攻玉--回顾我的微服务之旅(转)
查看>>
java8中的stream().filter()的使用和Optional()
查看>>
Mysql按数字大小排序String字段
查看>>
python练习笔记——组合恒等式
查看>>
Qt封装QTcpServer参考资料--QT4中构建多线程的服务器
查看>>
MySQL DDL--ghost执行模板和参数
查看>>
开源一个Android自定义图表库
查看>>
IPV6地址格式分析
查看>>
DTLS-PSK算法抓包解析***
查看>>
ROS-RouterOS hAP ac2+usb 4G上网卡+小米新推的无线上网卡是绝配
查看>>
Eclipse常用快捷键
查看>>
nginx brotli 压缩试用
查看>>
Guava学习笔记(三):集合
查看>>
[转]Java中BigDecimal的使用
查看>>
ORA-30377 MV_CAPABILITIES_TABLE not found
查看>>
排序题如何进行数据分析
查看>>
博客园博客自动生成目录/目录索引
查看>>
ASP.NET Session and Forms Authentication and Session Fixation
查看>>
(转)IntelliJ IDEA java项目导入jar包,打jar包
查看>>
头皮脂溢性皮炎推荐联合治疗:采乐50ml+希尔生100g(请看详情页)
查看>>