回归基础: JavaScript 变量提升
from me:
javascript的变量声明具有hoisting机制,它是JavaScript一个基础的知识点,也是一个比较容易犯错的点,平时在开发中,大大小小的项目都会遇到。
它是JavaScript引擎在执行的时候,把所有变量的声明都提升到当前作用域的最前面。
当然了,函数声明也是可以被提升的。然后,函数表达式却没有提升。
原文:Back to Basics: JavaScript Hoisting
变量声明是所有的编程语言中最基础部分之一。然而,JavaScript 有一个怪异点,称之为变量提升(hositing),这个能够让一个看上去无关紧要的声明变成一个小bug。这篇文章解释了变量提升(hositing)是什么,以及你该如何避免这个大坑。
JavaScript 是特别灵活的语言,几乎允许你在任何地方声明变量。比如,下方的立即执行函数表达式(IIFE)声明了2个变量,然后将他们用一个弹框显示他们。作为附注,你应该永远不要用弹框,不过我们正在这里证明这一点。
(function() {
var foo = ;
var bar = ;
var baz = ; alert(foo + " " + bar + " " + baz);
})();
这个看上去像是一个机智的 JavaScript 代码。就像预期那样,他显示了字符串 "1 2 3"
。现在,假设移动弹框位置,就下下方那样。
(function() {
var foo = ;
alert(foo + " " + bar + " " + baz);
var bar = ;
var baz = ;
})();
如果有人真的这么写代码,那么这可能就要报错了。很显然,弹框在 bar
和 baz
声明之前发生。然而这是完全有效的 JavaScript ,这完全不会抛出异常。相反,弹框会显示 "1 undefined undefined"
。
基于上一个实验,似乎你能够引用之前不存在的变量。现在,让我们做一个相同的 IIFE,但是移除 baz
声明,就想下方那样。马上,我们有个引用错误(ReferenceError)
,因为 baz
没有定义。
(function() {
var foo = ;
alert(foo + " " + bar + " " + baz);
var bar = ;
})();
这真的很有趣。为了理解这里发生了什么,你需要理解变量提升(hoisting)。变量提升(hoisting)是 JavaScript 编译器的行为,将所有的变量和函数声明移至当前作用域的最高处。然而,只有声明被提升了。任何赋值行为都被留在他们所在的地方。因此,我们第二个例子 IIFE 实际上等同于以下 代码:
(function() {
var foo;
var bar;
var baz; foo = ;
alert(foo + " " + bar + " " + baz);
bar = ;
baz = ;
})();
现在,你可以搞清楚为什么第二个例子不会抛出异常。变量提升之后(hoisting),bar
和 baz
实际上在弹框之前就已经被定义了,尽管显示undefined。在第三个例子中,baz
被完全移除了。因此,没有可以提升的变量,导致弹出框抛出异常。
函数变量提升(hoisting)
就像之前提到的那样,函数声明也是可以被提升的。然后,赋给变量的函数却没有提升。比如,在下方的代码中会像预期那样运行,因为函数声明被提升了。
foo(); function foo() {
alert("Hello!");
}
然而,下方例子苦逼地失败了。foo
这个变量声明在函数被调用之前提升了。然后,因为foo
的赋值没有提升,因此抛出了尝试调用非函数变量的异常。
foo(); var foo = function() {
alert("Hello!");
};
总结
变量提升(hoisting)很容易理解,但是却是 JavaScript 语言中经常被忽视的细节。没有对变量提升(hoisting)有一个合适的理解,你的程序很容易有小bug。为了帮助你远离这些bug,许多开发者(和静态分析工具)提倡在每一个作用域开头放一个单独变量声明。既然这是 JavaScript 编译器如何检测你的代码的基础,那么对这条规则来说是有效的——即使我打破了规则。
回归基础: JavaScript 变量提升的更多相关文章
- JavaScript变量提升 面试题
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- JavaScript变量提升和函数声明预解析
1.首先理解函数作用域 在JavaScript中,变量的定义并不是以代码块作为作用域的,而是以函数作用作用域的.也就是说,如果变量是在某个函数中定义的,那么它在函数以外的地方是不可见的.而如果该变量是 ...
- javascript变量提升
提升是一种将变量和函数的声明移到函数作用域(如果不在任何函数内的话就是全局作用域)最顶部的机制. 提升影响了变量的生命周期,一个变量的生命周期包含3个阶段: 声明——创建一个新变量,例如var myV ...
- 最通俗易懂的javascript变量提升
a = 'ghostwu'; var a; console.log( a ); 在我没有讲什么是变量提升,以及变量提升的规则之前, 或者你没有学习过变量提升,如果按照现有的javascript理解, ...
- javascript变量提升详解
js变量提升 对于大多数js开发者来说,变量提升可以说是一个非常常见的问题,但是可能很多人对其不是特别的了解.所以在此,我想来讲一讲. 先从一个简单的例子来入门: a = 2; var a; cons ...
- JavaScript 变量提升
变量提升(Hoisting):在ES6之前,函数声明和变量声明总是被JavaScript解释器隐式地提升(hoist)到包含他们的作用域的最顶端. 注意: 1. JavaScript 仅提升声明,而不 ...
- 160622、详解JavaScript变量提升
变量在程序中随处可见.它们是一些始终在相互影响,相互作用的的数据和逻辑.正是这些互动使应用程序活了起来. 在JavaScript中使用变量很重要的一方面就是变量的提升 —— 它决定了一个变量何时可以被 ...
- 详解JavaScript变量提升
变量在程序中随处可见.它们是一些始终在相互影响,相互作用的的数据和逻辑.正是这些互动使应用程序活了起来. 在JavaScript中使用变量很重要的一方面就是变量的提升 —— 它决定了一个变量何时可以被 ...
- 对javascript变量提升跟函数提升的理解
在写javascript代码的时候,经常会碰到一些奇怪的问题,例如: console.log(typeof hello); var hello = 123;//变量 function hello(){ ...
随机推荐
- Maven中的dependencyManagement 意义
1.在Maven中dependencyManagement的作用其实相当于一个对所依赖jar包进行版本管理的管理器. 2.pom.xml文件中,jar的版本判断的两种途径 1:如果dependenci ...
- linq 之 Distinct的使用
public class Product { public string Name { get;set;} public int Code { get; set; } } class ProductC ...
- C#------对SQLServer进行简单的增,删,改,查
EF中的操作转载: http://www.cnblogs.com/mcgrady/archive/2015/03/21/4355282.html PSContext db = new PSContex ...
- 按照网上方法js删除指定cookie,却怎么也删除不了,解决如下
网上方法: 查找原因说是没有指定Path,记得系统里以前也没指定还是可以的,就查了一下现在的系统Path,猜测是系统Path由以前的/改为/E7-Planning 就改了前端删除方法 测试一下OK了, ...
- Java——文件选择框:JFileChooser
import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; import j ...
- 比较详细Python正则表达式操作指南(re使用)
比较详细Python正则表达式操作指南(re使用) Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式.Python 1.5之前版本则是通过 regex 模块提供 E ...
- 《css3实战》读书笔记 第一章 基于CSS需求而编写的HTML.
笔记说明 <CSS3实战手册第3版(影印版)>可以消除Web设计工作的痛苦,并且带给你:HTML--重新入门.如果你是HTML新手,你会学到如何以CSS友好的方式进行基本页面构造.若你是H ...
- CodeForces 710CMagic Odd Square(经典-奇数个奇数&偶数个偶数)
题目链接:http://codeforces.com/problemset/problem/710/C 题目大意:输入一个奇数n,则生成n*n矩阵,要求矩阵的行.列还有斜着,所有元素之和为奇数. 解题 ...
- 解决问题--VS2012中一个Panel覆盖另一个Panel时拖动时容易造成两个控件成父子关系的避免
在*.Designer.cs中,假如想把panel1覆盖到panel2上,但是VS自动让panel1成为panel2的子控件了,在文件中会有this.panel2.Controls.Add(this. ...
- 修改美化Matlab字体
修改美化Matlab字体 MATLAB作为高校理工科类本科生或研究生必不可少的科研工具已经有着很多年的历史,以至于在我们的大学生活里或科研工作中,MATLAB处处闪现着它的身影,给我们带来了不少 ...