原文来自印记中文:函数表达式 (javascript.info)
这里记录一些易错点
函数表达式的写法如下:
let sayHi = function() {
alert( "Hello" );
};
函数是一个值
无论函数是如何创建的,函数都是一个值。
上面的语句,如果添加一个
alert( sayHi ); // 显示函数代码
则会完整的打印整个函数的代码
易错点:函数的复制
function sayHi() { // (1) 创建
alert( "Hello" );
}
let func = sayHi; // (2) 复制
func(); // Hello // (3) 运行复制的值(正常运行)!
sayHi(); // Hello // 这里也能运行(为什么不行呢)
解释一下上段代码发生的细节:
(1)
行声明创建了函数,并把它放入到变量sayHi
。(2)
行将sayHi
复制到了变量func
。请注意:sayHi
后面没有括号。如果有括号,func = sayHi()
会把sayHi()
的调用结果写进func
,而不是sayHi
函数 本身。- 现在函数可以通过
sayHi()
和func()
两种方式进行调用。
我们也可以在第一行中使用函数表达式来声明 sayHi
:
let sayHi = function() { // (1) 创建
alert( "Hello" );
};
let func = sayHi;
// ...
这两种声明的函数是一样的。
回调函数
我们写一个包含三个参数的函数 ask(question, yes, no)
:
question
关于问题的文本yes
当回答为 “Yes” 时,要运行的脚本no
当回答为 “No” 时,要运行的脚本
函数需要提出 question
(问题),并根据用户的回答,调用 yes()
或 no()
:
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "You agreed." );
}
function showCancel() {
alert( "You canceled the execution." );
}
// 用法:函数 showOk 和 showCancel 被作为参数传入到 ask
ask("Do you agree?", showOk, showCancel);
在实际开发中,这样的函数是非常有用的。实际开发与上述示例最大的区别是,实际开发中的函数会通过更加复杂的方式与用户进行交互,而不是通过简单的 confirm
。在浏览器中,这样的函数通常会绘制一个漂亮的提问窗口。但这是另外一件事了。
ask
的两个参数值 showOk
和 showCancel
可以被称为 回调函数 或简称 回调。
主要思想是我们传递一个函数,并期望在稍后必要时将其“回调”。在我们的例子中,showOk
是回答 “yes” 的回调,showCancel
是回答 “no” 的回调。
我们可以用函数表达式对同样的函数进行大幅简写:
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"Do you agree?",
function() { alert("You agreed."); },
function() { alert("You canceled the execution."); }
);
这里直接在 ask(...)
调用内进行函数声明。这两个函数没有名字,所以叫 匿名函数。这样的函数在 ask
外无法访问(因为没有对它们分配变量),不过这正是我们想要的。
这样的代码在我们的脚本中非常常见,这正符合 JavaScript 语言的思想。
一个函数是表示一个“行为”的值
字符串或数字等常规值代表 数据。
函数可以被视为一个 行为(action)。
我们可以在变量之间传递它们,并在需要时运行。
函数表达式 vs 函数声明
- 函数声明:在主代码流中声明为单独的语句的函数。 // 函数声明
function sum(a, b) {
return a + b;
}
- 函数表达式:在一个表达式中或另一个语法结构中创建的函数。下面这个函数是在赋值表达式
=
右侧创建的: // 函数表达式
let sum = function(a, b) {
return a + b;
};
在函数声明被定义之前,它就可以被调用。
例如,一个全局函数声明对整个脚本来说都是可见的,无论它被写在这个脚本的哪个位置。
这是内部算法的原故。当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数。我们可以将其视为“初始化阶段”。
在处理完所有函数声明后,代码才被执行。所以运行时能够使用这些函数。
函数表达式在代码执行到它时才会被创建。只会发生在 (*)
行。为时已晚。
函数声明的另外一个特殊的功能是它们的块级作用域。
严格模式下,当一个函数声明在一个代码块内时,它在该代码块内的任何位置都是可见的。但在代码块外不可见。
什么时候选择函数声明与函数表达式?
根据经验,当我们需要声明一个函数时,首先考虑函数声明语法。它能够为组织代码提供更多的灵活性。因为我们可以在声明这些函数之前调用这些函数。
这对代码可读性也更好,因为在代码中查找 function f(…) {…}
比 let f = function(…) {…}
更容易。函数声明更“醒目”。
……但是,如果由于某种原因而导致函数声明不适合我们(我们刚刚看过上面的例子),那么应该使用函数表达式。
暂无评论内容