高阶函数

用代码解释代码,用函数证明函数

基本概念


高阶函数主要指:

  • 这个函数中的参数是函数
  • 这个函数的返回值是函数

before函数(装饰函数,AOP)


在执行一个函数之前去执行另一个函数

const f1 = ()=>{
    console.log("正在执行任务...")
}

// 要在f1之前打印 开始... 
Function.prototype.before = function(beforeFn){   // beforeFn叫回调函数
    // 箭头函数中没有this
    return ()=>{
        beforeFn();
        this(); // 谁调用了before函数,this就指谁
    }
}
// f2是返回的新函数
const f2 = f1.before(()=>{
    console.log("开始...")
})
f2()

高阶传参

const f1 = (...args)=>{
    console.log("正在执行任务...",args)
}
Function.prototype.before = function(beforeFn){   // beforeFn叫回调函数
    return (...args)=>{  // ...args 叫rest参数 用来接收1,2,3
        beforeFn();
        this(...args);  // 把1,2,3继续传递给f1
    }
}
const f2 = f1.before(()=>{
    console.log("开始...")
})
f2(1,2,3)

包括函数


包括函数:在执行某个函数之前执行若干个函数,在执行某个函数之后执行若干个函数,事务函数

把之前的函数存起来,把之后的函数存起来,就把它存储到对象

let f1 = function(){
    console.log("正在执行任务...")
}
let wrappers = [
    {
        // warpper
        init(){
            console.log("hello 1")
        },
        close(){
            console.log("bye 1")
        }
    },
    {
        // warpper
        init(){
            console.log("hello 2")
        },
        close(){
            console.log("bye 2")
        }
    }
]
// 定义一个函数,把上面两者结合起来
const work = (core,wrappers)=>{
    // core是核心函数
    wrappers.forEach(wrap=>{
        wrap.init()
    })
    core()
    wrappers.forEach(wrap=>{
        wrap.close()
    })
}
work(f1,wrappers)

让人想起的了函数柯里化

curring又称部分求值。一个curring的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数中被真正的需要求值的时候,之前传入的所有参数被一次性用于求值。

after函数


调用一个函数n次后,触发另一个函数,用after函数实现

const after = (times,fn)=>{
    return ()=>{
        if(--times === 0){
            fn()
        }
    }
}
const f1 = after(3,()=>{
    console.log("调用3次后才执行...")
})
f1()
f1()
f1()

多次调用才执行
我又想到了函数节流。。。。
在一定的时间内,函数只触发一次,能大大降低了频率问题

function throttle(fn, wait) {
    let last = 0
    return () => {
        var now = +new Date().getMilliseconds();
        if (now - last > wait) {
            fn()
            // console.log(now-last)
            last = now;
        } else {
            // console.log(now-last)
            console.log("什么情况")
        }
    }
}
const f3 = throttle(() => {
    console.log('ZZZZ.....')
}, 500);
f3()

all函数


const fs = require("fs")
let content = {};
let index = 0;
fs.readFile("name.txt","utf8",(err,data)=>{
    content['name'] = data
    index++;
    out()
})
fs.readFile("age.txt","utf8",(err,data)=>{
    content['age'] = data
    index++;
    out()
})
function out(){
    if(index == 2){
        console.log(content)
    }
}
const fs = require("fs")
let content = {};
const after = (times,fn)=>{
    return ()=>{
        if(--times === 0){
            fn()
        }
    }
}
let newAfter = after(2,()=>{
    console.log(content)
})
fs.readFile("./name.txt","utf8",(err,data)=>{
    content['name'] = data
    newAfter()
})
fs.readFile("./age.txt","utf8",(err,data)=>{
    content['age'] = data
    newAfter()
})
// 两者都成功才输出结果

emmmm…这让人想起了函数分时。。。。真的(〃‘▽’〃)

和节流函数的应用场景不同,当短时间内接受的数据过多过大,可能会有影响效率等问题,特别是如果我们需要在短时间内才页面中插入大量的DOM节点,那显然会让浏览器吃不消,这可能会引起浏览器的假死,所以我们需要进行分时函数,分批插入。

