浅谈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 常用操作整理 基础入门篇
Oct 14 Javascript
javascript跨浏览器的属性判断方法
Mar 16 Javascript
javascript的创建多行字符串的7种方法
Apr 29 Javascript
分享2个jQuery插件--jquery.fileupload与artdialog
Dec 26 Javascript
Bootstrap源码解读按钮(5)
Dec 23 Javascript
JavaScript实现公历转农历功能示例
Feb 13 Javascript
javascript实现圣旨卷轴展开效果(代码分享)
Mar 23 Javascript
Vue.js 中取得后台原生HTML字符串 原样显示问题的解决方法
Jun 10 Javascript
详解ES6中的 Set Map 数据结构学习总结
Nov 06 Javascript
JavaScript作用域链实例详解
Jan 21 Javascript
微信小程序webview实现长按点击识别二维码功能示例
Jan 24 Javascript
vue 实现锚点功能操作
Aug 10 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
php发送post请求的三种方法
2014/02/11 PHP
利用PHP访问MySql数据库的逻辑操作以及增删改查的实例讲解
2017/08/30 PHP
JavaScript入门之事件、cookie、定时等
2011/10/21 Javascript
Js判断参数(String,Array,Object)是否为undefined或者值为空
2013/11/04 Javascript
jquery $("#variable") 循环改变variable的值示例
2014/02/23 Javascript
javascript实现复制与粘贴操作实例
2014/10/16 Javascript
原创jQuery弹出层插件分享
2015/04/02 Javascript
JavaScript三元运算符的多种使用技巧
2015/04/16 Javascript
jQuery+json实现的简易Ajax调用实例
2015/12/14 Javascript
JS随机打乱数组的方法小结
2016/06/22 Javascript
JS多文件上传的实例代码
2017/01/11 Javascript
理解javascript中的Function.prototype.bind的方法
2017/02/03 Javascript
Angular2 之 路由与导航详细介绍
2017/05/26 Javascript
老生常谈JavaScript面向对象基础与this指向问题
2017/10/16 Javascript
JS简单添加元素新节点的方法示例
2018/02/10 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
如何使用puppet替换文件中的string
2018/12/06 Javascript
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
使用layer弹窗提交表单时判断表单是否输入为空的例子
2019/09/26 Javascript
Python引用(import)文件夹下的py文件的方法
2014/08/26 Python
分析用Python脚本关闭文件操作的机制
2015/06/28 Python
基于python的七种经典排序算法(推荐)
2016/12/08 Python
python实现图片压缩代码实例
2019/08/12 Python
Python解析json代码实例解析
2019/11/25 Python
Python enumerate函数遍历数据对象组合过程解析
2019/12/11 Python
使用jupyter notebook将文件保存为Markdown,HTML等文件格式
2020/04/14 Python
Python爬虫后获取重定向url的两种方法
2021/01/19 Python
基于zepto的插件之移动端无缝向上滚动并上下触摸滑动实例代码
2016/12/20 HTML / CSS
英国标志性奢侈品牌:Burberry
2016/07/28 全球购物
香港艺人陈冠希创办的潮流品牌:JUICESTORE
2021/03/04 全球购物
中英文自我评价语句
2013/12/20 职场文书
物流仓储计划书
2014/01/10 职场文书
信息与计算机科学职业规划范文:成为一艘有方向的船
2014/09/11 职场文书
上课说话检讨书500字
2014/11/01 职场文书
Nginx 常用配置
2022/05/15 Servers
JavaScript圣杯布局与双飞翼布局实现案例详解
2022/08/05 Javascript