函数

作用域

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

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

闭包

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

function createClosure() {
  var name = 'Ourai';

  return function() {
    console.log('My name is ' + name + '.');
  }
}

var whatIsMyName = createClosure();

whatIsMyName();   // "My name is Ourai."

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

function Ourai() {
  var name = 'Ourai';

  this.say = function() {
    console.log('My name is ' + name + '.');
  }
}

var ourai = new Ourai();

ourai.say();   // "My name is Ourai."

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

上下文

改变上下文

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

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

var foo = 'from `window`';
var bar = {foo: 'from `bar`'};
var baz = {foo: 'from `baz`'};

function printFoo() {
  console.log(this.foo);
}

printFoo();             // "from `window`"
printFoo.call(bar);     // "from `bar`"
printFoo.apply(baz);    // "from `baz`"

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

var printBarFoo = printFoo.bind(bar);

printBarFoo();              // "from `bar`"
printBarFoo.call(window);   // "from `bar`"
printBarFoo.apply(baz);     // "from `bar`"

箭头函数有什么特点?

  1. 函数体内的 this 指向的是定义时所在的上下文,而不是使用时所在的上下文;
  2. 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误;
  3. 不可以使用 arguments,该对象在函数体内不存在,如果要用,可以用 rest 参数代替;
  4. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

上面四点中,第一点尤其值得注意。在普通函数中 this 对象的指向是可变的,但是在箭头函数中,它是固定的。

results matching ""

    No results matching ""