返回

函数表达式与函数声明的区别与应用

前端

函数是 JavaScript 中最重要的构建块之一,它允许您将代码组织成更小的、可重用的单元。函数可以声明或表达式来创建,它们之间存在一些关键差异。

函数声明

函数声明使用 function 和函数名来声明函数,后面跟一对圆括号和函数体。函数体由一对花括号括起来,其中包含函数的代码。

function greet(name) {
  console.log(`Hello, ${name}!`);
}

函数声明可以出现在脚本的任何位置,并且会在脚本执行时被解析。这意味着函数在被调用之前必须声明。

函数表达式

函数表达式使用 function 关键字和一对圆括号来声明函数,后面跟一对花括号和函数体。函数表达式可以分配给变量、作为参数传递给其他函数,或者作为函数返回值。

const greet = function (name) {
  console.log(`Hello, ${name}!`);
};

函数表达式可以在脚本的任何位置创建,并且在执行到该行时被解析。这意味着函数可以在被调用之前声明。

函数声明和函数表达式的区别

函数声明和函数表达式之间的主要区别在于它们的声明和执行顺序。函数声明在脚本执行时被解析,而函数表达式在执行到该行时被解析。

这意味着函数声明可以在脚本的任何位置声明,并且会在脚本执行时被解析。而函数表达式只能在脚本的当前位置声明,并且会在执行到该行时被解析。

变量提升

函数声明和函数表达式的一个重要区别是变量提升。变量提升是指在脚本执行时,所有变量声明都会被提升到脚本的最顶部。这意味着函数声明中的变量在脚本执行时会被提升到全局作用域,而函数表达式中的变量只会被提升到函数体内。

// 函数声明
function greet(name) {
  console.log(`Hello, ${name}!`);
}

// 函数表达式
const greet = function (name) {
  console.log(`Hello, ${name}!`);
};

console.log(greet); // undefined

在上面的示例中,函数声明中的 greet 变量在脚本执行时会被提升到全局作用域,因此 console.log(greet) 会输出函数声明。而函数表达式中的 greet 变量只会被提升到函数体内,因此 console.log(greet) 会输出 undefined

作用域

函数声明和函数表达式的一个区别是作用域。函数声明的作用域是全局作用域或函数体,而函数表达式的作用域是函数体。

// 函数声明
function greet(name) {
  console.log(`Hello, ${name}!`);
}

// 函数表达式
const greet = function (name) {
  console.log(`Hello, ${name}!`);
};

if (true) {
  // 函数声明
  function greet(name) {
    console.log(`Hello, ${name}!`);
  }

  // 函数表达式
  const greet = function (name) {
    console.log(`Hello, ${name}!`);
  };
}

console.log(greet); // 输出函数声明

在上面的示例中,函数声明中的 greet 变量在脚本执行时会被提升到全局作用域,因此 console.log(greet) 会输出函数声明。而函数表达式中的 greet 变量只会被提升到函数体内,因此 console.log(greet) 会输出 undefined

词法作用域和动态作用域

函数声明和函数表达式的一个区别是词法作用域和动态作用域。词法作用域是指函数的作用域由函数的声明位置决定,而动态作用域是指函数的作用域由函数的调用位置决定。

// 词法作用域
function greet(name) {
  console.log(`Hello, ${name}!`);

  function innerGreet(name) {
    console.log(`Hello, ${name}!`);
  }

  innerGreet("John"); // 输出 "Hello, John!"
}

greet("Mary"); // 输出 "Hello, Mary!"

在上面的示例中,函数 greet 和函数 innerGreet 都在函数 greet 的作用域内。这意味着函数 innerGreet 可以访问函数 greet 的变量 name

// 动态作用域
const greet = function (name) {
  console.log(`Hello, ${name}!`);

  const innerGreet = function (name) {
    console.log(`Hello, ${name}!`);
  };

  innerGreet("John"); // 输出 "Hello, undefined!"
};

greet("Mary"); // 输出 "Hello, Mary!"

在上面的示例中,函数 greet 和函数 innerGreet 都在函数 greet 的作用域内。但是,函数 innerGreet 只能访问函数 greet 的变量 name,而不能访问函数 greet 的变量 Mary

this

函数声明和函数表达式的一个区别是 thisthis 关键字是指当前执行的函数的作用域对象。在函数声明中,this 总是指向全局对象。而在函数表达式中,this 总是指向调用函数的作用域对象。

// 函数声明
function greet() {
  console.log(`Hello, ${this.name}!`);
}

greet(); // 输出 "Hello, undefined!"

// 函数表达式
const greet = function () {
  console.log(`Hello, ${this.name}!`);
};

greet(); // 输出 "Hello, undefined!"

在上面的示例中,函数声明中的 this 总是指向全局对象,因此 console.log(this.name) 会输出 undefined。而函数表达式中的 this 总是指向调用函数的作用域对象,因此 console.log(this.name) 会输出 undefined

变量绑定

函数声明和函数表达式的一个区别是变量绑定。函数声明中的变量在函数执行时被绑定到函数体,而函数表达式中的变量在函数调用时被绑定到函数体。

// 函数声明
function greet(name) {
  let message = "Hello, " + name + "!";
  return message;
}

const greeting = greet("John"); // 输出 "Hello, John!"

console.log(message); // ReferenceError: message is not defined

在上面的示例中,函数声明中的 message 变量在函数执行时被绑定到函数体,因此 console.log(message) 会输出 ReferenceError: message is not defined

// 函数表达式
const greet = function (name) {
  let message = "Hello, " + name + "!";
  return message;
};

const greeting = greet("John"); // 输出 "Hello, John!"

console.log(message); // ReferenceError: message is not defined

在上面的示例中,函数表达式中的 message 变量在函数调用时被绑定到函数体,因此 console.log(message) 会输出 ReferenceError: message is not defined

块级作用域

函数声明和函数表达式的一个区别是块级作用域。块级作用域是指变量的作用域由变量的声明位置决定。在函数声明中,变量在函数体中声明,因此变量的作用域是函数体。而在函数表达式中,变量在函数体中声明,因此变量的作用域是函数体。

// 函数声明
function greet() {
  {
    let name = "John";
    console.log(`Hello, ${name}!`); // 输出 "Hello, John!"
  }

  console.log(`Hello, ${name}!`); // ReferenceError: name is not defined
}

greet();

在上面的示例中,函数声明中的 name 变量在函数体中声明,因此变量的作用域是函数体。这意味着变量 name 只在函数体内有效,而在函数体外无法访问。

// 函数表达式
const greet = function () {
  {
    let name = "John";
    console.log(`Hello, ${name}!`); // 输出 "Hello, John!"
  }

  console.log(`Hello, ${name}!`); // ReferenceError: name is not defined
};

greet();

在上面的示例中,函数表达式中的 name 变量在函数体中声明,因此变量的作用域是函数体。这意味着变量 name 只在函数体内有效,而在函数体外无法访问。

全局作用域

函数声明和函数表达式的一个区别是全局