likes
comments
collection
share

JavaScript中的函数表达式和函数声明介绍

作者站长头像
站长
· 阅读数 78

不要混淆JavaScript中的函数表达式和函数声明

在JavaScript中,function 关键字做了一个简单的工作:创建一个函数。然而,你使用该关键字定义函数的方式可以创建具有不同属性的函数。

在这篇文章中,你会发现如何使用function 关键字来编写函数声明和函数表达式,以及这2种类型的函数之间有什么区别。

目录

1.函数表达式与函数声明

函数声明和函数表达式是使用function 关键字创建函数的两种方式。

让我们选一个例子来证明两者的区别--让我们为一个对数字求和的函数创建2个版本。

function sumA(a, b) {
  return a + b;
}
(function sumB(a, b) {
  return a + b;
});
sumA(1, 2); // ???
sumB(1, 2); // ???

在一种情况下,你像往常一样定义该函数(sumA 函数)。在另一种情况下,该函数被放在一对小括号中(sumB 函数)。

如果你调用sumA(1, 2)sumB(1, 2) ,会发生什么?

正如预期的那样,sumA(1, 2) 仅仅返回12 的数字之和 -3 。然而,调用sumB(1, 2) ,会出现一个错误Uncaught ReferenceError: sumB is not defined

解释是:sumA 是用一个函数声明创建的,它在当前作用域中创建了一个函数变量(与函数名相同)。但是sumB 是用一个函数表达式创建的(它被包裹在圆括号中),这并没有在当前作用域中创建一个函数变量

如果你想访问用函数表达式创建的函数,那么就把函数对象保存到一个变量中:

// Works!
const sum = (function sumB(a, b) {
  return a + b;
});
sum(1, 2); // => 3

这里有一个关于如何区分函数声明和函数表达式的简单提示。

如果语句以function 关键字开头,那么它就是一个函数声明,否则就是一个函数表达式

// Function declaration: STARTS with `function` keyword
function sumA(a, b) {
  return a + b;
}
// Function expression: DOES NOT START with `function` keyword
const mySum = (function sumB(a, b) {
  return a + b;
});
// Function expression: DOES NOT START with `function` keyword
[1, 2, 3].reduce(function sum3(acc, number) { 
  return acc + number 
});

从更高的角度来看,函数声明对于创建独立的函数很有用,但函数表达式作为回调很好。

现在,让我们更深入地了解函数声明和函数表达式的行为。

2.函数声明

正如你在前面的例子中已经看到的,sumA 是一个函数声明。

// Function declaration
function sumA(a, b) {
  return a + b;
}
sumA(4, 5); // => 9

当一条语句中包含function 关键字,后面是函数名,一对小括号中的参数(param1, param2, paramN) ,以及包含在一对大括号中的函数体{ } ,就会发生函数声明

函数声明创建了一个函数变量--一个与函数名称相同的变量(例如,前面例子中的sumA )。这个函数变量在当前的作用域*(在函数声明之前之后*),甚至函数的作用域都可以访问。

函数变量通常被用来调用函数或将函数对象传递给其他函数(到高阶函数)。

例如,让我们写一个函数sumArray(array) ,对一个数组(该数组可以包含数字或其他数组)的项目进行递归求和。

sumArray([10, [1, [5]]]); // => 16
function sumArray(array) {
  let sum = 0;
  for (const item of array) {
    sum += Array.isArray(item) ? sumArray(item) : item;
  }
  return sum;
}
sumArray([1, [4, 6]]); // => 11

function sumArray(array) { ... } 是一个函数声明。

sumArray([1, [4, 6]]) 包含函数对象的函数变量sumArray ,在当前的作用域中可用:在函数声明sumArray([10, [1, [5]]]) 之前和之后,也在函数本身的作用域sumArray(item) (允许递归调用)。

由于hoisting,函数变量在函数声明之前是可用的。

2.1 函数声明的应做和不应做的事

函数声明语法的作用是创建独立的函数。函数声明应该在全局范围内或直接在其他函数的范围内。

// Good!
function myFunc1(param1, param2) {
  return param1 + param2;
}
function bigFunction(param) {
  // Good!
  function myFunc2(param1, param2) {
    return param1 + param2;
  }
  const result = myFunc2(1, 3);
  return result + param;
}

出于同样的原因,不建议在条件语句(if )和循环(while,for )中使用函数声明。

// Bad!
if (myCondition) {
  function myFunction(a, b) {
    return a * b;
  }
} else {
  function myFunction(a, b) {
    return a + b;
  }
}
myFunction(2, 3);

创造条件性函数最好使用函数表达式。

3.函数表达式

function 关键字在一个表达式内创建一个函数(无论是否有名称)时,就会出现函数表达式。

下面是使用表达式创建函数的例子:

// Function expressions
const sum = (function sumB(a, b) {
  return a + b;
});
const myObject = {
  myMethod: function() {
    return 42;
  }
};
const numbers = [4, 1, 6];
numbers.forEach(function callback(number) {
  console.log(number);
  // logs 4
  // logs 1
  // logs 1
});

在函数表达式内部创建的函数有2种:

  • 如果表达式中的函数没有名字,例如:function() { return 42 } ,那么这就是一个匿名函数表达式
  • 如果函数有一个名字,例如前一个例子中的sumBcallback ,那么这就是一个有名字的函数表达式

3.1 函数表达式的应做和不应做的事

函数表达式很适合作为回调或由条件创建的函数:

// Functions created conditionally
let callback;
if (true) {
  callback = function() { return 42 };
} else {
  callback = function() { return 3.14 };
}
// Functions used as callbacks
[1, 2, 3].map(function increment(number) {
  return number + 1;
}); // => [2, 3, 4]

如果你已经创建了一个命名的函数表达式,请注意,函数变量只能在创建的函数范围内使用:

const numbers = [4];
numbers.forEach(function callback(number) {
  console.log(callback); // logs function() { ... }
});
console.log(callback); // ReferenceError: callback is not defined

callback 是一个命名的函数表达式,因此 callback函数变量只能在callback 函数范围内使用,而不能在外部使用。

然而,如果你将函数对象存储到一个普通变量中,那么你可以在函数范围内外从该变量中访问该函数对象。

const callback = function(number) {
  console.log(callback); // logs function() { ... }
};
const numbers = [4];
numbers.forEach(callback);
console.log(callback); // logs function() { ... }

4.总结

根据你使用function 关键字来创建函数的方式,你可以以2种方式结束对函数的创建:函数声明和函数表达。

当你用function 关键字开始语句时就会发生函数声明:

// Function declaration
function sumA(a, b) {
  return a + b;
}

函数声明对于创建独立的、通用的函数很有用。

然而,如果一个语句没有以function 关键字开头,那么你就有一个函数表达式:

// Function expression
(function sumB(a, b) {
  return a + b;
});

使用函数表达式创建的函数对于创建回调或按条件的函数很有用。

转载自:https://juejin.cn/post/7125999296347897863
评论
请登录