浅谈JavaScript 声明提升


Posted in Javascript onSeptember 14, 2020

1 引例及基本原理

在学习JavaScript声明提升之前,我们先看下面这个例子:

console.log(a);
var a=2;

运行结果会是什么?你可能会有以下的猜测:

1.报错ReferenceError: a is not defined;

2.打印2;

3.打印undefined。

正确的结果是第三种,打印undefined。

下面让我们来看看具体的原因。其实,对于var a=2;这条语句,JavaScript会将其视为两个声明:

  1. 定义声明var a,会在编译阶段进行;
  2. 赋值声明a=2,会留在原地等待执行阶段进行。

而所谓的声明提升:就是JavaScript会把var变量声明和函数声明都会被提升到各自作用域的顶部,而赋值操作并不会被提升。
因此,上面的例子实际是按照这样的流程来处理:

var a;
console.log(a);
a=2;

我们还需要知道,不仅仅是var变量声明会提升,函数声明同样也会提升,现在来看下面这个例子

foo();
function foo(){
 console.log(a);
 var a=2;
}

这个例子的运行结果为:打印undefined。这段代码实际上会被理解为为下面的形式:

function foo(){
 var a;
 console.log(a);
 a=2;
}
foo();

2 关于声明提升的常见问题

2.1 函数表达式

先看一个函数表达式的例子:

console.log(foo);
var foo=function(){}

上面代码的运行结果为:打印undefined。实际上,变量标识符foo被提升了,但它的赋值操作并没有被提升,我们可以理解为下面的形式:

var foo;
console.log(foo);
foo=function(){}

结论:函数声明会被提升,但函数表达式不会被提升。

2.2 声明的优先级

如果在同一个作用域内,存在同名的函数声明和var变量声明,那么会发生什么样的情况呢?我们同样再来看一个例子:

function a(){}
var a;
console.log(a);
var a;
function a(){}
console.log(a);

上面的两种写法,运行结果均为打印a(){}。也就是说,如果在同一个作用域内,存在同名的函数声明和var变量声明,则函数声明的优先级更高。
还有一种情况:如果同一个作用域内,存在多个同名的函数声明。这种情况下,后面声明的会覆盖前面声明的。

3 练习题

3.1 第一题

var getName = function() {
 console.log(1);
}
function getName() {
 console.log(2);
}
getName();

答案:打印1

解析:提升后的顺序如下

var getName;//与函数声明同名,故失效
function getName() {
 console.log(2);
}
getName = function() {//赋值
 console.log(1);
};
getName();

3.2 第二题

var a = 1;
function b(){
 a = 10;
 return;
 function a(){
  console.log(a);
 } 
}
b();
console.log(a);

答案:打印1

解析:首先,我们需要梳理清楚声明的提升。
本题有几个关键点,我们需要明白:

函数b内的a函数虽然在return之后,但它并没有失效,它会发生声明提升,从而提升到b函数作用域的顶部。

很多童鞋(比如我TAT)可能会错误地认为这题的答案是10,认为我们在最后调用了b函数,修改了全局变量a。实际上,由于函数a发生了声明提升,导致在函数b内“遮蔽”了全局作用域中的变量a,因此,a=10;其实是将函数a重新赋值。为了进一步测验,大家可以把a函数注释掉,会发现此时的答案就变成了10。

注:本题还涉及到了闭包的相关知识,这一题详细的解析请见参考资料[2],讲得非常详细。

var a;//全局变量a发生了声明提升
function b(){
 function a(){//函数a发生声明提升
   console.log(a);
  }
 a = 10;//因为函数a离它最近,因此赋值给函数a
 return; 
}
a = 1;//赋值给了全局变量a
b();
console.log(a);

4 参考资料

[1] 《你不知道的JavaScript》

[2] js中变量名与函数名重名的问题,Charles_Tian

[3] 函数声明与变量声明的提升机制优先级问题,一个菜鸟的奋斗史

