你不知道的JS之作用域和闭包(四)(声明)提升
原文:你不知道的js系列
先有鸡还是先有蛋?
如下代码:
a = 2;
var a;
console.log( a );
很多开发者可能会认为结果会输出 undefined,因为 var a 在 a = 2 后面,好像变量似乎被重新定义了,所以结果会是默认值 undefined。
然而,正确结果是 2.
下面这段代码,a 在 定义之前被引用。不会抛出错误,也不会输出 2 。
console.log( a );
var a = 2;
结果输出 undefined。
编译器
回忆一下第(一)节中的内容,引擎在解释执行之前会编译你的代码。
所有的声明,包括函数和变量,都会在代码执行之前被处理。
你看到 var a = 2;是一个语句,实际上 JavaScript 会认为这是两个语句,第一个声明 var a 在编译期间被处理,第二个语句赋值操作,留在原处等待执行。
所以上面的第一段代码会被处理成两部分
var a;
a = 2;
console.log( a );
第二段代码实际上也被处理成:
var a;
console.log( a );
a = 2;
这个过程,可以看成是变量和函数的声明被提升到代码的头部,叫做变量提升(Hoisting)
也就是说变量声明在赋值语句之前被执行。
注:只有声明被提升,赋值和其它的操作被留在原处。
foo();
function foo() {
console.log( a ); // undefined
var a = 2;
}
上面代码中的函数 foo 的声明被提前,所以这样的调用是可以被执行的。
提升发生在每个作用域内部,所有变量 a 的声明被提升到 foo 的顶部。相当于:
function foo() {
var a;
console.log( a ); // undefined
a = 2;
}
foo();
函数声明被提升了,但是函数表达式不会被提升:
foo(); // not ReferenceError, but TypeError!
var foo = function bar() {
// ...
};
这里的变量 foo 的声明被提升了,所以对 foo 的 RHS 查询不会报错。但这个时候 foo 的值还是 undefined,所有会报 TypeError 错误。
就算是有命名的函数表达式,这个名称标识也不会被外部作用域访问:
foo(); // TypeError
bar(); // ReferenceError var foo = function bar() {
// ...
};
上面这段代码会被解释为类似下面的:
var foo; foo(); // TypeError
bar(); // ReferenceError foo = function() {
var bar = ...self...
// ...
}
函数优先
函数和变量的声明都会被提升,但是一个细微的区别就是函数声明在前面。
考虑下面的代码:
foo(); //
var foo;
function foo() {
console.log( 1 );
}
foo = function() {
console.log( 2 );
};
输出结果为1
因为这段代码会被解释为:
function foo() {
console.log( 1 );
}
foo(); //
foo = function() {
console.log( 2 );
};
var foo 是一个重复的声明,所有被忽略掉了。即时它在函数声明的前面编写,因为函数声明的提升要先于变量声明的提升。
和函数名称重复的变量声明就会被忽略,但如果有多个同名的函数声明,那么后面的声明会覆盖掉前面的:
foo(); //
function foo() {
console.log( 1 );
}
var foo = function() {
console.log( 2 );
};
function foo() {
console.log( 3 );
}
在普通的代码块中出现的函数声明也会被提升到外部作用域的顶部。
foo(); // "b" var a = true;
if (a) {
function foo() { console.log( "a" ); }
}
else {
function foo() { console.log( "b" ); }
}
但这种行为并不靠谱,因为有可能将来 JavaScript 的版本会改变这个机制(比如在块中声明的函数将会绑定在块作用域中),所以要避免在块中声明函数。
小结:
变量声明提升,函数声明提升,其它操作不变
函数表达式不会被提升
函数声明优先于变量声明
后声明的会覆盖先声明的
你不知道的JS之作用域和闭包(四)(声明)提升的更多相关文章
- 你不知道的JS之作用域和闭包 附录
原文:你不知道的js系列 A 动态作用域 动态作用域 是和 JavaScript中的词法作用域 对立的概念. 动态作用域和 JavaScript 中的另外一个机制 (this)很相似. 词法作用域是 ...
- 你不知道的JS之作用域和闭包(五)作用域闭包
原文:你不知道的js系列 一个简单粗暴的定义 闭包就是即使一个函数在它所在的词法作用域外部被执行,这个函数依然可以访问这个作用域. 比如: function foo() { var a = 2; fu ...
- 你不知道的JS之作用域和闭包(三)函数 vs. 块级作用域
原文:你不知道的js系列 在第(二)节中提到的,标识符在作用域中声明,这些作用域就像是一个容器,一个嵌套一个,这个嵌套关系是在代码编写时定义的. 那么到底是什么产生了一个新的作用域,只有函数能做到 ...
- 你不知道的JS之作用域和闭包(二)词法作用域
原文:你不知道的js系列 词法作用域(Lexical Scope) Lex time 一个标准的编译器的第一个阶段就是分词(token化) 词法作用域就是在词法分析时定义的作用域.换句话说,词法作用域 ...
- 你不知道的JS之作用域和闭包(一)什么是作用域?
原文:你不知道的js系列 什么是作用域(Scope)? 作用域 是这样一组规则——它定义了如何存放变量,以及程序如何找到之前定义的变量. 编译器原理 JavaScript 通常被归类为动态语言或者解释 ...
- JS之作用域与闭包
JS之作用域与闭包 作用域在JS中同样也是一个重要的概念.它不复杂,因为ES5中只有全局作用域和函数作用域,我们都知道他没有块级作用域.但在ES6中多了一个let,他可以保证外层块不受内层块的影响 ...
- JS(作用域和闭包)
1.对变量提升的理解 1.变量定义(上下文) 2.函数声明 2.说明 this 几种不同的使用场景 常见用法 1.作为构造函数执行 2.作为对象属性执行 3.作为普通函数执行(this === win ...
- 解析js中作用域、闭包——从一道经典的面试题开始
如何理解js中的作用域,闭包,私有变量,this对象概念呢? 就从一道经典的面试题开始吧! 题目:创建10个<a>标签,点击时候弹出相应的序号 先思考一下,再打开看看 //先思考一下你会怎 ...
- 你不知道的JavaScript(作用域和闭包)
作用域和闭包 ・作用域 引擎:从头到尾负责整个JavaScript的编译及执行过程. 编译器:负责语法分析及代码生成等. 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非 ...
随机推荐
- 论文笔记:Fast(er) RCNN
在 RCNN 初步试水取得成功后,研究人员又迅速跟进,针对 RCNN 中的几点不足提出改进,接连推出了 fast-rcnn 和 faster-rcnn.关于这两篇论文,网上相关的文章实在是多如牛毛,因 ...
- 3D Slicer中文教程(五)—三维视图颜色改变
3D Slicer在分割后三维重建的图像,效果很好,但是存在一定的不足,默认的颜色并不是很合适,这时手动设置三维视图下的需要的颜色就很有必要了.如下图所示,默认的三维重建后的颜色. 这样的颜色显然不是 ...
- 【easy】257. Binary Tree Paths 二叉树找到所有路径
http://blog.csdn.net/crazy1235/article/details/51474128 花样做二叉树的题……居然还是不会么…… /** * Definition for a b ...
- Centos安装Git、DotNet、Docker
1.安装Git yum install git 可通过下面的命令查看Git版本 git --version 2.安装Dotnet sudo yum install libunwind libicu 导 ...
- 奇yin技巧
关于一些奇yin技巧 关于删除字符串中的一些字串,并且考虑新的字串 例题:luogu4824 luogu3121 方法:开一个栈记录,发现字串后剪去字串长度. for(int i=1;i<=le ...
- margin:auto你真的理解么?
含义 margin:auto是具有强烈计算意味的关键字,用来计算元素对应方向应该获得的剩余空间大小 填充规则 (1) 如果一侧定值,一侧auto,则auto为剩余空间大小 (2) 如果两侧均是auto ...
- SVG初尝试(一)
SVG简介 SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics).其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它 ...
- ad9361自测试校准
#include "config.h" #include "CONFIG_FPGA_ALL.h" #include "xparameters.h&qu ...
- poj1988 Cube Stacking 带权并查集
题目链接:http://poj.org/problem?id=1988 题意:有n个方块,编号为1-n,现在存在两种操作: M i j 将编号为i的方块所在的那一堆方块移到编号为j的方块所在的那 ...
- python django2.x报错No module named 'django.core.urlresolvers'
解决方法就是: from django.urls import reverse 最近从django1.9迁移到django2.0中出现一个意外的报错: 这个报错的原因在stack overflow上有 ...