全文共 2416字,预计学习时长 5分钟
图片来源:Unsplash/Luca Bravo
函数是编程中的关键部件之一。这些函数可执行特定任务,并可反复调用执行。将Javascript中的函数和其他编程语言中的函数相比较,其中最大的区别在于Javascript函数为一级对象,这意味着Javascript中的函数表现类似于对象,可作为变量、数组和其他对象。
本文就定义函数的三种不同方法进行讨论:
1. 函数声明
2. 函数表达式
3. 生成器函数
1. 函数声明
函数声明可能是最常见的方式了。观察如下语句:
function name (parameter){ statements }
函数声明语句
函数由关键字函数、函数的强制名称和括号内的参数组成(定义函数也可无参数)。最后,大括号内则是函数的主体,用以执行实际任务。
理解形参和实参的区别很重要。形参是定义函数时的一个变量。在调用函数时,实参则是输入函数形参的实际数据。
首先,看一个简单实例:
function hello(name){console.log("Hello "+ name)}hello('stuti')// Hello stutihello(12)// Hello 12
名为hello的函数以实际参数名称声明,在控制台记录消息。从本例中,可以看出,因为实际参数上无指定类型,所以其既适用于string函数,也适用于number函数。倘若只是希望该函数是一个名称而不是数值呢?很遗憾,由于Javascript中没有预建法来实现这一点,必须手动确定输入函数的实际参数类型,如下所示:
function hello(name) { if (typeof name === 'string') console.log("Hello " + name) else console.log("Please input a Name")}hello(12) // Plese input a Name
默认情况下,函数返回未定义变量。若要返回任何其他值,则函数必须具备返回语句,而由该语句指定返回值。
function something(){}console.log(something()) // undefinedfunction notSomething(){ return 1}console.log(notSomething()) // 1
函数声明中提升是什么?
简单地说,这意味着在执行代码时,无论何处声明函数或变量,它们均会移动至作用域的顶部。这也就是所谓的提升。
观察下方实例:
myName()// My name is Stuti Chahuhanfunction myName() { console.log(`My name is Stuti Chauhan`)}
函数声明中的提升
此处甚至是在声明之前就调用了这个函数——提升。
2. 函数表达式
图片来源:unsplash.com/@creativegangsters
函数表达式与函数声明极为相似,连语句都不甚相同。最主要的区别在于函数表达式不以关键字函数开头,且函数名称可选,在此情况下,该函数表达式则可以成为一个匿名函数。如果函数有名称,则将其称为命名函数表达式。
let checkNumber = function check (num){ return (num %2==0)?"even" : "odd" }console.log(checkNumber(50)) // even
函数表达式的例子
现在来观察一下定义上述函数的匿名法。
//Anonymous Function let checkNumber = function (num){ return (num %2==0)?"even" : "odd" }console.log(checkNumber(50)) // even
匿名函数表达式
函数声明和函数表达式最关键的区别就在于函数表达式无提升功能。若在函数表达式中尝试与提升函数声明相同的项目,则会出现报错。
myName()// ReferenceError: myName is not definedlet myName =function () { console.log(`My name is Stuti Chauhan`)}
函数表达式中无提升
IIFE(立即执行函数表达式)
这意味着函数一旦定义就开始运行,而函数表达式附在分组操作符()中,
( function () { let num = 4 return num })//4
为什么典型的函数表达式需要IIFE?一般定义一个函数,随后多次调用。但倘若只想调用一次用来生成输出,并且不再使用该函数呢?由此就出现了IIFE。该函数会立即执行,并在以后不再经程序访问。因为不需再调用该函数,所以它也不需要名称,因此匿名函数表达式首选IIFE。
3. 生成器函数
图片来源:unsplash.com/@roman_lazygeek
普通函数遵循运行-完成的模型,不能在执行最后一行之前停止运行。若想在执行过程中退出,必须返回或抛出一个错误。
而生成器函数可以在执行过程中停止。当其调回时,仍然从停止的地方继续。
该函数与普通函数一样进行声明,但不同之处在于生成器函数在function关键字后面带有星号*,其间可包含任意数量的空格。
还有一点需要注意:在JavaScript中,生成器是一个函数,该函数返回一个对象,在该对象上可调用next(),每次调用next()都会返回一个结构如下的对象:
{ value: Any, done: true|false}
此对象包含两个属性:value和done。Value是对象的实际值,而done规定了函数终止的属性——默认值为false,当其变为true时,则函数停止。
通过一个简单的例子来理解这点:
function * generatorFunction(){ console.log('first to execute'); yield 'takes a pause'; console.log(' printed after the pause'); yield 'end of the function'; }const gen = generatorFunction();console.log(gen.next().value); // first to execute // takes a pauseconsole.log(gen.next().value); // printed after the pause // end of the functionconsole.log(gen.next().value); // undefined
函数本体中,不使用return关键字——而是使用yeild,如果使用了return,则会将done属性更改为true,函数将结束——之后的任何操作都不会执行。Yield给出为其分配的值。
首先,在调用函数前先定义函数,同时调用一个生成器函数,形成一个生成器对象,存储在变量中。
然后在使用next()和value属性时调用对象。第一次使用next()时,函数执行开始。首先,运行console.log (“首次执行”)并将其记录在控制台中,然后遇到yield—输出 “暂停”值,执行停止。
第二次调用next()时,它从上次暂停处继续。同样,首先运行console.log(),再次遇到yield,生成“函数结束”值,函数停止。
第三次调用next()时,结果是未定义。这是因为由生成器函数生成的对象只能迭代一次——该对象现在是无用的,必须生成一个新对象才能重新启动程序。
function* generator() { yield "some value"; return "ends here"; yield "will never execute"; yield "never reach here"}var gen = generator()console.log(gen.next()); // { value: "some value