以上就是浅谈JavaScript 声明提升的详细内容,更多关于JavaScript 声明提升的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JQuery中getJSON的使用方法
Dec 13 Javascript
使用js的replace()方法查找字符示例代码
Oct 28 Javascript
JavaScript中的原型继承基础学习教程
May 06 Javascript
JS给swf传参数的实现方法
Sep 13 Javascript
js实现上传文件添加和删除文件选择框
Oct 24 Javascript
Bootstrap树形菜单插件TreeView.js使用方法详解
Nov 01 Javascript
微信小程序 免费SSL证书https、TLS版本问题的解决办法
Dec 14 Javascript
使用canvas及js简单生成验证码方法
Apr 02 Javascript
实例详解JavaScript中setTimeout函数的执行顺序
Jul 12 Javascript
JS XMLHttpRequest原理与使用方法深入详解
Apr 30 Javascript
vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作
Jul 27 Javascript
Vue管理系统前端之组件拆分封装详解
Aug 23 Javascript
详解vue 中 scoped 样式作用域的规则
Sep 14 #Javascript
详解JavaScript 高阶函数
Sep 14 #Javascript
vue实现简单计算商品价格
Sep 14 #Javascript
Vue中添加滚动事件设置的方法详解
Sep 14 #Javascript
JavaScript位置参数实现原理及过程解析
Sep 14 #Javascript
swiper自定义分页器的样式
Sep 14 #Javascript
js+canvas实现转盘效果(两个版本)
Sep 13 #Javascript
You might like
粗略计算在线时间,bug:ip相同
2006/12/09 PHP
php 变量定义方法
2009/06/14 PHP
php 生成WML页面方法详解
2009/08/09 PHP
学习php设计模式 php实现单例模式(singleton)
2015/12/07 PHP
php实现替换手机号中间数字为*号及隐藏IP最后几位的方法
2016/11/16 PHP
详解PHP发送邮件知识点
2018/05/06 PHP
Thinkphp5.0 框架视图view的比较标签用法分析
2019/10/12 PHP
MC Dialog js弹出层 完美兼容多浏览器(5.6更新)
2010/05/06 Javascript
jquery实现的鼠标拖动排序Li或Table
2014/05/04 Javascript
简单对比分析JavaScript中的apply,call与this的使用
2015/12/04 Javascript
Markdown与Bootstrap相结合实现图片自适应属性
2016/05/04 Javascript
基于Bootstrap3表格插件和分页插件实例详解
2016/05/17 Javascript
AngularJS自定义指令实现面包屑功能完整实例
2017/05/17 Javascript
angular框架实现全选与单选chekbox的自定义
2017/07/06 Javascript
微信小程序实现图片放大预览功能
2020/10/22 Javascript
详解Immutable及 React 中实践
2018/03/01 Javascript
JavaScript 日期时间选择器一些小结
2018/04/02 Javascript
vue 组件高级用法实例详解
2018/04/11 Javascript
javascrit中undefined和null的区别详解
2019/04/07 Javascript
微信小程序分享小程序码的生成(带参数)以及参数的获取
2020/03/25 Javascript
浅析Python3爬虫登录模拟
2018/02/07 Python
python实现12306抢票及自动邮件发送提醒付款功能
2018/03/08 Python
Python求解任意闭区间的所有素数
2018/06/10 Python
使用Python脚本zabbix自定义key监控oracle连接状态
2019/08/28 Python
pytorch实现seq2seq时对loss进行mask的方式
2020/02/18 Python
基于python实现FTP文件上传与下载操作(ftp&sftp协议)
2020/04/01 Python
在Windows上安装和配置 Jupyter Lab 作为桌面级应用程序教程
2020/04/22 Python
Python爬虫分析微博热搜关键词的实现代码
2021/02/22 Python
台湾饭店和机票预订网站:Expedia台湾
2016/08/05 全球购物
印度服装购物网站:Limeroad
2018/09/26 全球购物
什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?
2013/05/03 面试题
公司接待方案
2014/03/08 职场文书
风险评估实施方案
2014/03/09 职场文书
交通文明倡议书
2014/05/16 职场文书
2021-4-5课程——SQL Server查询【3】
2021/04/05 SQL Server
Lombok的详细使用及优缺点总结
2021/07/15 Java/Android