JS 作用域与变量提升---JS 学习笔记(三)
你知道下面的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 学习笔记(三)的更多相关文章
- JS作用域、变量提升和闭包
作用域 作用域可以理解为JS引擎执行代码的时候,查找变量的规则. 从确定变量访问范围的阶段的角度,可以分为2类,词法作用域和动态作用域.js是词法作用域. 从变量查找的范围的角度,可以分为3类,全局作 ...
- js 作用域,变量提升
先看下面一段代码: 代码执行的结果是: 1st alert : a = 0 2nd alert : a = undefined 5th alert : a = 0 3rd alert : a = 3 ...
- JS作用域和变量提升看这一篇就够了
作用域是JS中一个很基础但是很重要的概念,面试中也经常出现,本文会详细深入的讲解这个概念及其他相关的概念,包括声明提升,块级作用域,作用域链及作用域链延长等问题. 什么是作用域 第一个问题就是我们要弄 ...
- js作用域和变量提升
Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of ...
- JS 函数作用域及变量提升那些事!
虽然看了多次js函数作用域及变量提升的理论知识,但小编也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷) ...
- JS _函数作用域及变量提升
虽然看了多次js函数作用域及变量提升的理论知识,但也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷)&g ...
- 《Node.js开发实战详解》学习笔记
<Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...
- javascript中的变量作用域以及变量提升
在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...
- javascript中的变量作用域以及变量提升详细介绍
在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...
随机推荐
- Spring增强代理模式
1. 依赖注入;(掌握) 2. XML自动注入;(掌握) 3. 全注解配置;(掌握) 4. 代理模式;(掌握,难点) 依赖注入 构造参数注入 constructor-arg:构造器注入: index: ...
- 10#Windows注册表的那些事儿
引言 用了多年的Windows系统,其实并没有对Windows系统进行过深入的了解,也正是由于Windows系统不用深入了解就可以简单上手所以才有这么多人去使用.笔者是做软件开发的,使用的基本都是Wi ...
- C# 初识Redis
一.下载:听网上的朋友説的找的是redis for windows ,直接下载即可 https://github.com/ServiceStack/redis-windows 二.下载后解压 文件 r ...
- Redis哨兵模式(sentinel)部署记录(主从复制、读写分离、主从切换)
部署环境: CentOS7.5 192.168.94.11 (master) 192.168.94.22 (slave0) 192.168.94.33 (slave1) 192.168.94.44 ...
- GALV_maptravel研究分析(2)
本节地图:Gov's Mansion,Campsite,Yourmansion ++++++++++++++++++++华丽丽的分割线+++++++++++++++++++++++++++++++++ ...
- ajax的网上解析
/* 用XMLHTTPRequest来进行ajax异步数据交交互*/ 主要有几个步骤: //1.创建XMLHTTPRequest对象 //最复杂的一步 if (window.XMLHttpReques ...
- lua tonumber
[1]应用tonumber函数 local function test(telnum) , )) == ) -- 5000~5999公司预留号码 , ) == ' or isLen or isRese ...
- Linux的DNS配置3-多域
1.实验目的 现要求在两个局域网中分别搭建各自的DNS服务器,并通过相关设置,使得两个DNS服务器能相互解析 2.实验拓扑 3.实验分析 要使两个不同网络的DNS服务器能相互访问,需要额外假设一台DN ...
- Linux 开放端口号(mysql开启远程连接)
在 Centos 7 或 RHEL 7 或 Fedora 中防火墙由 firewalld 来管理,而不是 iptables. 一.firewalld 防火墙语法命令如下:启用区域端口和协议组合 fir ...
- hdu1172(枚举)
中文题,题意就不解释了. 思路:因为答案一定是四位数,所以只要枚举1000-9999,如果符合所有条件,那么保存一下答案,记录一下答案的个数,如果答案是唯一的,那么输出它,否则,就不确定. 代码如下: ...