高阶函数
高阶函数类型
高阶函数作用
- 高阶函数可以对一个函数进行扩展,使之在执行阶段能有其它业务处理
function fn(){
return function(){}
}
function(cb){
cb()
}
function core (a,b,c){
console.log(a,b,c)
}
Function.prototype.before = function(cb){
return (...args)=>{
cb()
this(...args)
}
}
let newCore = core.before(()=>{console.log('before')})
newCore(1,2,3)
- 总结:通过传入函数来扩展新的操作,通过返回一个新的函数来将新操作和原函数结合
函数柯里化
如何判断数据类型
- typeof
- typeof 只能判断基本数据类型,其中typeof null = ‘object’
- typeof undefine = ‘undefine’
- typeof Object typeof Function typeof Array 皆为"function"
- typeof function fn(){} 为"function"
- typeof [] typeof {} 为"object"
- instanceof
- 检测构造函数的prototype属性是否出现在实例对象的原型链上
function person(){
}
let p = new person()
console.log(p instanceof person)
- constructor 拷贝 除了null和undefined以外,其它类型都是包装类对象
let num = 1
console.log(num.constructor)
let arr = []
console.log(arr.constructor)
let a = ()=>{}
console.log(a.constructor)
<!-- [Function: Number] -->
<!-- [Function: Array] -->
<!-- [Function: Function] -->
- Object.prototype.toString.call()
console.log(Object.prototype.toString.call(1))
console.log(Object.prototype.toString.call('1'))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call(function(){}))
console.log(Object.prototype.toString.call(null))
console.log(Object.prototype.toString.call(undefined))
- 方法1
function judgeType (type,val){
return Object.prototype.toString.call(val) == `[object ${type}]`
}
console.log(judgeType('Array',[1,2,3]))
- 这种方法不太理想,每次都要传入一个类型才行,不能简便的判断其类型
- 方法2
- 利用闭包的缓存思想,将每一种类型判断封装成一个函数返回,以后只需要单独调用即可判断改类型
- 闭包:定义函数的作用域和执行函数的作用域不一致,就会产生闭包
function judgeType(type){
return (val)=>{
return Object.prototype.toString.call(val) == `[object ${type}]`
}
}
let util = {}
let type = ['Array','Number','Function','Object','String','Null','Undefined']
type.forEach(tp =>{
util[`is${tp}`] = judgeType(tp)
})
console.log(util.isNumber(1))
console.log(util.isString(1))
柯里化概念
- 将一个函数利用高阶函数思想改便成多个函数嵌套形式,其传参由多个变成分批传入一个(让每个函数负责的功能更具体,缩小函数的范围),上述方法就是柯里化的思想
- 如何实现一个通用柯里化函数
function Currying(fn){
let len = fn.length
let allArg = Array.from(arguments).splice(1)
return (...newArg)=>{
allArg = [...allArg,...newArg]
if(allArg.length >= len){
return fn(...allArg)
}else {
return Currying(fn,...allArg)
}
}
}
function sum(a,b,c,d){
return a+b+c+d
}
let newSum = Currying(sum,1,2)
console.log(newSum(3)(4))
- 如何扩大函数的范围
- 通常原型链上的函数只能提供给拥有该原型的实例对象,通过call等方法可以将其扩展给其它类型使用
function unCurrying(fn){
return (...args)=>{
return (Function.prototype.call).call(fn,...args)
}
}
let toString = unCurrying(Object.prototype.toString)
console.log(toString(123))
console.log(toString('123'))
异步并发问题
const fs = require("fs")
const path = require("path")
fs.readFile(path.resolve(__dirname,'./file/1.txt'),'utf-8',function(err,data){
console.log(data)
})
fs.readFile(path.resolve(__dirname,'./file/2.txt'),'utf-8',function(err,data){
console.log(data)
})
- 针对这种异步的并行请求,我们如何同步最终的结果呢,最直接的方法就是利用定时器+回调
const fs = require("fs")
const path = require("path")
fs.readFile(path.resolve(__dirname,'./file/1.txt'),'utf-8',function(err,data){
finish('1',data)
})
fs.readFile(path.resolve(__dirname,'./file/2.txt'),'utf-8',function(err,data){
finish('2',2)
})
function after(timer,cb){
let util={}
return function(key,value){
util[key] = value
if(--timer === 0){
cb(util)
}
}
}
const finish = after(2,function(obj){
console.log(obj)
})
const fs = require('fs')
const path = require('path')
const events = {
_arr:[],
on(callback){
this._arr.push(callback)
},
emit(key,value){
this._arr.forEach(fn=>{
fn(key,value)
})
}
}
let obj = {}
events.on((key,value)=>{
obj[key] = value
if(Object.keys(obj).length == 2){
console.log(obj)
}
})
fs.readFile(path.resolve(__dirname,'./file/1.txt'),'utf-8',function(err,data){
events.emit(1,data)
})
fs.readFile(path.resolve(__dirname,'./file/2.txt'),'utf-8',function(err,data){
events.emit(2,data)
})
class Subject{
constructor(name){
this.name = name,
this.state = '开心',
this.observer = []
}
attach(ob){
this.observer.push(ob)
}
setState(newState){
if(this.state != newState){
this.state = newState
this.observer.forEach(ob=>{
ob.update(this.state)
})
}
}
}
class Observer{
constructor(name){
this.name = name
}
update(state){
console.log(state)
}
}
let baby = new Subject('baby')
let mon = new Observer('mon')
let fath = new Observer('fath')
baby.attach(mon)
baby.attach(fath)
baby.setState('哭')