1.4.1 定义函数
函数声明+函数表达式(普通函数+生成器函数)、箭头函数、函数构造器
定义函数的几种方式:
普通函数:函数声明、函数表达式
生成器函数:生成器函数声明、生成器函数表达式
箭头函数
构造函数:用 new 操作符
不推荐使用这种方式来创建函数。因为它们都需要函数体作为字符串,这可能会妨碍 JavaScript 引擎的一些优化,还可能会导致其它问题。
说明:GeneratorFunction 不是全局对象,但可以从生成器函数实例中获取
接下来,详细介绍下普通函数的函数声明和函数表达式。
1. 函数声明
函数声明,也称函数语句。
function declaration
function statement
2. 函数表达式
函数表达式,可以是匿名的,也可以有自己的名字。
an anonymous function expression,匿名函数表达式
a named function expression,命名函数表达式
一个好处:更方便调试,因为堆栈跟踪会包含函数的名字
以上两个例子都不是以 function 关键字开头的。涉及到函数的语句,不以 function 关键字开头的,就是函数表达式。
当函数只使用一次时,一个常见的模式就是 IIFE,Immediately Invoked Function Expression,立即调用函数表达式。IIFE 也是一种函数表达式,它在声明的同时被调用:
注意:函数表达式不会被提升到作用域的开头,所以它在定义之前是不能被调用的。
3. 注意事项
3.1 声明 vs 表达式 vs 构造器
Declaration vs. Expression vs. Constructor
它们做的事情大致相同,但有一些细微的差别:
函数名称 vs 函数变量
函数名称不能修改,而函数变量可以被重新赋值
函数表达式中的函数名,只能在函数体中使用
当函数通过
toString()
方法进行序列化时,会包含函数名
是否发生函数提升
用函数声明定义的函数,可以在函数声明本身之前使用(会提升)
用函数表达式或构造函数定义的函数,不会发生函数提升(不会提升)
是否继承当前作用域
用函数声明和函数表达式定义的函数,会继承当前作用域(函数会形成一个闭包)
用 Function 构造函数定义的函数,不会继承任何作用域,除了全局作用域(所有的函数都会继承)
是否只解析一次
用函数声明和函数表达式定义的函数,只解析一次。虽然函数表达式每次都会创建一个闭包,但函数体不会重新解析
用 Function 构造函数定义,每次调用都会解析一次(所以不建议使用)
注:嵌套在 Function() 构造函数的字符串参数中的函数表达式和函数声明,不会重复解析
3.2 函数声明“变”表达式
函数声明很容易变成函数表达式(通常是无意的)。比如:
当函数声明成了表达式的一部分
当函数声明不再是函数或脚本的“源元素”(source element),源元素是脚本或函数体中的非嵌套语句
3.x 其它
eval(str)
在 JavaScript 中,还可以根据条件定义函数。如下:
4. 扩展阅读
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Last updated