返回

JavaScript函数作用域深层次理解!从菜鸟到大师!

前端

前言

本文是由一道面试题展开的,关于Javascript函数与作用域的查遗补漏相关知识点:

  • 函数
  • 函数表达式 vs 函数声明
  • 深入理解箭头函数
  • 作用域
  • 词法作用域
  • 函数作用域
  • 块作用域

函数

函数是JavaScript中最重要的概念之一,它允许你将代码组织成可重用的模块,以便在程序中多次调用。函数可以接受参数,并返回一个值。

函数有两种定义方式:函数表达式和函数声明。函数表达式是将函数定义为一个表达式,而函数声明是使用function来声明函数。

// 函数表达式
const sum = function(a, b) {
  return a + b;
};

// 函数声明
function sum(a, b) {
  return a + b;
}

作用域

作用域是JavaScript中另一个重要的概念,它决定了变量和函数可以在程序中的哪些部分被访问。作用域可以分为词法作用域和动态作用域。

词法作用域是JavaScript中默认的作用域类型。在词法作用域中,变量和函数的作用域由它们在代码中的位置决定。这意味着变量和函数只能在它们被定义的作用域内被访问。

function outer() {
  let a = 10;

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

  inner();
}

outer();

在上面的例子中,变量a的作用域是函数outer。这意味着变量a只能在函数outer内部被访问。函数inner是函数outer的内部函数,因此它也可以访问变量a

动态作用域是另一种作用域类型,它不是JavaScript中的默认作用域类型。在动态作用域中,变量和函数的作用域由它们在运行时的位置决定。这意味着变量和函数可以在它们被定义的作用域之外被访问。

function outer() {
  let a = 10;

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

  return inner;
}

const inner = outer();

inner();

在上面的例子中,变量a的作用域是函数outer。这意味着变量a只能在函数outer内部被访问。但是,函数inner是在函数outer外部调用的,因此它不能访问变量a

词法作用域

词法作用域是JavaScript中默认的作用域类型。在词法作用域中,变量和函数的作用域由它们在代码中的位置决定。这意味着变量和函数只能在它们被定义的作用域内被访问。

function outer() {
  let a = 10;

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

  inner();
}

outer();

在上面的例子中,变量a的作用域是函数outer。这意味着变量a只能在函数outer内部被访问。函数inner是函数outer的内部函数,因此它也可以访问变量a

函数作用域

函数作用域是JavaScript中另一种作用域类型。函数作用域是函数内部的作用域。这意味着变量和函数只能在它们所在的函数内部被访问。

function outer() {
  let a = 10;

  if (true) {
    let b = 20;

    console.log(a); // 10
    console.log(b); // 20
  }

  console.log(a); // 10
  console.log(b); // ReferenceError: b is not defined
}

outer();

在上面的例子中,变量a的作用域是函数outer。这意味着变量a可以在函数outer的任何地方被访问。变量b的作用域是函数outer内部的if语句块。这意味着变量b只能在if语句块内部被访问。

块作用域

块作用域是JavaScript中最新引入的作用域类型。块作用域是花括号{}内部的作用域。这意味着变量和函数只能在它们所在的块作用域内被访问。

function outer() {
  let a = 10;

  {
    let b = 20;

    console.log(a); // 10
    console.log(b); // 20
  }

  console.log(a); // 10
  console.log(b); // ReferenceError: b is not defined
}

outer();

在上面的例子中,变量a的作用域是函数outer。这意味着变量a可以在函数outer的任何地方被访问。变量b的作用域是函数outer内部的花括号{}块。这意味着变量b只能在花括号{}块内部被访问。

闭包

闭包是JavaScript中的一种函数,它可以访问其定义范围之外的变量。闭包通常用于创建私有变量或实现延迟执行。

function outer() {
  let a = 10;

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

  return inner;
}

const inner = outer();

inner();

在上面的例子中,函数inner是一个闭包。函数inner可以访问其定义范围之外的变量a。这是因为函数inner是函数outer的内部函数,因此它可以访问函数outer的所有变量。

作用域链

作用域链是JavaScript中的一种数据结构,它存储了变量的作用域。作用域链是从当前执行环境开始,一直到全局作用域的变量作用域的列表。

当JavaScript解释器执行代码时,它会创建一个执行环境。执行环境包含了当前正在执行的代码、变量的作用域以及其他一些信息。

当JavaScript解释器在执行环境中找不到某个变量时,它就会沿着作用域链向上查找。如果在作用域链中找到了该变量,则JavaScript解释器就会使用该变量。如果在作用域链中找不到该变量,则JavaScript解释器就会抛出一个错误。

总结

在本文中,我们深入探究了JavaScript函数的作用域。我们学习了函数表达式、函数声明、箭头函数、作用域、词法作用域、函数作用域、块作用域、闭包和作用域链。通过这些知识,我们可以更好地理解JavaScript代码,并写出更健壮、更可靠的JavaScript程序。