备战-作用域链、闭包

302 阅读2分钟

前言

今天是对作用域链以及闭包的一个整理,小编之前的相关文章感觉不够细致,所以今天还是再次系统的整理一下,为面试做好准备。

两种作用域

再开始今天的分享之前,我们先来了解一下两种作用域。

  • 静态作用域

    函数的作用域在函数定义的时候就决定了,我们的js就是采用的静态作用域

  • 动态作用域

    函数的作用域在函数调用的时候去决定的。

var value = 1;

function foo() {
   console.log(value);
}

function bar() {
   var value = 2;
   foo();
}

bar(); // 1

我们直接上一个实例,看一下输出结果,可能有些人按照作用域链惯例的思想,foo函数在bar()中执行,自己未找到value,然后依据作用域链往调用自己的bar函数去找,诶嘿输出2,这是对作用域链一个很错误的理解(小编后面会细细讲到)。

按照我们作用域的理解来,foo()执行,未找到value然后去函数定义的地方往上层去找,这才是他正真的作用域链,所以该题输出1.

作用域链

我们前面介绍到了执行上下文,执行上下文的三部分就是对象作用域链this。 我们上面说到了js是静态作用域,所以函数作用域链[[scope]]的产生是在函数定义的 时候。

function foo() {
    function bar() {
        ...
    }
}

// 定义内部属性 
foo.[[scope]] = [
  globalContext.GO
];

bar.[[scope]] = [
    fooContext.AO,
    globalContext.GO
];

函数定义即会给内部属性[[scope]]赋值定义他的作用域链(全局作用域链我们简称GO,函数称为AO),那么具体执行过程理解了jiu,这边就不啰嗦了。

闭包

之前小编有一篇关于闭包的文章,但是这边还是写上一下,简单的理解就是嵌套函数被返回在外部执行,他的那么它会保留父级函数作用域链不被销毁,这边就放一个简单的闭包应用吧

function makeAdder(x) {
  let a = '外部函数变量'
  return function(y) {
    return x + y + a;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // '7外部函数变量'
console.log(add10(2)); // '12外部函数变量'

总结

今天简单的总结了一下作用域链和闭包,下一期总结一下原型以及继承(this、call、apply、bind小编之前的文章有写这边就后续不在总结)