JavaScript 的作用域一直以来是前端开发中比较难以理解的知识点, 对于 JavaScript 的作用域主要记住几句话, 走遍天下都不怕...
一,"JavaScript 中无块级作用域"
在 Java 或 C# 中存在块级作用域, 即: 大括号也是一个作用域.
- publicstaticvoidmain (){
- if(1==1){Stringname ="seven";
- }
- System.out.println(name);}
- // 报错
- publicstaticvoidMain(){
- if(1==1){stringname ="seven";
- }
- Console.WriteLine(name);}
- // 报错
在 JavaScript 语言中无块级作用域
- functionMain(){
- if(1==1){
- varname ='seven';
- }
- console.log(name);
- }
- // 输出: seven
二, JavaScript 采用函数作用域
在 JavaScript 中每个函数作为一个作用域, 在外部无法访问内部作用域中的变量.
- functionMain(){
- varinnerValue ='seven';
- }
- Main();
- console.log(innerValue);
- // 报错: Uncaught ReferenceError: innerValue is not defined
三, JavaScript 的作用域链
由于 JavaScript 中的每个函数作为一个作用域, 如果出现函数嵌套函数, 则就会出现作用域链.
- xo ='alex';
- functionFunc(){
- varxo ="seven";
- functioninner(){
- varxo ='alvin';
- console.log(xo); }
- inner();
- }Func();
如上述代码则出现三个作用域组成的作用域链, 如果出现作用域链后, 那么寻找变量时候就会出现顺序, 对于上述实例:
当执行 console.log(xo) 时, 其寻找顺序为根据作用域链从内到外的优先级寻找, 如果内层没有就逐步向上找, 直到没找到抛出异常.
四, JavaScript 的作用域链执行前已创建
JavaScript 的作用域在被执行之前已经创建, 日后再去执行时只需要按照作用域链去寻找即可.
示例一:
- xo ='alex';
- functionFunc(){
- varxo ="seven";
- functioninner(){
- console.log(xo);
- }
- returninner;
- }
- varret = Func();
- ret();
- // 输出结果: seven
上述代码, 在函数被调用之前作用域链已经存在:
全局作用域 -> Func 函数作用域 -> inner 函数作用域
当执行 [ret();] 时, 由于其代指的是 inner 函数, 此函数的作用域链在执行之前已经被定义为: 全局作用域 -> Func 函数作用域 -> inner 函数作用域, 所以, 在执行 [ret();] 时, 会根据已经存在的作用域链去寻找变量.
示例二:
- xo ='alex';
- functionFunc(){
- varxo ="eirc";
- functioninner(){
- console.log(xo);
- } xo ='seven';returninner;
- }varret = Func();
- ret();
- // 输出结果: seven
上述代码和示例一的目的相同, 也是强调在函数被调用之前作用域链已经存在:
全局作用域 -> Func 函数作用域 -> inner 函数作用域
不同的时, 在执行 [var ret = Func();] 时, Func 作用域中的 xo 变量的值已经由 "eric" 被重置为 "seven", 所以之后再执行 [ret();] 时, 就只能找到 "seven".
示例三:
- xo ='alex';
- functionBar(){
- console.log(xo);
- }functionFunc(){
- varxo ="seven";
- returnBar;
- }
- varret = Func();
- ret();
- // 输出结果: alex
上述代码, 在函数被执行之前已经创建了两条作用域链:
全局作用域 -> Bar 函数作用域
全局作用域 -> Func 函数作用域
当执行 [ret();] 时, ret 代指的 Bar 函数, 而 Bar 函数的作用域链已经存在: 全局作用域 -> Bar 函数作用域, 所以, 执行时会根据已经存在的作用域链去寻找.
五, 声明提前
在 JavaScript 中如果不创建变量, 直接去使用, 则报错:
- console.log(xxoo);
- // 报错: Uncaught ReferenceError: xxooisnotdefined
JavaScript 中如果创建值而不赋值, 则该值为 undefined, 如:
- varxxoo;console.log(xxoo);
- // 输出: undefined
在函数内如果这么写:
- functionFoo(){
- console.log(xo);
- varxo ='seven';
- }
- Foo();
- // 输出: undefined
上述代码, 不报错而是输出 undefined, 其原因是: JavaScript 的函数在被执行之前, 会将其中的变量全部声明, 而不赋值. 所以, 相当于上述实例中, 函数在 "预编译" 时, 已经执行了 var xo; 所以上述代码中输出的是 undefined.
来源: http://www.jianshu.com/p/cce056fbd382