Javascript Hoisting
编程过程中,别人谈到Javascript中的funcation是顺序执行的,所以书写的顺序要留心,不然会出未定义就执行的错误。当然,C语言出身的程序员不以为意,会认为理所当然,C语言就是这么干的。但Javascript并非如此!
1 | function ints(arrOfNumberStr) { |
从执行结果上来看,先调用后执行时正确的。但是JS是解析执行的,如果没有预先定义,执行到调用处必然会失败,那么为什么这段代码可以工作呢?
先看一段略做修改之后的代码
1 | function ints(arrOfNumberStr) { |
执行结果失败了。回头看这两段代码的定义,不难发现程序对于toInt
的定义方式有差别,一种用常规的函数定义方式,一种使用var定义。
接着再看一段代码
1 | function loop(n) { |
估计学习C语言的人开始惊讶了:这个i
的作用域不是应该只在for loop
中吗?
那么到底是什么原因造成的呢?这就是Javascript Hoisting!简单解释,声明提升到作用域的最前面。
接上面的variable.js
1 | function loop(n) { |
这和原来的写法是等价的,所以i
的作用域在整个function
中都是有效的。依次类推,init_fail.js中的var toInt
这样的函数声明也会被提升到作用域的最上方,但是只是声明被提升了,真正赋值还是在后面,所以此时调用该函数,它还是undefined
。
但是对于init.js而言,它的声明方式会将整个函数都提升,所以它是先于调用方赋值初始化的,所以能工作。
‘use strict’ 可以防止 only reference hoisting?
如果变量未声明,use strict模式下赋值会报错。
1 | (function(){ |
如果在以前例子中使用use strict,并不能提前报出toInt
未赋值的错误。直到运行期间,才会发现toInt
依然undefined
。
1 | (function ints(arrOfNumberStr) { |
优先使用function declaration
Why? Function declarations are named, so they’re easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use Arrow Functions in place of function expressions. – from javascript style guide
下篇会记录Javascript的作用域,Global Scope, Lexical Scope, Dynamic Scope, Function Scope