突然发现,虽然天天都写,但是这里头还有不少东西很模糊,放一下自己的探索过程。
此次只讨论该两种形式:
function add(a, b) {
return a + b;
}
const add = (a, b) => a + b;
接下来对比一下两者之间差异,也许很多地方看起来都很针对函数声明。
使用函数声明方式创建的函数,可以在其有效作用域的任何位置进行使用,包括函数声明之前使用也是可以的,这便是函数提升。
// OK
console.log(add(10, 20)); // 30
function add(a, b) {
return a + b;
}
而函数表达式并不存在这个规则,其遵从变量声明规则:
// Err
console.log(add(10, 20));
const add = (a, b) => a + b;
那能不能用 var
进行声明,让其提升呢?不行,var
声明的变量只是变量本身提升了,值是不会跟上的,只能说你可以找到变量,但是在达到声明语句之前,都只是 undefined
。
对于函数声明来说,是可以存在重复声明的,当存在重复声明时,最终落实的是最后一个函数:
console.log(add(10, 20)); // 0
// 被后者覆盖
function add(a, b) {
return a + b;
}
// 该函数生效
function add(a, b) {
return 0;
}
好,这个了解到了,那么再扩展一下:
如果在其中插入一个同名变量会怎么样,请问谁会覆盖谁?(分别给出
var
与const
两者的执行结果)
先回答 const
的表现:但凡使用 const
导致重复声明(包括与函数名称冲突),统一异常停止。
至于 var
,那就很有意思了,首先是,可以共存:
console.log(add); // [Function: add]
console.log(add(10, 20)); // 0
var add = "add";
console.log(add); // "add"
function add(a, b) {
return a + b;
}
function add(a, b) {
return 0;
}
console.log(add); // "add"
可以看出,在达到变量声明之前,add
这个名称都归第二个函数所有,而变量完成声明之后,就成了字符串 "add"
。
至于为什么执行经过了函数声明却没有任何变化,因为函数声明语句在一开始就已经执行好了。
那么函数表达式呢,其表现已经在扩展题当中提到了:
console.log(add); // undefined
var add = (a, b) => a + b;
console.log(add(10, 20)); // 30
var add = () => 0;
console.log(add(10, 20)); // 0
当然,该表现只要知道 var
的行为逻辑就很容易理解。而对于函数表达式来说,通常都是 const
声明,所以通常不会存在重复声明问题,该问题也是需要自己避免的。
这么看下来,你就是想捧函数表达式吧?
至少我个人更习惯如此,并不需要函数提升,先有声明再使用也符合正常。
函数表达式并不存在 this
问题,没用规定说函数表达式都是箭头函数形式是吧,而使用箭头函数恰恰是用来解决 this
绑定问题的。
我在想反例时,发现好像有一种奇怪的存在,那就是非箭头函数形式的函数表达式:
const add = function (a, b) {
return a + b;
}
因为我突然想起来,这个函数好像可以取一个名字,只是说多数情况下,不会特意给其一个名称,因为没什么意思。
但现在回头看,真的会没用吗,就想试试水,因为记得一规范指南当中提到,这是最推荐的写法(虽然我一直都没有照做)。
const fn = function add(a, b) {
console.log(a, b);
};
console.log(fn); // [Function: add]
console.log(add); // ReferenceError: add is not defined
啊,这种写法导致函数声明不起效果,根本找不到 add
。不过慢着,这个函数叫什么来着,居然是 [Function: add]
?于是尝试在 add()
函数体内找 add
,居然真的可以:
const fn = function add(a, b) {
console.log(add); // [Function: add]
return a + b;
};
console.log(fn(1, 2)); // 3
哇,看似好像发现了一个什么了不得的东西,但是别急,在这个场景下是没用的。若是真的想递归调用,可以选择直接找 fn()
,而不需要在内部找。
当然,也可以这么玩:
(function dfs(n) {
if (n === 0) {
return;
}
dfs(n - 1);
console.log(n);
})(5);
// 1
// 2
// 3
// 4
// 5
-END-