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中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...
随机推荐
- mysql 获取昨天数据 utc时间
# yzj邀请昨日数据 SELECT s.id, s.create_at, ch.id, ch.code AS channel, c.id , c.code AS custom, so.id, so. ...
- Cron表达式范例
每隔5秒执行一次:*/5 * * * * ? 每隔1分钟执行一次:0 */1 * * * ? 每天23点执行一次:0 0 23 * * ? 每天凌晨1点执行一次:0 0 1 * * ? 每月1号凌晨1 ...
- 基数排序-LSD
这个最低位优先的基数排序,非常适合移植到硬件设备中,所以,我们提供一个C源码 —————————————————————————————————————— #include <stdio.h&g ...
- 北京大学Cousera学习笔记--3-计算导论与C语言基础-第一讲.计算机的基本原理-计算机怎么计算-数的二进制
思考问题 1.“数”在计算机中是如何表示的? 2.逻辑上“数”是怎么运算的? 3.物理上“数”的计算是怎么实现的? 从图灵机计算问题得出: 1.字母表中的符号越多(几进制),读入移动次数减少,但程序数 ...
- Wireshark常用过滤命令
WireShark在我们网络编程中有非常重要的作用,可以帮我们抓取我们程序发送的数据包,大家常常说他是抓包工具,其实它是一款非常强大的网络数据包分析工具. 在WireShark的学习上,不想花费太多的 ...
- UIElementImageShot
MemoryStream memStream = new MemoryStream(); System.Windows.Media.Imaging.RenderTargetBitmap bmp = n ...
- 解决CentOS(6和7版本),/etc/sysconfig/下没有iptables的问题
一.Centos 6版本解决办法: 1.任意运行一条iptables防火墙规则配置命令: iptables -P OUTPUT ACCEPT 2.对iptables服务进行保存: service ip ...
- Installing ROS Indigo on the Raspberry Pi
Installing ROS Indigo on the Raspberry Pi Description: This instruction covers the installation of R ...
- 日志入库-log4j-mysql连接中断问题
mysql5.6 druid1.0.17 log4j 1.2.16 一定时间后无法连接 CommunicationsException: Communications link failure 粗暴 ...
- 帮助Bsny(乱搞做法)
帮助Bsny 题目描述 Bsny的书架乱成一团了,帮他一下吧! 他的书架上一共有n本书,我们定义混乱值是连续相同高度书本的段数.例如,如果书的高度是30,30,31,31,32,那么混乱值为3:30, ...