返回

细数《JavaScript高级程序设计》中的函数机制

见解分享

《JavaScript高级程序设计》(第三版)学习复盘(二)

在上一篇文章中,我们对《JavaScript高级程序设计》(第三版)中的变量进行了深入探讨。在这篇文章中,我们将把目光转向函数。函数是JavaScript编程的基石,也是理解JavaScript程序执行流程的关键。

函数声明提升

函数声明提升是一个非常重要的概念,它意味着函数声明在代码执行之前就被解释器读取和执行。这意味着函数可以在其声明之前被调用,而不会报错。

foo();

function foo() {
  console.log('Hello, world!');
}

这段代码首先调用了foo()函数,然后才定义了foo()函数。然而,代码不会报错,因为在执行foo()函数之前,函数声明就被提升了。

递归函数

递归函数是在一个函数通过名字调用自身的情况下构成的。递归函数可以用来解决许多问题,比如阶乘计算、斐波那契数列计算等等。

function factorial(n) {
  if (n === 0) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}

这个函数计算n的阶乘。它使用递归来减少问题的大小,直到达到基本情况(n === 0)。

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。闭包可以在函数内部访问父函数的作用域,即使父函数已经执行完毕。

function outer() {
  var a = 1;

  function inner() {
    console.log(a);
  }

  return inner;
}

var innerFunc = outer();
innerFunc(); // 1

在这个例子中,inner()函数是一个闭包,它可以访问outer()函数的作用域,即使outer()函数已经执行完毕。

作用域链

作用域链是一个函数可以访问的变量的作用域的列表。作用域链从当前函数的作用域开始,然后是父函数的作用域,依此类推。

function outer() {
  var a = 1;

  function inner() {
    var b = 2;

    console.log(a); // 1
    console.log(b); // 2
  }

  inner();
}

outer();

在这个例子中,inner()函数的作用域链包括inner()函数的作用域和outer()函数的作用域。inner()函数可以访问a和b这两个变量,因为它们都在inner()函数的作用域链中。

this

this指向当前函数的作用域。this的值取决于函数的调用方式。

function outer() {
  var a = 1;

  function inner() {
    console.log(this.a);
  }

  inner(); // undefined
  inner.call(this); // 1
}

outer();

在这个例子中,inner()函数被调用了两次。第一次调用时,this指向全局对象,因此console.log(this.a)输出undefined。第二次调用时,inner()函数被显式地调用,this指向outer()函数的作用域,因此console.log(this.a)输出1。

call、apply和bind

call、apply和bind都是可以改变函数this指向的函数。

  • call()方法接受两个参数:第一个参数是要改变this指向的对象,第二个参数是要传递给函数的参数列表。
  • apply()方法也接受两个参数:第一个参数是要改变this指向的对象,第二个参数是要传递给函数的参数数组。
  • bind()方法也接受两个参数:第一个参数是要改变this指向的对象,第二个参数是要传递给函数的参数列表。与call()和apply()不同的是,bind()方法返回一个新的函数,该函数的this指向已经被改变。
function outer() {
  var a = 1;

  function inner() {
    console.log(this.a);
  }

  inner.call(this); // 1
  inner.apply(this); // 1
  var boundInner = inner.bind(this);
  boundInner(); // 1
}

outer();

在这个例子中,inner()函数被调用了三次。第一次调用时,inner()函数被显式地调用,this指向outer()函数的作用域,因此console.log(this.a)输出1。第二次调用时,inner()函数被apply()方法调用,this指向outer()函数的作用域,因此console.log(this.a)输出1。第三次调用时,inner()函数被bind()方法调用,this指向outer()函数的作用域,因此console.log(this.a)输出1。