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. 函 ...
随机推荐
- python学习笔记之函数(方法)(四)
一.函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,编程中的函数在英文中也有很多不同的叫法.在C中叫function,在Java里面叫做method. 定义: ...
- Google 出品的 Java 编码规范,强烈推荐,既权威又科学
这份文档是 Google Java 编程风格规范的完整定义.当且仅当一个Java源文件符合此文档中的规则, 我们才认为它符合Google的Java编程风格.原文:google.github.io/st ...
- QQ群消息监听并将消息存储到SQLite数据库中
目录 一.前言 二.效果图 1.插件界面 2.SQLite数据库 3.QQ群消息 三.准备工作 1.CQA软件 2.CQA-SDK易语言版本 3.易语言破解版 4.使用到的相关模块 四.开始撸代码 五 ...
- JS的数据类型你真的懂了吗
一.JS数据类型分类 1.基本数据类型 (1)Number 数字 (2)String 字符串 (3)Boolean 布尔值 (4)null 空对象指针 (5)undefined 为定义 (6)symb ...
- 解决for循环里获取到的索引是最后一个的问题
方法一 原理: 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入 利用 bind 函数部分执行的特性 代码 1: for (var i = 0; i < 10; i+ ...
- Scala 面向对象(七):静态属性和静态方法
1 Scala中静态的概念-伴生对象 Scala语言是完全面向对象(万物皆对象)的语言,所以并没有静态的操作(即在Scala中没有静态的概念). 但是为了能够和Java语言交互(因为Java中有静态概 ...
- java 数据结构(五):数据结构简述
1.数据结构概述数据结构(Data Structure是一门和计算机硬件与软件都密切相关的学科,它的研究重点是在计算机的程序设计领域中探讨如何在计算机中组织和存储数据并进行高效率的运用,涉及的内容包含 ...
- 数据可视化之powerBI技巧(十八)Power BI动态技巧:动态显示列和度量值
今天分享一个可视化小技巧,如何在PowerBI的表格中动态显示需要的列? 就是这样的效果, 也就是根据切片器的筛选,来显示需要的列,做起来很简单,步骤如下: 01 逆透视表 进入Powerquery编 ...
- hihoCoder 1052 基因工程 最详细的解题报告
题目来源:基因工程 解题思路:假设基因序列长度为N,则需要计算基因序列前K个和后K个相同所需要的最少改变次数sum. 假设基因序列为 ATACGTCT (即M=8),K=6:interval=M-K= ...
- Quartz.Net系列(十三):DateBuilder中的API详解
1.DateOf.ToDayAt.TomorrowAt DateOf:指定年月日时分秒 public static DateTimeOffset DateOf(int hour, int minute ...