在本文中,我们展示了如何在 JavaScript 中使用函数。
函数是零个或多个输入参数到零个或多个输出参数的映射。
使用函数,我们可以减少代码的重复性并提高其清晰度。可以使用函数将更复杂的任务分成更简单的步骤。
函数可以分配给变量,作为参数传递给函数或从其他函数返回。
JS函数定义
JS函数是用function
关键字定义的。关键字后跟函数名称,用括号括起来并用逗号分隔的函数参数列表,以及用花括号 {}
括起来的函数体。
函数体由JS语句组成。函数使用 return
关键字返回值。
function add(x, y) { return x + y; } let z = add(10, 5); console.log(z);
该示例定义了一个简单的add
函数。
function add(x, y) { return x + y; }
这是函数的定义。它返回一个简单加法表达式的值。它有两个用逗号分隔的参数。使用return
关键字,我们将计算值传递给调用者。
let z = add(10, 5);
函数被调用。它接收整数参数。返回值存储在z
变量中。
JS函数表达式
function
关键字可用于在表达式中定义函数。函数表达式允许我们创建匿名函数。
函数表达式在其他编程语言中被称为lambda表达式。
let z = function add(x, y) { return x + y; } console.log(z(10, 10));
我们用函数表达式重写前面的例子。
let z = function add(x, y) { return x + y; }
我们将函数表达式传递给z
变量。
console.log(z(10, 10));
函数是通过z
变量调用的。
JS匿名函数
匿名函数没有名字。在许多情况下,定义命名函数是多余的。
setTimeout( function() { console.log('Hello there!') }, 3000 );
setTimeout
函数定义了一个处理函数,该函数在指定的毫秒数后执行。不需要定义命名函数;匿名函数很适合这里。
数组集合包含几个作用于其元素的函数。
let vals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let res = vals.reduce(function (x, y) { return x + y; }); console.log(res);
reduce
函数用于计算JS数组元素的总和。该函数将 reducer 函数作为参数。对数组的所有元素运行 reducer 的结果是总和值。
let res = vals.reduce(function (x, y) { return x + y; });
reducer 函数是一个匿名的 JS 函数。
JS函数默认值
在 JavaScript 中,函数的参数默认为undefined
。我们可以给函数参数自定义默认值;如果没有为参数提供值,则使用它们。
function power(a, b = 2) { if (b == 2) { return a * a } let value = 1 for (let i = 0; i < b; i++) { value *= a } return value; } let r1 = power(3) console.log(r1); let r2 = power(3, 3) console.log(r2); let r3 = power(3, 5) console.log(r3);
我们创建了一个power
函数。该函数有一个带有隐式值的参数。我们可以用一个或两个参数调用该函数。
$ node main.js 9 27 243
JS 可变函数
可变参数函数可以接受可变数量的参数。例如,当我们想要计算值的总和时,我们可能有四个、五个、六个等值要传递给函数。
我们使用 …(省略号)运算符在 JavaScript 中定义可变参数函数。
function sum(...vals) { return vals.reduce(function (x, y) { return x + y; }); } console.log(sum(1, 2)); console.log(sum(1, 2, 3)); console.log(sum(1, 2, 3, 4));
程序定义了一个sum
函数,它可以接受可变数量的参数。
function sum(...vals) { return vals.reduce(function (x, y) { return x + y; }); }
vals 是一个 JS 数组。我们使用它的reduce
函数来计算值的总和。 reduce
函数需要
$ node main.js 3 6 10
JS箭头函数
箭头函数是一种语法较短的匿名函数。它是用一对包含参数列表的括号定义的,后跟一个粗箭头 (=>) 和一对花括号 {}
分隔主体语句。
如果箭头函数只有一个参数,括号对可以省略。如果它包含单个语句,则花括号也可以省略。
let vals = [-1, 2, 3, -4, 5, 6, -7, 8, 9, 10]; let res = vals.filter(e => e > 0); console.log(res);
在示例中,我们过滤了一个整数数组。 filter
函数将谓词函数作为参数;它定义了过滤的值。谓词是用箭头函数定义的。
JS嵌套函数
嵌套函数,也称为内部函数,是在另一个函数内部定义的函数。
let user = { fname: 'John', lname: 'Doe', occupation: 'gardener' } function sayHello(u) { let msg = buildMessage(u); console.log(msg); function buildMessage(u) { return `${u.fname} ${u.lname} is a ${u.occupation}`; } } sayHello(user);
在示例中,我们有一个嵌套的buildMessage
函数,它是在sayHello
函数内部定义的辅助函数。
JS 闭包
闭包 是一个匿名的嵌套函数,它保留对定义在闭包主体之外的变量的绑定。闭包可以拥有自己的独特状态。当我们创建函数的新实例时,状态就会变得孤立。
function intSeq() { let i = 0; return function () { return i++; }; } let nextInt = intSeq(); console.log(nextInt()); console.log(nextInt()); console.log(nextInt()); console.log(nextInt()); let nextInt2 = intSeq(); console.log(nextInt2()); console.log(nextInt2());
我们有intSeq
函数,它生成一个整数序列。它返回一个递增 i
变量的闭包。
function intSeq() { let i = 0; return function () { return i++; }; }
函数中定义的变量具有局部函数作用域。但是,在这种情况下,即使在 i
函数返回后,闭包也绑定到 intSeq
变量。
let nextInt = intSeq();
我们调用intSeq
函数。它返回一个函数,该函数将增加一个计数器。返回的函数关闭变量i
以形成闭包。闭包绑定到nextInt
名称。
let nextInt2 = intSeq(); console.log(nextInt2()); console.log(nextInt2());
intSeq
函数的下一次调用返回一个新的闭包。这个新的闭包有自己独特的状态。
$ node main.js 0 1 2 3 0 1
JS高阶函数
高阶函数对其他函数进行操作,要么将它们作为参数,要么通过返回它们。
let vals = [-3, 0, 1, 2, 5, 4, 9, 11, 8, 7]; let isEven = e => e % 2 == 0; let isOdd = e => e % 2 != 0; function doFilter(vals, pred) { let filtered = []; for (let i = 0; i < vals.length; i++) { pred(vals[i]) ? filtered.push(vals[i]) : null; } return filtered; } let res = doFilter(vals, isEven); console.log(res); res = doFilter(vals, isOdd); console.log(res);
doFilter
是高阶函数。
function doFilter(vals, pred) { let filtered = []; for (let i = 0; i < vals.length; i++) { pred(vals[i]) ? filtered.push(vals[i]) : null; } return filtered; }
该函数将谓词函数(谓词是一个产生布尔值的函数)作为参数。它过滤掉所有满足给定谓词的值。
$ node main.js [ 0, 2, 4, 8 ] [ -3, 1, 5, 9, 11, 7 ]
JS成员函数
成员函数是在类定义中定义的函数。成员函数在某些语言中称为方法,包括 Java 和 C#。
class Person { constructor(firstName, lastName, email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } info() { return `${this.firstName} ${this.lastName}, ${this.email}`; } } let person = new Person('John', 'Doe', 'jdoe@example.com'); console.log(person.info());
类是用class
关键字定义的。
info() { return `${this.firstName} ${this.lastName}, ${this.email}`; }
info
是在类中定义的成员函数。
JS函数构造函数
可以使用函数构造函数创建 JS 对象。它将值作为参数。使用this
关键字设置属性。成员函数是使用this
和函数关键字创建的。使用 new
关键字创建新对象。
function Person(firstName, lastName, email) { this.firstName = firstName; this.lastName = lastName; this.email = email; this.info = function () { return `${this.firstName} ${this.lastName}, ${this.email}`; } } let person = new Person('John', 'Doe', 'jdoe@example.com'); console.log(person.info());
在程序中,我们定义了一个Person
类型。
function Person(firstName, lastName, email) {
Person
的构造函数是用function
关键字定义的。
this.info = function () { return `${this.firstName} ${this.lastName}, ${this.email}`; }
在构造函数定义中,我们定义了info
成员函数。
$ node main.js John Doe, jdoe@example.com
JS函数类型
JavaScript 也是一种强大的面向对象语言。每个函数也是一个对象。它的类型是Function
。可以使用new Function
构造函数创建函数,但不推荐这样做。
let x = 3; let y = 8; let square = new Function('x', 'return x * x'); let res = square(x); console.log(res); res = square(y); console.log(res);
在示例中,我们使用square
构造函数定义了Function
函数。
JS函数提升
提升是在执行代码之前将函数、变量或类的声明移动到其作用域顶部的过程。
console.log(sum(1, 2, 3, 4, 5)); function sum(...vals) { return vals.reduce((x, y) => x + y); }
我们在定义之前调用sum
函数。
但是,提升不适用于函数表达式。
console.log(sum(1, 2, 3, 4, 5)); let sum = (...vals) => vals.reduce((x, y) => x + y);
程序以错误结束:ReferenceError: Cannot access 'sum' before initialization
。
JS 生成器
生成器是可以退出并稍后重新进入的函数。它们的上下文(变量绑定)在函数调用中保存。使用 function*
语法创建生成器函数。
调用生成器函数返回一个迭代器。当迭代器的next
方法被调用时,生成器函数的主体被执行到第一个yield
表达式;它返回一个包含生成值的value
属性的对象。 done
property 指示生成器是否已生成其最后一个值。
function* idxGen(max) { let idx = 0; while (idx < max) { yield idx++; } } const g = idxGen(100); for (let i of g) { console.log(i); }
该示例创建了一个生成器,它生成的索引达到指定的最大值。
function* idxGen(max) { let idx = 0; while (idx < max) { yield idx++; } }
我们定义了idxGen
生成器函数。 yield
关键字退出生成器并返回一个值。下次调用迭代器的 next 函数时,我们继续执行 yield 关键字后的行。保留局部 idx
变量。当 idx
达到 max
值时,生成器生成其最后一个值并将 done
属性设置为 true。
const g = idxGen(100);
我们称idxGen
;它返回一个迭代器。
for (let i of g) { console.log(i); }
在 for 循环中,我们迭代生成的值。
JS IIFE
立即调用函数表达式 (IIFE) 是定义为表达式并在创建后立即执行的函数。它使用函数作用域产生词法作用域。在引入 JS 模块之前,这是一种广泛使用的方法。
let sum = (function (a, b) { return a + b; })(15, 50); console.log(sum);
我们定义了一个带有两个参数的立即执行的加法函数。结果存储在sum
变量中。
$ node main.js 65
在本文中,我们介绍了 JavaScript 函数。
列出所有 JavaScript 教程。