// 分时函数
var timeChunk = function (ary, fn, count) {
    var timer;

    var start = function () {
        for (var i = 0; i < Math.min(count || 1, ary.length); i++) {
            fn && fn(ary.shift())
        }
    };

    return function () {
        timer = setInterval(function () {
            if (ary.length === 0) { // 如果全部节点都已经被创建好
                return clearInterval(timer);
            }
            start();
        }, 200); // 分批执行的时间间隔,也可以用参数的形式传入
    };
};

var ary = [];
for (var i = 1; i <= 1000; i++) {
    ary.push(i);
};
var renderFriendList = timeChunk(ary, function (item) {
    console.log(item)
}, 8);
renderFriendList();

发布订阅


一种概念,订阅时把函数保存到一个容器中,发布时拿到这个容器并把里面的函数一一执行

订阅和发布之间没有关系

const fs = require("fs")
let content = {};
let e = {  //订阅
    arr:[],
    on(fn){
        this.arr.push(fn)
    },
    emit(){
        this.arr.forEach(fn=>fn())
    }
}

e.on(()=>{
    // console.log("订阅了... ")
    if(Object.keys(content).length === 2){
        console.log(content)
    }
})

e.emit()  // 发布
fs.readFile("name.txt","utf8",(err,data)=>{
    content["name"] = data;
    e.emit()  // 发布
})
fs.readFile("age.txt","utf8",(err,data)=>{
    content["age"] = data;
    e.emit()  // 发布
})

同样的,既然可以保存函数到最后一起执行,又怎么可能不能保存多个呢

let e = {
    arr:[],
    on(fn){
       this.arr.push(fn)
    },
    emit(){
        this.arr.forEach(fn=>fn())
    }
}
e.on(()=>{
    console.log("哈哈1")
})
e.on(()=>{
    console.log("哈哈2")
})
e.on(()=>{
    console.log("哈哈3")
})
e.emit()

观察者模式


观察者模式分为观察者和被观察者(在被观察者中存储观察者),观察者模式是基于订阅和发布,但二者之间有关系

// 被观察者
class Subject{
    constructor(){
        this.arr = [] // 存储谁在观察者
        this.state = "很开心"
    }
    attach(o){
        this.arr.push(o)
    }
    setState(newState){
        this.state = newState
        this.arr.forEach(o=>o.update(newState))
    }
}
// 观察者
class Observer{
    constructor(name){
        this.name = name;
    }
    update(newState){
        console.log(this.name,"小宝宝状态:",newState)
    }
}
let s = new Subject("小宝宝")
let o1 = new Observer("我")
let o2 = new Observer("我媳妇")
s.attach(o1)        //  我 小宝宝状态: 不开心
s.attach(o2)        //  我媳妇 小宝宝状态: 不开心
s.setState("不开心") 
// console.log(s.state)

一点cones


惰性加载函数

有两种实现惰性载入的方式,第一种事函数在第一次调用时,对函数本身进行二次处理,该函数会被覆盖为符合分支条件的函数,这样对原函数的调用就不用再经过执行的分支了,我们可以用下面的方式使用惰性载入重写addEvent()。

function addEvent (type, element, fun) {
    if (element.addEventListener) {
        addEvent = function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    }    else if(element.attachEvent){
        addEvent = function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    }    else{
        addEvent = function (type, element, fun) {
            element['on' + type] = fun;
        }
    }   
     return addEvent(type, element, fun);
    }

在这个惰性载入的addEvent()中,if语句的每个分支都会为addEvent变量赋值,有效覆盖了原函数。最后一步便是调用了新赋函数。下一次调用addEvent()的时候,便会直接调用新赋值的函数,这样就不用再执行if语句了。

第二种实现惰性载入的方式是在声明函数时就指定适当的函数。这样在第一次调用函数时就不会损失性能了,只在代码加载时会损失一点性能。一下就是按照这一思路重写的addEvent()。

var addEvent = (function () {  
    if (document.addEventListener) {  
        return function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    }  
   else if (document.attachEvent) {  
          return function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    }  
      else {        
         return function (type, element, fun) {
            element['on' + type] = fun;
        }
    }
})();

请参考javascript之惰性函数

This`s all,thanks!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值