你知道下面的JavaScript代码执行时会输出什么吗?

var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
console.log(foo);
}
bar();

答案是“10”,吃惊吗?那么下面的可能会真的让你大吃一惊:

var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a);

答案是 “1”。为什么会这样呢,这就涉及到 JS 里面的作用域、作用域链和提升的相关知识了。

首先要明白 作用域和作用域链的内容(点击阅读),现在主要介绍提升。

在 JavaScript 中,当遇到 var a = 1; 这个语句时,我们可能会这么认为,“为一个变量分配内存,给这个变量命名为 a,再把 1 保存进去”。然而这个过程并不完全正确。当编译器遇到 var a = 1 时,会做以下两个步骤:

1. 遇到 var a ,首先会先看看当前的作用域中是否已经有 a,若有,就不再声明 a,若没有,就会在当前的作用域,创建一个 a

2. 然后处理 a = 1 。先查看当前作用域,是否有 a 。如果有,就把 1 赋值给 a 。如果没有,就向上一个作用域中寻找 a,直到寻找到全局作用域。全局作用域中如果还没有,就会抛出异常。

所以,当我们看到 var a = 1; 会认为这是一个声明,实际上这是两个声明, var a 和 a = 1 。第一个声明会在编译阶段进行,第二个声明会在原地等待执行。函数声明和变量声明总会被 JavaScript 的编译器提升到他们所在作用域的顶部。有了这些知识就可以解释上面的代码了

第一段代码实际上如下图:在遇到并执行 bar()函数时,执行到 if 语句里面的 foo,此时会先查询 bar()函数的作用域内有没有声明 foo:

若没有声明,就像上一个作用域中寻找 foo 有没有被声明。

若声明了,就直接将声明提升到 bar 作用域里的顶部(foo = 10 留在原地按顺序等待执行),这样,foo 就是 undefined,!foo 就是 true,可以进入 if 循环。

第二段代码实际上如下图:执行 b()时,首先就是 a = 10;这条语句,执行这条语句之前,先看 a 在 b 中是否被声明,若没有被声明就向上一个作用域中寻找 a ,现在的情况是,在 b 函数内部,a 以函数声明的方式,被声明了,那么就要把这个 a 函数声明提升到 a 所在的作用域的顶部,再按顺序执行后面的代码。

对于提升总结的知识点:

1. 函数声明和变量声明都会提升,但在同一个作用域相同名字的函数声明优先于变量声明。

2. 变量声明会提升,但变量赋值的过程不会提升,会在原地等待被执行。

3. 提升后,赋值语句会向前覆盖提升的内容。例子 2 中,b 函数的内部,最开始 a 是函数提升,a 的本质是函数,但是函数提升后,执行了一个赋值语句:a = 10;此时,a 就是一个 number 类型的变量了。

对于这种情况,我们在写 JavasScript 代码的时候该怎么做呢?

使用单 var 模式:避免变量提升所带来的问题

/*jslint onevar: true [...] */
function foo(a, b, c) {
var x = 1,
bar,
baz = "something";
}

本文参考以下资料:

颜海镜的博客:JavaScript作用域链和提升机制

你不知道的JavaScript

JavaScript高阶程序设计

JS 作用域与变量提升---JS 学习笔记(三)的更多相关文章

  1. JS作用域、变量提升和闭包

    作用域 作用域可以理解为JS引擎执行代码的时候,查找变量的规则. 从确定变量访问范围的阶段的角度,可以分为2类,词法作用域和动态作用域.js是词法作用域. 从变量查找的范围的角度,可以分为3类,全局作 ...

  2. js 作用域,变量提升

    先看下面一段代码: 代码执行的结果是: 1st alert : a = 0 2nd alert : a = undefined 5th alert : a = 0 3rd alert : a = 3 ...

  3. JS作用域和变量提升看这一篇就够了

    作用域是JS中一个很基础但是很重要的概念,面试中也经常出现,本文会详细深入的讲解这个概念及其他相关的概念,包括声明提升,块级作用域,作用域链及作用域链延长等问题. 什么是作用域 第一个问题就是我们要弄 ...

  4. js作用域和变量提升

    Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of ...

  5. JS 函数作用域及变量提升那些事!

    虽然看了多次js函数作用域及变量提升的理论知识,但小编也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷) ...

  6. JS _函数作用域及变量提升

    虽然看了多次js函数作用域及变量提升的理论知识,但也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷)&g ...

  7. 《Node.js开发实战详解》学习笔记

    <Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...

  8. javascript中的变量作用域以及变量提升

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...

  9. javascript中的变量作用域以及变量提升详细介绍

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...

随机推荐

  1. MIPI-Layout说明(转载)

    转载于:http://www.ccm99.com/thread-3713-1-1.html 前言:随着新的总线协议不断提高信号速率,如今的PCB 设计人员需要充分理解高速布线的要求并控制PCB 走线的 ...

  2. win10家庭版删除文件提示没有权限最简单的方式

    1.cmd 2.右键-以管理员身份运行(重要) 3.输入:net user administrator /active:yes,开启超级管理员账号 4.win+r键打开运行对话框,输入 netplwi ...

  3. HDU 1556 BIT区间修改+单点查询(fread读入优化)

    BIT区间修改+单点查询 [题目链接]BIT区间修改+单点查询 &题解: BIT区间修改+单点查询和求和的bit是一模一样的(包括add,sum) 只不过是你使用函数的方式不一样: 使用区间的 ...

  4. 深入理解javascript原型和闭包(转)

    深入理解javascript原型和闭包(完结)   说明: 该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的 ...

  5. github爬虫100项目

    为了更好的巩固所学,在github上开始100爬虫项目,记录学习过程,也希望对他人的学习有帮助,目前还在持续更新中,有兴趣可以看看 地址: https://github.com/mapyJJJ/100 ...

  6. ECMAScript6 入门教程记录 变量的解构赋值

    (1)变量的解构赋值 基本用法:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). let a = 1; let b = 2; let c = ...

  7. [批处理]使用IncrediBuilder加速自动化测试过程

    背景 1.目前单机全部跑完一次测试的时间大概是5个小时 2.7个虚拟机进行分布式执行的时间大概为3.5小时(包含复制.收集日志的时间) 预期 期望通过IncrediBuilder的虚拟进程的功能在单机 ...

  8. (转)利用CAS算法实现通用线程安全状态机

    在多线程环境下,如果某个类是有状态的,那我们在使用前,需要保证所有该类的实例对象状态一致,否则会出现意向不到的bug.下面是通用线程安全状态机的实现方法. public class ThreadSav ...

  9. Mysql AVG() 值 返回NULL而非空结果集

    [1]select 查询返回一行NULL 先来模拟复现一下遇到的问题. (1)源数据表grades,学生成绩表 (2)查询SQL语句 查询‘080601’班的各门课平均成绩 SELECT sClass ...

  10. Emote木马分析

    前言:网上找的样本是EXE的,没有邮件样本,所以只做了exe分析. 一.Emote木马相关信息 文件: C:\Users\Desktop\Samp.exe 大小: 249856 bytes 文件版本: ...