关于作用域链

JavaScript 有两种作用域:全局作用域和函数作用域。

var n = 1;

function f1() {
  console.log(n);
}
f1() // 1

函数内部可以直接读取全局变量,但是函数外部不能读取函数内部声明的变量。

function f1() {
  var n = 1;
}

console.log(n)
// Uncaught ReferenceError: n is not defined

如果出于种种原因,需要得到函数内的局部变量。正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

function f1() {
  var n = 1;
  function f2() {
  console.log(n); // 1
  }
}

JavaScript 语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。父对象的所有变量,对子对象都是可见的,反之则不成立。因此对于上述例子中,f2可以使用f1作用域中的变量。

function f1() {
  var n = 1;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); // 1

闭包就是函数f2,即能够读取其他函数内部变量的函数。

由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。

在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

关于作用域链,只要记住先从自己的作用域下找,找不到从上层作用域找就可以了。

题1

var a = 1
function fn1(){
  function fn2(){
    console.log(a)
  }
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() // 找出输出函数是 fn2,但是其作用域下无 a 的声明,再找上一级 fn1,a=2
题2

var a = 1
function fn1(){
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
function fn2(){
  console.log(a)
}
var fn = fn1()
fn() // fn2 里没有,全局 a=1
题3

var a = 1
function fn1(){

  function fn3(){
    function fn2(){
      console.log(a)
    }
    var a

    fn2()
    a = 4
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() // fn2 没有,fn3 有,但是根据声明顺序,最终结果是 undefined

参考:http://javascript.ruanyifeng.com/ 、饥人谷

你可能感兴趣的:(关于作用域链)