这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
闭包
高阶函数除了可以接受函数为参数,还可以返回一个函数作为返回的结果
闭包总结来说就是,一个作用域使用了另一个作用域中的变量。那怎么使用呢?用返回的函数。
转换成Java视角,就是一个类定义私有变量private,其他类不能直接访问,只能通过get或者set方法获得或者修改这个私有变量。
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum() 返回一个函数,不立刻求和
f(); // 15 等调用函数时,才真正求和。
//内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中
function count() {
var arr = [];
for (var i=1; i<=3; i++) { //使用的是var
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
//最后调用都是16 因为他的循环数使用的是var没有局部作用域,最后的i都是4,
f1(); // 16
f2(); // 16
f3(); // 16
//我们可以用该函数的参数绑定循环变量当前的值
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
//或者
//改用let或者const就会恢复正常,因为他们有局部作用域,每一次循环都是新建一个变量
function count() {
var arr = [];
for (let i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
返回函数不要引用任何循环变量,或者后续会发生变化的变量
利用闭包,我们可以实现类似Java中的类的不同实例的感觉。
function make_pow(n) {
return function (x) {
return Math.pow(x, n);
}
}
// 创建两个新函数: 类似于不同的实例类 Person 一个名字叫2 一个名字叫3
var pow2 = make_pow(2);
var pow3 = make_pow(3);
console.log(pow2(5)); // 25
console.log(pow3(7)); // 343
立刻执行的匿名函数
上述代码中有一段这样的代码,他的作用是创建一个匿名函数并立刻执行
(function (n) {
return function () {
return n * n;
}
})(i) //其中的i为传入,传入之后即为n
//像是这样
(function (x) {
return x * x;
})(3);
//他和 3 * 3 结果没有区别
没有给函数名称命名的函数,为匿名函数
箭头函数
ES6新增了箭头函数,他用一个等于加上大于号,定义一个函数。
x => x * x
箭头函数简化了函数的定义,他可以把定义的函数体{...}的括号和return省略。当然如果有多条语句,就不能省略
x => {
if(x = 1){
return 1;
}else {
return x * x;
}
}
如果参数是多个,就不能省略参数的括号
(x,y) => {
return x * y;
}
当我们在单表达式中,返回一个对象
x => ({foo: x}) // 主要要用小括号包裹,不然对象的{}和函数体的{}会造成冲突
箭头函数中的this
箭头函数内部的
this是词法作用域,由上下文确定
之前有说到this关键字的指向问题。那么箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25 不再需要之前用var捕获this的写法了
生成器generator
ES6引入了生成器的概念,generator由function*定义,并且,除了return语句,还可以用yield返回多次。
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
直接调用一个generator和调用函数不一样
第一种方式使用generator的next方法
function* fib(max) { //斐波那契数列
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
第二种方式可以使用for of的方式调用
for (var x of fib(10)) {
console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}