JavaScript Scope
JavaScript Scope
构造块作用域:
let
let创建块作用域的例子:
1 | if(i){ |
const
const创建块作用域的例子:
1 | if(i){ |
<!-- const创建的作用变量为常量,不能被修改,并且let声明的变量不会被提升 –>
提升
变量提升
Javascript代码执行时并不是从上往下执行的:
示例一:
1 | a=2; |
我们可能认为会输出undefined,事实并非如此。这是因为变量声明var a;被提升了。
示例二:
1 | alert(a); /\*undefined\*/ |
这是因为变量声明被提升,而赋值操作并不会被提升。
函数声明同样会被提升,但是函数表达式中的函数名标示符在赋值之前不会被加到作用域中。
函数优先
一个普通块内部的函数声明通常会被提升到所在作用域的顶部。
例如:
1 | foo(); /\*1\*/ |
这是因为引擎会把这段代码理解为:
1 | function foo(){ |
变量提升与引擎的工作机制有关,引擎处理程序中的声明发生在编译阶段,数值处理发生在执行阶段,因此声明会被提升。
闭包
当执行函数可以记住并访问所在的词法作用域时,就产生了闭包,即时函数是在当前词法作用域之外执行。
1 | var fn; |
无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都将产生闭包。
块作用域与闭包
1 | for(var i=1;i<=5;i++){ |
这段代码输出5次6;因为setTimeout函数公用全局作用域的i,解决办法:
1 | for(let i=1;i<=5;i++){ |
块作用域与闭包联手天下无敌,HH.
使用IIFE来创建块作用域
try/catch的性能很糟糕,使用期创建块作用域运行会很慢;使用try/catch异常最大的开销是创建异常时需要回溯栈信息,如果没有异常的时候几乎不会影响性能。
但是将一段代码中的任意部分拿出来进行函数包装会改变吧这段代码的含义,其中的this、return、break和continue都会发生变化。IIFE并不是一个普遍适合的解决方案,它只适合在某些情况下进行手动操作。
模块
模块模式应该具备的条件:
1.必须有外部的封闭函数,该函数至少被调用一次。
2.封闭函数至少返回一个内部函数。