一、引入

  在了解这个知识点之前,我们先来看看下面的代码,控制台都会输出什么

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——变量提升和函数提升的更多相关文章

  1. 浅谈JS变量声明和函数声明提升

    先来两个问题 很多时候,在直觉上,我们都会认为JS代码在执行时都是自上而下一行一行执行的,但是实际上,有一种情况会导致这个假设是错误的. a = 2; var a; console.log(a); 按 ...

  2. JS 变量提升与函数提升

    JS 变量提升与函数提升 JS变量提升 变量提升是指:使用var声明变量时,JS会将变量提升到所处作用域的顶部.举个简单的例子: 示例1 console.log(foo); // undefined ...

  3. js变量提升与函数提升的详细过程

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  4. JS逻辑题 技术点: 1). 变量提升 2). 函数提升 3). 预处理 4). 调用顺序

    考查的技术点:  1). 变量提升 2). 函数提升  3). 预处理  4). 调用顺序 var c = 1; function c(c) { console.log(c); var c = 3; ...

  5. js中的变量提升和函数提升

    从上周开始,我所在的学习小组正式开始了angular的学习,angular是全面支持es6的,所以语法上和以前的angular有了很大的不同,比如变量声明时就抛弃了var,而选择了let和const: ...

  6. js中变量提升和函数提升

    变量提升和函数提升的总结 我们在学习JavaScript时,会遇到变量提升和函数提升的问题,为了理清这个问题,现做总结如下,希望对初学者能有所帮助 我们都知道 var 声明的变量有变量提升,而 let ...

  7. JavaScript系列文章:变量提升和函数提升

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...

  8. JavaScript:变量提升和函数提升

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...

  9. JavaScript: 变量提升和函数提升

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...

随机推荐

  1. 无题 II 二分图最大匹配

    题目描述 这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小. Input 输入一个整数T表示T组数据. 对于每组数据第一行输 ...

  2. mysql-如何删除主从同步

    我用 change master  语句添加了一个主从同步, change master to master_host='localhost',master_user='slave',master_p ...

  3. SimpleImputer 中fit和transform方法的简介

    sklearn.impute.SimpleImputer 中fit和transform方法的简介 SimpleImputer 简介 通过SimpleImputer ,可以将现实数据中缺失的值通过同一列 ...

  4. Python math 、cmath

    1.math dir(math) 2.cmath 复数运算

  5. python 生成器(一):生成器基础(一)生成器函数

    前言 实现相同功能,但却符合 Python 习惯的方式是,用生成器函数代替SentenceIterator 类.示例 14-5 sentence_gen.py:使用生成器函数实现 Sentence 类 ...

  6. bzoj3767A+B Problem加强版

    bzoj3767A+B Problem加强版 题意: 求两个数的和,每个数绝对值≤10^(10^7). 题解: 又用Python水过了…… 代码: a=raw_input() b=a.split() ...

  7. ScheduledThreadPoolExecutor源码主要部分解析

    ScheduledThreadPoolExecutor继承与基础线程池类ThreadPoolExecutor并实现ScheduledExecutorService接口. 其中ScheduledExec ...

  8. OSCP Learning Notes - Exploit(9)

    Tool: Metasploit 1. Start the msfconsole tool. msfconsole 2.Search ssh related modules. 3.Use the &q ...

  9. 通过Vue实现的todolist

    和接口对接的todolist因为有后台的存在,todolist获取的数据会一直存在不丢失(不管你如何刷新页面),思路如下: 首先得先搞到接口: 通过这个接口地址可以获取整段的数据,成功err为0. 于 ...

  10. Spring框架零基础学习(一):IOC|DI、AOP

    文章目录 一.IDEA创建Spring项目 二.Spring: IOC和DI 三.Spring: AOP 参考链接: HOW2J.CN:Spring idea创建一个spring项目 一.IDEA创建 ...