JavaScript中变量提升机制示例详解


Posted in Javascript onDecember 27, 2019

变量提升

JavaScript的变量提升有两种,用var声明的变量以及用function声明的变量。

用var声明的变量

我们先来看下面这段代码,a的值是多少

代码1

console.log(a);

var a;

按照以往编程语言的思路来看,代码自上而下运行,按这种思路,会报错,因为执行到第2行时,变量a还没有定义,所以会报错a is not defined

然而事实上答案是undefined

好,抱着疑惑,我们看下面的代码

var a;
console.log(a);

我们发现,这两段代码是一样的,那么又有一个新的问题,是不是有没有var a都无所谓,它的答案始终是undefined,才造成了以为变量会提升的错觉,于是我写了代码3

代码3

console.log(a);

好,它终于报错了,所以这证明了javaScript代码并不是自上而下执行的,至少从表面看上面是这样的。

于是我们再看代码4

代码4

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

因为变量提升嘛,所以答案是2,然而事实上,它依然是undefined,why?

这时候我们有请编译器这位负责语法分析及代码生成等脏活累活的大佬。

编译器在看到var a = 2;,它会将其看做两个声明,var a;和a = 2,第一个声明在编译阶段进行,第二个声明会被原地等待执行阶段。

也就是说上面代码,会变成下面的这段代码

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

所以最终会是undefined

好,我在??乱幌拢?凑舛未??

代码5

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

我想大家应该已经知道这段代码执行时的真正顺序及其答案了,没错,答案是2,但我想说的是把第2行给注释掉,答案依然是2,但这个和变量提升没啥关系了,是严格模式与非严格模式的锅,在非严格模式下允许开发者可以不使用声明变量的关键字,但在严格模式下是不可以的,它会报错的。

用function声明的变量

与var一样,function声明的变量依然会提升。

log(5);

function log(mes){
  console.log(mes)
}

按照之前的变量提升的理解,这段代码的真正顺序是这样的,

function log(mes){
  console.log(mes)
}

log(5);

很好,很正确,那么再看下一段代码

log(5);

var log = function(mes){
  console.log(mes)
}

它报错了,log is not a function,从这里我们可以看出,这种函数表达式是不会被提升的,只有函数声明才会被提升,试着在最前面新增一行代码console.log(log),会先输出undefined。

所以这里的真正顺序是

var log;
log(); //这时候只是声明了log这个变量,并不是函数,却用函数的方法调用它,所以会报错,说这不是一个函数。
log = function(mes){
  console.log(mes)
}

在function里用var声明变量

我们虽然知道,var声明的变量会提升,但并不知道会提升到哪个程度。

在此之前来看一段代码

var a = 4;

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

}
foo();

console.log(a)

答案是5,4,先输出5,再输出4。

用var声明的变量是有函数作用域的,所以foo里的a和foo外面的a没有任何关系,这种情况正是我想要的。

再改下代码

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

console.log(a)

答案是5,a is not defined

第4行代码输出5,第9行报错。

这种情况就是变量提升只会提升到变量所在的 作用域的顶部,不会提升到父级作用域。

因此可以得出一个结论:变量提升只会将变量提升到自己所在的作用域的顶部

函数优先

既然用var和function的变量都有提升的功能,那如果同一个变量用这两种都声明会怎样,好吧,看标题就知道了,函数优先。

具体看下代码

foo();

var foo;

function foo(){
  console.log(1)
}

foo = function(){
  console.log(2)
}

答案是1

这段代码其实这样子的

function foo(){
  console.log(1)
}

foo();// 1

foo = function(){
  console.log(2)
}

仔细一看,var foo;没了,没错,它被引擎忽略了,认为重复声明所以把它抛弃了。

好,既然var声明的变量比不了函数声明,那就用函数声明,多次声明同个变量。

foo()
function foo(){
  console.log(1);
}
foo()
function foo(){
  console.log(2);
}
foo()
function foo(){
  console.log(3);
}

foo()

foo声明了三次,调用了四次,每次调用的结果都是3,所以最后的函数声明会覆盖之前的函数声明

但是var还想挣扎一下,觉得还是有必要证明自己的存在感的。

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

foo()

仔细看,中间那部分代码改了,依次输出3,3,2,2

虽然var foo被忽略了,但下面的函数还是有用的,这段代码可以看成是这样的

function foo(){
  console.log(3);
}

foo();//3
foo();//3
foo = function(){
  console.log(2);
}
foo();//2
foo();//2

在普通块内部声明函数

之前是在作用域声明函数,现在来块里面声明函数

function foo(){

  console.log(b); // undefined
  b(); //TypeError: b is not a function

  var a = true;

  if(a){
    function b(){
      console.log(2)
    }
    //下面这段代码和上面的结果一样
    // var b = function(){
 //      console.log(2)
 //    }
  }
  //b() --> 这里会被执行

}

