JavaScript中的函数表达式和函数声明介绍
不要混淆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)
仅仅返回1
和2
的数字之和 -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 }
,那么这就是一个匿名函数表达式。 - 如果函数有一个名字,例如前一个例子中的
sumB
和callback
,那么这就是一个有名字的函数表达式。
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