1 定义
1. 函数:是一段可以通过其名称被调用的代码,他可以传递参数并返回只=值。
2. 方法:是一段必须通过其名称及其关联对象的名称被调用的代码。
// 一个简单的函数
var simple = (a) => {return a};
simple(5); // 用其名称调用
// 一个简单的方法
var obj = {
simple: (a) => {return a}
}
obj.simple(5) // 用其名称及其关联对象调用
3. 引用透明性:所有的函数对于相同的输入都将返回相同的值。
4. 纯函数:对于给定的输入返回相同的输出。
5. javascript 是函数式编程语言。
6. 高阶函数:接受函数作为参数并且/或者返回函数作为输出的函数。
2 高阶函数
2.1 every 函数
对数组中的每个元素都执行一次指定的函数(callback)。如果回调函数对每个元素执行后都返回 true ,every 将返回 true,否则返回false。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。
[NaN,NaN,NaN].every(isNaN) // true
[NaN,NaN,4].every(isNaN) // false
2.2 some 函数
对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。
[NaN,NaN,NaN].every(isNaN) // true
[3,4,4].every(isNaN) // false
2.3 sort 函数
arrayObject.sort(sortby)
如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
- 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
- 若 a 等于 b,则返回 0。
- 若 a 大于 b,则返回一个大于 0 的值。
[9,1,11].sort() // [1, 11, 9]
[9,1,11].sort((a,b)=>{return a-b;}) // [1, 9, 11]
3 闭包
1. 闭包:闭包就是一个内部函数。
2. 内部函数:在另一个函数内部的函数。
3. 闭包的作用域:
- 可以访问在它自身声明之内声明的变量;
function outer() {
function inner(){
let a = 5;
console.log(a); // 5
}
inner();
}
- 对全局变量的访问;
let global = 'global';
function outer() {
function inner(){
let a = 5;
console.log(global);
}
inner(); // global
}
- 可以访问外部函数变量的访问。
let global = 'global';
function outer() {
let outer = 'outer';
function inner(){
let a = 5;
console.log(outer);
}
inner(); // outer
}
4. 闭包可以记住它的上下文
var fn = (arg) => {
let outer = 'visible';
let innerFn = () => {
console.log(outer);
console.log(arg)
}
return innerFn;
}
outer = 'global'
var closureFn = fn(5);
closureFn(); // visible 5
当 innerFn 被返回时,innerFn被视为闭包,并相应地设置了它的作用域,所以,返回函数的引用存储在 closureFn 中。
4 数组的函数式编程
4.1 map函数
map 函数返回了给定函数转换后的值,故也称为投影函数或转换函数。
[1,2,3].map(parseInt); // [1, NaN, NaN]
原因:map 接受三个参数 element,index,arr;parseInt 接受两个参数 parse,radix。
如果把 parseInt 传给 map,map函数会把 index 的值传给 parseInt 的 radix。
解决方法:
const unary = (fn) => {
return fn.length === 1 ? fn : (arg) => fn(arg)
}
[1,2,3].map(unary(parseInt)); // [1,2,3]
4.2 filter 函数
对数组中的每个元素都执行一次指定的函数(callback),并且创建一个新的数组,该数组元素是所有回调函数执行时返回值为 true 的原数组元素。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略,同时,新创建的数组也不会包含这些元素。
回调函数可以有三个参数:当前元素,当前元素的索引和当前的数组对象。
[1,2,3,4,5].filter((element)=>{
return element > 3
})
// [4, 5]
4.3 concat
用于连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
[1,2,3].concat([5,6,7]); // [1, 2, 3, 5, 6, 7]
4.4 reduce
接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值将。即数组元素计算为一个值(从左到右)
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
total 必需。初始值, 或者计算结束后的返回值。
currentValue 必需。当前元素。
currentIndex 可选。元素的索引。
arr 可选。当前元素所属的数组对象。
initialValue 可选。传递给函数的初始值。
[1,2,3,4].reduce((total,currentValue)=>{return total+currentValue;}) // 10
[1,2,3,4].reduce((total,currentValue)=>{return total*currentValue;},0); // 0
[1,2,3,4].reduce((total,currentValue)=>{return total*currentValue;},1); // 24
4.5 reduceRoght
将数组元素计算为一个值(从右到左)。
5 Generator
5.1 基础知识
function* gen(){
return 'first generator'
}
let genResult = gen();
console.log(genResult);
// gen{[[GeneratorStatus]]: "suspended",[[GeneratorReceiver]]: Window}
上面结果说明了genResult 不是一个普通的函数,而是一个 Generator 原始类型的实例。
如何从该 Generator 实例中获取值?
答案:调用该实例的 next 函数。
console.log(genResult.next()); // {value: "first generator", done: true}
故,用以下方法来获取值:
console.log(genResult.next().value); // first generator
5.2 yield 关键字
function* genSequenceFun() { yield 'first'; yield 'second'; yield 'third'}let genSequence = genSequenceFun();console.log(genSequence.next().value); // firstconsole.log(genSequence.next().value); // secondconsole.log(genSequence.next().value); // third
yield 使 Generator 函数暂停了执行并将结果返回给调用者。因此,当第一次调用 genSequenceFun 时,函数看到了 yield 后面的值是first,yield 将函数置于暂停模版并返回了该值(而且它准确地记住了暂停的位置)。当下一次调用 genSequenceFun 时(使用相同的实例变量),Generator 函数将从它中断的地方回复执行。
5.3 done属性
每次对 next 函数的调用都将返回一个如下所示的对象:
[value: 'value', done: false]
done 它是一个判断 Generator 序列是否已被完全消费的属性。
function* genSequenceFun() { yield 'first'; yield 'second'; yield 'third'}let genSequence = genSequenceFun();console.log(genSequence.next()); // {value: "first", done: false}console.log(genSequence.next()); // {value: "second", done: false}console.log(genSequence.next()); // {value: "third", done: false}console.log(genSequence.next()); // {value: undefined, done: true}
可见, done 属性清楚的告诉我们 Generator 序列已被完全消费了,所以,当 done = true 时,就应该停止调用 Generator 的实例 next
5.4 注意事项
- 不能无限制地调用 next 从 Generator 中取值。
function* gen() {
return 'first generator'
}
let genResult = gen();
console.log(genResult.next().value); // first generator
console.log(genResult.next().value); // undefined
原因:Generator 如同序列,一旦序列中的值被消费,你就不能再次消费它。
为了能够再次消费该序列,需要创建另一个 Generator 实例:
function* gen() {
return 'first generator'
}
// 第一个序列let
genResult1 = gen();
console.log(genResult1.next().value); // first generator
// 第二个序列let
genResult2 = gen();
console.log(genResult2.next().value); // first generator
- 所有带 yield 的 Generator 都会以惰性求值的顺序执行。
惰性求值,即代码指导调用时才会执行,当我们需要的时候,相应的值才会被计算并返回。
- for 循环:利用了 Generator 的 done 属性进行遍历。
function* genSequenceFun() { yield 'first'; yield 'second'; yield 'third'}let genSequence = genSequenceFun();for (let value of genSequence) { console.log(value);}
// first,second,third
5.5 向 Generator 传递数据
function* sayFullName() { let firstName = yield; let secondName = yield; console.log(firstName + secondName);}let fullName = sayFullName();fullName.next();fullName.next('Huang');fullName.next('Xiaoming');
// HuangXiaoming
当第一次调用 next 时,代码将暂定并返回于此:let firstName = yield;
由于没有通过 yield 发送任何值,因此 next 返回 undefined
第二次调用 next 时,传递数据 Huang,Generator 将从上一次暂定的状态(let firstName = yield;)中恢复,并将 yield 替换成 Huang,firstName 被赋值后,执行将恢复,直到遇见 yield 再次暂停。以此类推。