foo()

从上面看上去,b是undefined,证明这个变量还是有的,只不过它并不是一个函数,这情况和用函数表达式差不多。

总结

  • 提升分为函数声明提升和变量声明提升
  • 声明变量用var,声明函数用function
  • 变量提升会将变量提升到自己所在作用域的顶部
  • 函数表达式不存在提升的机制。
  • 函数声明和变量声明同时声明同一个标识符时,函数声明优先
  • 多个函数声明同一个标识符时,最后一个声明覆盖先前的声明

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jQuery 源代码显示控件 (Ajax加载方式).
May 18 Javascript
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
Apr 24 Javascript
js关闭当前页面(窗口)的几种方式总结
Mar 05 Javascript
JavaScript获取某年某月的最后一天附截图
Jun 23 Javascript
javascript 实现map集合
Apr 03 Javascript
jquery实现漂亮的二级下拉菜单代码
Aug 26 Javascript
跟我学习javascript的浮点数精度
Nov 16 Javascript
原生JS实现轮播效果+学前端的感受(防止走火入魔)
Aug 21 Javascript
js实现按钮控制带有停顿效果的图片滚动
Aug 30 Javascript
浅谈jquery拼接字符串效率比较高的方法
Feb 22 Javascript
JavaScript学习笔记之DOM操作实例分析
Jan 08 Javascript
layui 对table中的数据进行转义的实例
Sep 12 Javascript
vue 中 elment-ui table合并上下两行相同数据单元格
Dec 26 #Javascript
Vue使用虚拟dom进行渲染view的方法
Dec 26 #Javascript
node.js Promise对象的使用方法实例分析
Dec 26 #Javascript
js回调函数仿360开机
Dec 26 #Javascript
js仿360开机效果
Dec 26 #Javascript
element-ui中按需引入的实现
Dec 25 #Javascript
原生JS实现顶部导航栏显示按钮+搜索框功能
Dec 25 #Javascript
You might like
php csv操作类代码
2009/12/14 PHP
php中将数组转成字符串并保存到数据库中的函数代码
2013/09/29 PHP
输入值/表单提交参数过滤有效防止sql注入的方法
2013/12/25 PHP
php 过滤英文标点符号及过滤中文标点符号代码
2014/06/12 PHP
php实现的RSS生成类实例
2015/04/23 PHP
php三种实现多线程类似的方法
2015/10/30 PHP
redis查看连接数及php模拟并发创建redis连接的方法
2016/12/15 PHP
用JS实现一个页面多个css样式实现
2008/05/29 Javascript
js,jQuery 排序的实现代码,网页标签排序的实现,标签排序
2011/04/27 Javascript
Jquery 点击按钮显示和隐藏层的代码
2011/07/25 Javascript
JavaScript 匿名函数(anonymous function)与闭包(closure)
2011/10/04 Javascript
js 弹出菜单/窗口效果
2011/10/30 Javascript
JS onmousemove鼠标移动坐标接龙DIV效果实例
2013/12/16 Javascript
Jquery 在页面加载后执行的几种方式
2014/03/14 Javascript
AJAX实现瀑布流触发分页与分页触发瀑布流的方法
2016/05/23 Javascript
JS命令模式例子之菜单程序
2016/10/10 Javascript
使用JS判断移动端手机横竖屏状态
2018/07/30 Javascript
小程序实现列表点赞功能
2018/11/02 Javascript
js实现无缝轮播图
2020/03/09 Javascript
使用Vue实现一个树组件的示例
2020/11/06 Javascript
vue使用element-ui实现表单验证
2020/12/13 Vue.js
python3 selenium 切换窗口的几种方法小结
2018/05/21 Python
django的聚合函数和aggregate、annotate方法使用详解
2019/07/23 Python
python Kmeans算法原理深入解析
2019/08/23 Python
python图形开发GUI库pyqt5的详细使用方法及各控件的属性与方法
2020/02/14 Python
django创建超级用户时指定添加其它字段方式
2020/05/14 Python
Python实现上下文管理器的方法
2020/08/07 Python
如何完美的建立一个python项目
2020/10/09 Python
俄罗斯旅游网站:Tripadvisor俄罗斯
2017/03/21 全球购物
Columbia Sportswear法国官网:全球户外品牌
2020/09/25 全球购物
会计找工作求职信范文
2013/12/09 职场文书
五一口号
2014/06/19 职场文书
联片教研活动总结
2014/07/01 职场文书
2015年安置帮教工作总结
2015/05/22 职场文书
PostgreSQL通过oracle_fdw访问Oracle数据的实现步骤
2021/05/21 PostgreSQL
Django框架模板用法详解
2022/06/10 Python