以前一直觉会认为javascript代码执行是由上到下一行行执行的。自从看了《你不知道的JS》后发现这个观点并不彻底正确。先来给你们举一个书本上的的例子:javascript
var a='hello world'; var a; console.log(a);
一开始我以为输出的是undefined。可是真正的结果是hello world。带着疑问再看另一段代码:java
console.log(a); var a='hello world';
借鉴与上面的例子会认为会输出一个hello world,或者是抛出一个没有声明的异常错误,然而发现这两种想法也是错误。输出的结果是‘undefined’。这书很是人性化的总结出告终论是:es6
引擎解释javascript代码的以前会对其进行编译。在编译过程当中会查找全部声明,并用合适做用域将他们关联起来。换句话说,在代码执行以前,会对做用域链中全部变量和函数声明先处理完先。因此,当遇到var a='hello world'中是 var a是先在编译阶段执行,而后在执行a='hello world'。因此,第一段代码实质上是:函数
var a; a='hello world'; console.log(a);
因此输出的就就是helloworld。总结一句话就是:只有声明被提高,而赋值或其余运算会留在原地。因此第二段代码实际上就是:spa
var a; console.log(a); a='hello world';
介绍完这两个经典例子是时候来看看一下这个例子了:code
var name = "world"; (function () { if (typeof name == 'undefined') { var name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
根据javascript的运行机制和javascript没有块做用域这个特色,能够得出,变量name会声明提高移至做用域 scope (全局域或者当前函数做用域) 顶部的。因此上述代码就至关于:ip
var name = "world"; (function () { var name; if (typeof name == 'undefined') { var name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
所以,if判断的时候typeof name == 'undefined'是true。因此会执行条件为true里面的代码。输出就是Hello yang。
那么若是想实现上面的函数,咱们该如何实现?答案很是简单那就建立块做用域了。如何最简单的建立块做用域呢?那固然是采用es6的新特性let关键字。let关键字能够将变量绑定到所在的任意区域中一般在{...}中。换句话说。let为其声明变量隐性劫持到所在区域中。下列例子中:let就绑定到if (typeof name == 'undefined') {...}中
。因此name不会被提高,因此判断就为假,因而就能够输出咱们期待已久的‘helloworld’。作用域
var name = "world"; (function () { if (typeof name == 'undefined') { let name = 'yang'; console.log('Hello ' + name) } else { console.log('Hello ' + name) } })()
注意点:let所在的块级做用域,在声明代码被运行前,是不会像var那样会被查找到,提早声明,而是运行到了该代码才会被声明执行。下面例子很好说明这个问题:it
(function (){ console.log(b); let b=2; })()
谢谢你们观看,你们有什么好见解能够提出来讨论讨论。io