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 EasyUI API 中文文档 - TreeGrid 树表格使用介绍
Nov 21 Javascript
javascript中定义类的方法详解
Feb 10 Javascript
基于javascript实现浏览器滚动条快到底部时自动加载数据
Nov 30 Javascript
JQuery点击事件回到页面顶部效果的实现代码
May 24 Javascript
js计算系统当前日期是星期几的方法
Jul 14 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
Dec 08 Javascript
javascript表单正则应用
Feb 04 Javascript
Bootstrap表单使用方法详解
Feb 17 Javascript
AngularJS实现的2048小游戏功能【附源码下载】
Jan 03 Javascript
JS中创建自定义类型的常用模式总结【工厂模式,构造函数模式,原型模式,动态原型模式等】
Jan 19 Javascript
JS实现的定时器展示简单秒表、页面弹框及跳转操作完整示例
Jan 26 Javascript
Express 配置HTML页面访问的实现
Nov 01 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
高分R级DC动画剧《哈莉·奎茵》第二季正式预告首发
2020/04/09 欧美动漫
用PHP实现多级树型菜单
2006/10/09 PHP
php使用MySQL保存session会话的方法
2015/06/26 PHP
PHP中的随机性 你觉得自己幸运吗?
2016/01/22 PHP
PHP+redis实现微博的拉模型案例详解
2019/07/10 PHP
JavaScript对内存分配及管理机制详细解析
2013/11/11 Javascript
嵌入式iframe子页面与父页面js通信的方法
2015/01/20 Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
2015/03/01 Javascript
JAVA四种基本排序方法实例总结
2015/07/24 Javascript
深入浅析JavaScript中with语句的理解
2016/05/12 Javascript
JavaScript“尽快失败”的原则实例详解
2016/10/08 Javascript
JavaScript用JSONP跨域请求数据实例详解
2017/01/06 Javascript
详解在Vue中通过自定义指令获取dom元素
2017/03/04 Javascript
vue+axios实现登录拦截的实例代码
2017/05/22 Javascript
js删除数组中的元素delete和splice的区别详解
2018/02/03 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
2018/10/18 Javascript
layui实现多图片上传并限制上传的图片数量
2019/09/26 Javascript
微信小程序 this.triggerEvent()的具体使用
2019/12/10 Javascript
[41:17]完美世界DOTA2联赛PWL S3 access vs CPG 第二场 12.13
2020/12/17 DOTA
python 提取文件的小程序
2009/07/29 Python
跟老齐学Python之玩转字符串(3)
2014/09/14 Python
python编码总结(编码类型、格式、转码)
2016/07/01 Python
Django数据库表反向生成实例解析
2018/02/06 Python
python如何使用unittest测试接口
2018/04/04 Python
浅谈利用numpy对矩阵进行归一化处理的方法
2018/07/11 Python
Python Django框架url反向解析实现动态生成对应的url链接示例
2019/10/18 Python
image-set实现Retina屏幕下图片显示详细介绍
2012/12/24 HTML / CSS
使用CSS3编写类似iOS中的复选框及带开关的按钮
2016/04/11 HTML / CSS
英国电子产品购物网站:TobyDeals
2018/07/30 全球购物
名人珠宝设计师:Melinda Maria Jewelry
2019/03/06 全球购物
手工制作的豪华英式沙发和沙发床:Willow & Hall
2019/05/03 全球购物
New Balance比利时官方网站:购买鞋子和服装
2021/01/15 全球购物
一些网络技术方面的面试题
2014/05/01 面试题
同步和异步有何异同,在什么情况下分别使用他们
2013/04/09 面试题
2015年教师工作总结范文
2015/03/31 职场文书
本科毕业论文致谢词
2015/05/14 职场文书