文章目录
- 1、什么是高阶函数:
- 2、高阶函数的应用:
- 1. AOP 面向切片编程
- 2. vue 2.0 也会用到 函数劫持(AOP切片)的思想
- 3. react 里的setState的事务transcation
- 4. 保存变量
说到异步肯定要说到回调函数:回调函数是高阶函数的一种;
1、什么是高阶函数:
- 如果函数的参数是一个函数
javascript">function (func){
func();
}
- 一个函数返回了一个函数(返回函数)
javascript">function (){
return function (){}
}
2、高阶函数的应用:
1. AOP 面向切片编程
或者重写一些方法的时候会用到
javascript">function say() {
//todo...
console.log('hello')
}
//拓展函数,不想破环原有的函数,不然别人调用say(),say就被修改了。但还想在函数之前或之后添加一些逻辑
// 这是我们设想的最后实现的方法befor的使用方式
Function.prototype.befor = function (func) {
//给befor方法一个参数,这个参数就是要执行的逻辑参数
let that = this; //最后say 调用befor方法,所以这里this指向say方法。
// 但是在下面的返回函数里,this指向调用这个函数的对象,在浏览器里是window,不是say,所以这里我们把this的指向存在变量that里
//这是闭包的私有变量,因为被返回函数使用,所以不会被销毁
return function () {
func(); //在返回的参数里,先执行要添加的逻辑
that(); //然后执行say方法里的逻辑
}
}
let newSay = say.befor(function () {
//让say方法,调用一个方法befor,然后把想要添加的逻辑作为参数传进去,这个方法执行完返回一个函数,这个函数是两个函数的拼接
console.log('我先执行再say');
})
newSay();
// 我们按照上面的使用方法进行编写
// 我们希望所有的函数都有befor方法,都可以在执行之前先执行别的函数,所以加在Function.prototype
上面这个方法里的this问题也可以用es6的箭头函数来写:
javascript">Function.prototype.befor = function (func) {
return () => { //箭头函数没有this,没有arguments, 没有原型
func();
this(); //因为没有this,所以向上查找,它的上一级函数里this 指向say方法
}
}
我们也可以给say方法传参数
javascript">function say(who) { //1.这里有个参数:形参
//todo...
console.log(who + ' hello')
}
Function.prototype.befor = function (func) {
// ...args 剩余运算符:将所有的参数组合成一个数组,只能在最后一个参数里使用
return (...args) => { //3.执行逻辑时,获取实参并进行处理, 这个返回的函数,就是最后赋值给newSay的函数
//如果不是箭头函数,可以直接用arguments 来获取实参列表,但是箭头函数没有arguments
//当然如果知道有几个参数,也可以写死
func();
this(...args); //展开运算符
}
}
let newSay = say.befor(function () {
console.log('我先执行再say');
})
newSay('lxz'); // 2.实参:say 没有单独调用执行,而是在这里调用执行的,所以实参应该写在这里
什么叫闭包? 有一个函数,这个**函数可以不在当前作用域下执行,可以在外面执行,并且可以拿到之前作用域的值==**;
作用域什么时候产生的?作用域的产生是 根据函数定义的位置,函数执行的时候是执行上下文
2. vue 2.0 也会用到 函数劫持(AOP切片)的思想
函数劫持(AOP切片)的思想
javascript">
[1,2,3].push(4); //我们希望 在调用push方法的时候,触发一句更新操作。相当于我们把push方法重写了
let oldPush = Array.prototype.push; // 拿到老的push方法
// Array.prototype.push 放在原型上会好用些
function push(...args){ //我们自己写一个push方法,但是这样写我们调用方法就只能 push();
// 本来应该写形参a,但是不知道有多少个参数,所以可以把参数放到一个数组里,利用剩余运算符,转为数组 ...args
//传的是4,5,6 ; 也就是...args 是4,5,6;那args是[4,5,6]
// 不能用 xx.push()这样调用了,那push里的this不能用了,我们要用this可以用call /apply
console.log('数据更新了')
oldPush.call(this,...args); //在这里调用原来的push, 这里是展开运算符
// 但是 oldPush() 这样写,oldPush里的this并不是指向数组,还需要通过call来改变this指向
//因为 oldPush 也就是 Array.prototype.push 里面的实现也用到了this,所以要用call改变this指向
}
let arr = [1,2,3];
push.call(arr,4,5,6) //[1,2,3]第一个参数改变push里的this指向,后面的都是参数,我们用arguments 或者 ...args 剩余运算符获取
// call的特点:1.改变this指向 1.可以让push方法执行
// 4,5,6 是实参,有实参就要在定义的地方写下形参 -1实参
console.log(arr);
3. react 里的setState的事务transcation
如下图,给任何一个方法加上多层 init初始化的方法 和 close关闭的方法,实现猜想:
javascript">// react 里的setState就用到了事务的概念
function perform(anyMethod, wrappers) { //参数传一个函数,任何的方法
return function(){ //如果不想代码直接执行,就放在一个函数里返回,想执行的时候调用,这又是一个闭包
wrappers.forEach(wrapper => wrapper.initialize()) //这是添加的bofor功能
//forEach 的第一项是数组里的每一个元素,wrapper就是个名字,
//这里是循环完wrappers,每项都执行一次initialize()
// 箭头函数只有一个参数,可以省略(),没有return 可以省略{}
anyMethod(); //这是核心功能
wrappers.forEach(wrapper => wrapper.close()); //这是添加的after 功能
}
}
//perform 就是一个高阶函数
let newFunc = perform(function () { //perform,参数时一个函数,返回一个函数; 所以时高阶函数
console.log('这里是say方法');
}, [ //perform的第二个参数是一个数组,里面每一项都是一个对象,对象里是一层添加的方法
{ //wrapper1
initialize() {
console.log('beforSay1');
},
close() {
console.log('close1');
}
}, { //wrapper2
initialize() {
console.log('beforSay2');
},
close() {
console.log('close2');
}
}
]);
newFunc();
4. 保存变量
如下:要函数执行3次后,才调用回调函数,必须把3次这个times 利用闭包,保证其不会被销毁,不然每次调用完被销毁了,那下次调用还是从3开始算;
下面这个函数,只有第3次执行,超过了也不执行
javascript">function after(times, callback) { //这是一个闭包,它的参数在返回的函数中有用到,它的执行期上下文AO对象永远不会被销毁
//AO{times:3;}
//高阶函数的应用:times 永远被保存在作用域里;
return function () { //newFunc ,并且它不在这里执行,这定义它的作用域的外面执行,且能拿到外面的变量
if (--times === 0) { //--times 就是times -= 1 就是 times = times -1
// 这里先计算times = times-1 然后将减后的times 和 0 做比较
callback();
}
}
}
let newFunc = after(3, function () { //after的第一个参数是这个函数调用3次后,才会执行后面的回调函数
//after的参数传要真正执行的函数
console.log('真正执行的函数');
})
newFunc();
newFunc();
newFunc();