• 函数
    • 作用域
      • 闭包
    • 上下文
      • 改变上下文

    函数

    作用域

    作用域分静态作用域和动态作用域两种,其中静态作用域又被叫做词法作用域。在 JavaScript 中没有动态作用域,采用的是词法作用域,也就是说函数的作用域在函数定义的时候就决定了。

    按照变量的有效范围可以分为全局作用域、函数作用域和块级作用域。其中,块级作用域需要配合 letconst 关键字。

    闭包

    闭包又称词法闭包或函数闭包,是引用了自由变量的函数,是由函数以及创建该函数的词法环境组合而成,这个环境包含了闭包创建时所能访问的所有局部变量。

    1. function createClosure() {
    2. var name = 'Ourai';
    3. return function() {
    4. console.log('My name is ' + name + '.');
    5. }
    6. }
    7. var whatIsMyName = createClosure();
    8. whatIsMyName(); // "My name is Ourai."

    用闭包可以模拟基于类的面向对象编程中的私有属性和方法,从而隐藏和封装数据。

    1. function Ourai() {
    2. var name = 'Ourai';
    3. this.say = function() {
    4. console.log('My name is ' + name + '.');
    5. }
    6. }
    7. var ourai = new Ourai();
    8. ourai.say(); // "My name is Ourai."

    从性能角度考虑,实例对象的公共方法应该通过继承原型对象实现而不用闭包。

    上下文

    改变上下文

    在 JavaScript 中可以通过函数的 .call().apply().bind() 这三个方法来改变其上下文。

    调用 .call().apply() 都是立即执行函数,它们的区别仅仅是传参方式不同。

    1. var foo = 'from `window`';
    2. var bar = {foo: 'from `bar`'};
    3. var baz = {foo: 'from `baz`'};
    4. function printFoo() {
    5. console.log(this.foo);
    6. }
    7. printFoo(); // "from `window`"
    8. printFoo.call(bar); // "from `bar`"
    9. printFoo.apply(baz); // "from `baz`"

    而调用 .bind() 则是返回一个绑定了函数上下文的副本,需要另外执行,并且再次通过 .call().apply() 调用也无法改变其上下文。

    1. var printBarFoo = printFoo.bind(bar);
    2. printBarFoo(); // "from `bar`"
    3. printBarFoo.call(window); // "from `bar`"
    4. printBarFoo.apply(baz); // "from `bar`"