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. 函 ...
随机推荐
- mysql 时间自动更新问题
万恶的根据当前时间戳更新,有时候会自动更新,有时候又不会. 通过navicat 创建datetime类型的字段时,会自动勾选上根据当前时间戳更新.当更新数据的时候勾上这个的字段时间就会更改为当前的时间 ...
- SQLserver-MySQL的区别和用法
对于程序开发人员而言,目前使用最流行的两种后台数据库即为MySQL and SQL Server.这两者最基本的相似之处在于数据存储和属于查询系统.你可以使用SQL来访问这两种数据库的数据,因为它们都 ...
- 介绍python由来, 安装python3.8.3 及其变量的定义, 小整数池
介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名字,来自Guido所挚爱 ...
- day71 django收尾
目录 一.Auth模块 1 简介 2 方法总结 3 如何扩展auth_user表 二.bbs表介绍 1 项目开发流程 2 bbs七张表关系 一.Auth模块 1 简介 在我们创建好一个django项目 ...
- Spring的学习与实战
目录 一.Spring起步 学习路线图 Spring的基础知识 什么是Spring Spring框架核心模块 SpringBoot 第一个Spring应用DEMO 编写自己的第一个SpringMVC例 ...
- Python axis的含义
axis=0表述列 axis=1表述行 如下面例子: In [52]: arr=np.arange(12).reshape((3,4))In [53]:arrOut[53]:array([[ 0, 1 ...
- cas客户端流程详解(源码解析)--单点登录
博主之前一直使用了cas客户端进行用户的单点登录操作,决定进行源码分析来看cas的整个流程,以便以后出现了问题还不知道是什么原因导致的 cas主要的形式就是通过过滤器的形式来实现的,来,贴上示例配置: ...
- flask 源码专题(九):flask扩展点
1. 信号(源码) 信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作. pip3 install blinker 2. 根据flask项目的请求流程来进行设置扩展点 中间件 # ...
- python 并发专题(二):python线程以及线程池相关以及实现
一 多线程实现 线程模块 - 多线程主要的内容:直接进行多线程操作,线程同步,带队列的多线程: Python3 通过两个标准库 _thread 和 threading 提供对线程的支持. _threa ...
- 数据可视化之powerBI入门(十)认识Power BI的核心概念:度量值
https://zhuanlan.zhihu.com/p/64150720 本文学习PowerBI最重要的概念:度量值 初学Power BI一般都会对度量值比较困惑,毕竟对长期接触Excel的人来说, ...