如何理解JS作用域与作用域链?

1.背景介绍

JavaScript 中存在两种作用域:全局作用域和函数作用域,不存在块级作用域。全局作用域在浏览器中是window对象。

执行环境(execution context)是JavaScript 中最为重要的一个概念,定义了变量和函数访问其它数据的权力。

全局作用域: 
最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。

局部作用域: 
和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的。

像在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,但是javascript不同,并没有所谓的块级作用域,javascript的作用域是相对函数而言的。

js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。 

全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。 
js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。 

2.知识剖析

变量的可访问性

1 非严格模式下不声明直接使用变量,变量会成为全局变量

2 和作用域对应的全局变量和局部变量(函数内变量)

作用域链

执行环境会创建变量对象的作用域链。

作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。

作用域链的前端始终是当前执行代码所在环境的变量对象。全局执行环境的变量对象始终是作用域链中最后一个对象。

这有两方面的影响:1 变量只能沿着自身所在的作用域链查找,直到找到为止,否则返回错误;2 隔离其它变量。

简化来说:就是一个调用变量形成的查找过程;把它再和执行环境结合起来包装形成作用域链。

3.常见问题

延长作用域链

4.解决方案

try - catch 语句的 catch 块

with 语句

在作用域链前端临时增加一个变量对象,该对象会在代码执行之后移除

5.编码实战

demo
// 下面的变量定义在全局作用域(global scope)中
var num1 = 20,
    num2 = 4,
    name = "Chamahk";

// 本函数定义在全局作用域
function multiply() {
  return num1 * num2;
} // 返回 80

// 嵌套函数的例子
function getScore() {
  var num1 = 2,
      num2 = 3;
  
  function add() {
    return name + " scored " + (num1 + num2);
  }
  
  return add();
}// 返回 "Chamahk scored 5"

// for
var n = 0;
for(var i = 0 ; i < 10; i ++) {  
  n += i;
}
console.log(  num1 + '\n'+ multiply() + '\n'+getScore()+ '\n' + i + '\n' + n + '\n' );

6.扩展思考

this

this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在 所有函数的作用域中。

this 对象是在运行时基于函数执行环境绑定的。

《javascript高级程序设计》一书给出的解释是:

this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象。不过,匿名函数具有全局性,因此this对象同常指向window

闭包

函数嵌套形成的整个执行环境就是闭包。

1 内部函数只可以在外部函数中访问。

2 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。

7.参考文献

参考一  MDN文档

参考二  js 高程

8.更多讨论

问:严格模式下直接使用变量会发生什么?

答:抛出错误 ReferenceError: n is not defined

问:函数怎么查找变量

答:调用变量时,首先在当前函数对象中查找,如果没有找到就顺着作用域链向上,在外层对象中查找变量,如果没有找到再顺着作用域链向上查找,直到在最后Global对象中找到为止,否则报错。

问:js 有块级作用域?

答:没有块级作用域。

像在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,但是javascript不同,并没有所谓的块级作用域,javascript的作用域是相对函数而言的。



技能树.IT修真院     
 “我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。

这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。

 
快来与我一起学习吧~邀请链接  点击打开链接

猜你喜欢

转载自blog.csdn.net/zach90/article/details/80875592