JS——变量提升和函数提升
一、引入
在了解这个知识点之前,我们先来看看下面的代码,控制台都会输出什么
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
小白理解:foo是一个全局变量,值为1,当执行bar函数的时候,对1取反的结果是false,不会执行bar函数内部的if语句,所以弹出1
小炉:不不不,你并不知道变量提升和函数提升,请看下面正确的代码执行过程
var foo;
foo = 1
function bar(){
var foo;
if(!foo){
foo = 10;
}
alert(foo);
}
bar();
上面这段代码才是正确的执行顺序,在调用bar函数时,内部的foo产生了变量提升,提升到函数内部的顶端,又因为只是声明变量foo并未赋值,所以foo的值为undefined,取反则为true,然后if语句执行,将foo的值改为10,最后alert弹出10。这是为什么上面代码不输出1而输出10的原因,那么下面我们来介绍相关概念
二、从js预解析过程理解函数提升和变量提升
1.预解析过程
(1)把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
(2)把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
(3)var fn = function(){}时,先提升var,再提升function。
(4)提升完后其他代码位置不变
举个栗子
例1:
var a = 25;
function abc() {
alert(a);
var a = 10;
}
abc(); 预解析后如下:
var a;
function abc() {
var a;
alert(a);
a = 10;
}
a = 25;
abc(); //ndefined;
从字面上理解就是变量和函数的声明会移动到移动到函数或者全局代码的开头位置,先提升var,再提升function,提升完成后不改变其他代码位置
2.函数提升
函数提升,只会提升函数声明,而不会提升函数表达式。
f();
fn(); // 函数表达式
var fn = function(){
console.log(1);
} // 函数声明
function f(){
console.log(0);
}
真实的执行过程是怎么样的呢?看下面
// 函数声明
function f(){
console.log(0)
}
var fn;
f();
fn();
fn = function(){
console.log(1);
}
所以在fn()时就会报错,说fn不是一个函数。也证明了函数提升,只会提升函数声明,而不会提升函数表达式。
3.变量提升
console.log(a) // undefined
var a = 'hello JS' /* 在我们声明a之前为什么输出a不会报错呢? 不急,让我们接着往下看 */ num = 6;
num++;
var num;
console.log(num) // 7 为什么给一个还没有声明的变量赋值会不报错呢
上面的代码能够正确执行的原因都是因为变量提升,将变量提升到当前作用域的最前面,由于并未赋值,所以上面第一个console会打出undefined
三、同名函数和变量提升时怎么办?
1.函数和变量同名
举个栗子
var a = 1;
function a(){
console.log(a)
}
console.log(a)
上面的代码最终结果是打印出1,当函数和变量同名时,函数声明提升的优先级高于变量声明的提升。(浏览器底层的实现过程是这样的:当js解析器在遇到函数声明时,会优先将其提升到定义体顶部,其次再是var声明的变量)
2.函数同名
举个栗子
fn();//2
function fn() { console.log(1); }
fn();//2
var fn = 10;
fn();//报错 fn is not a function
function fn() { console.log(2); }
fn();
函数同名时,后面声明的函数会覆盖前面的函数
3.变量同名
(1)全局变量和函数内部变量同名
var a = 1;
function test(x) {
alert(x);//undefined
alert(a);//undefined
var a = 2;
alert(a);//2
}
test();
代码执行过程:首先声明变量a和test函数,然后给a赋值为1,调用函数test,因为没有给test传参,x为undefined,又因为函数内部有var声明的变量a,存在变量提升,所以先弹出a为undefined,再给a赋值为2,再弹出2。
我们可以看到,局部变量的优先级高于同名的全局变量 。如果在函数中声明一个局部变量同名,则全局变量就会被局部变量覆盖。
(2)同一环境下的两个同名变量,后一个会覆盖前一个
四、由函数提升和变量提升引出的作用域问题
1.javascript是没有块级作用域的,函数是javascript中唯一拥有自身作用域的结构
2.声明变量,实际上就是定义了一个名字,在内存中开辟了存储空间,并且初始为undefined,提升到当前作用域顶部,只提升变量,不提升所赋的值
3.块内的变量声明和函数声明也会被提升,例如if语句。
4.局部变量的优先级高于同名的全局变量,当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。
五、如何取消函数提升和变量提升
ES6中引入了块级作用域的概念,也有let、const、class等新的声明方式来避免函数提升和变量提升带来的问题(ES6语法传送门)
六、总结
1.函数声明和变量声明会被提升到作用域的顶部,只提升声明,提升完成后其他代码位置不改变
2.当函数和变量同名时,函数声明提升的优先级高于变量声明的提升。
3.同名变量、同名函数后声明的会覆盖前面的
4.块内的变量声明和函数声明也会被提升,例如if语句。
5.函数声明和函数表达式相比,函数声明使用可以更加自由,可以放在随意的位置,因为它能够整体的变量提升。而函数表达式使用就相对没有那么自由了,调用必须在声明的后面,因为变量提前只是将表达式的变量提前,并没有将表达式的内容提前。
6.局部变量的优先级高于同名的全局变量
参考文档:https://www.cnblogs.com/nangezi/p/9105778.html
https://blog.csdn.net/liuqiao0327/article/details/106971270/
https://juejin.im/post/6844904179371081741#heading-0
JS——变量提升和函数提升的更多相关文章
- 浅谈JS变量声明和函数声明提升
先来两个问题 很多时候,在直觉上,我们都会认为JS代码在执行时都是自上而下一行一行执行的,但是实际上,有一种情况会导致这个假设是错误的. a = 2; var a; console.log(a); 按 ...
- JS 变量提升与函数提升
JS 变量提升与函数提升 JS变量提升 变量提升是指:使用var声明变量时,JS会将变量提升到所处作用域的顶部.举个简单的例子: 示例1 console.log(foo); // undefined ...
- js变量提升与函数提升的详细过程
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- JS逻辑题 技术点: 1). 变量提升 2). 函数提升 3). 预处理 4). 调用顺序
考查的技术点: 1). 变量提升 2). 函数提升 3). 预处理 4). 调用顺序 var c = 1; function c(c) { console.log(c); var c = 3; ...
- js中的变量提升和函数提升
从上周开始,我所在的学习小组正式开始了angular的学习,angular是全面支持es6的,所以语法上和以前的angular有了很大的不同,比如变量声明时就抛弃了var,而选择了let和const: ...
- js中变量提升和函数提升
变量提升和函数提升的总结 我们在学习JavaScript时,会遇到变量提升和函数提升的问题,为了理清这个问题,现做总结如下,希望对初学者能有所帮助 我们都知道 var 声明的变量有变量提升,而 let ...
- JavaScript系列文章:变量提升和函数提升
第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...
- JavaScript:变量提升和函数提升
第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...
- JavaScript: 变量提升和函数提升
第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...
随机推荐
- 「HAOI2015树上染色」「树形DP」
其实我还不大会树形DP 此题就当练手叭,缕一下思路就好 题目链接 BZOJ4033 题目大意就是给一棵树,对一部分点染成黑色,剩下的为白色,问所有同色点距离之和....... 简明扼要的题意,然额我不 ...
- WPF DataGrid ScrollBar Style
效果图如下 代码 <DataGrid.Resources> <Style TargetType="{x:Type ScrollBar}"> <Sett ...
- day57 jQuery基础
目录 一.操作标签 1 位置操作 2 尺寸 3 文本操作 4 获取值操作 5 属性操作 6 获取属性的特例 7 文档处理 二.事件 1 克隆事件 2 自定义模态框 3 左侧菜单 4 回到顶部 5 输入 ...
- requests接口自动化3-url里带参数的get请求:params
url里带参数的get请求:用params传参 #2.带参数的get请求,把参数写成字典格式,用params传参 para2={"type":"math"} r ...
- shell专题(一):Shell概述
大数据程序员为什么要学习Shell呢? 1)需要看懂运维人员编写的Shell程序. 2)偶尔会编写一些简单Shell程序来管理集群.提高开发效
- softmax、cross entropy和softmax loss学习笔记
之前做手写数字识别时,接触到softmax网络,知道其是全连接层,但没有搞清楚它的实现方式,今天学习Alexnet网络,又接触到了softmax,果断仔细研究研究,有了softmax,损失函数自然不可 ...
- bzoj3062[Usaco2013 Feb]Taxi*
bzoj3062[Usaco2013 Feb]Taxi 题意: Bessie在农场上为其他奶牛提供出租车服务,她必须赶到这些奶牛的起始位置,并把他们带到它们的目的地.Bessie的车很小,所以她只能一 ...
- tcpreplay的使用指导
Tcpreplay的介绍 简单的说, tcpreplay是一种pcap包的重放工具, 它可以将用ethreal, wireshark工具抓下来的包原样或经过任意修改后重放回去. 它允许你对报文做任意的 ...
- Java常用API(Arrays类)
Java常用API(Arrays类) 什么是Arrays类? java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等.其所有方法均为静态方法,调用起来 非常简单. 这里我们 ...
- CSS栅格布局
CSS栅格布局 认识栅格布局 CSS的栅格布局也被称为网格布局(Grid Layout),它是一种新兴的布局方式. 栅格布局是一个二维系统,这意味着它可以同时处理列和行,与弹性布局相似,栅格系统也是由 ...