6.30学习-函数柯里化,回调解决异步多线程
- 1.函数柯里化
- 1.1 确定参数的函数柯里化
- 1.2参数不确定的函数柯里化
- 1.3 用法
- 1.3.1 给setTimeout传递进来的函数添加参数
- 2.回调解决异步多线程
1.函数柯里化
函数柯里化,经常可能就面试的时候听说过,反正一般开发我就很少用到过(自己层次不够吧)。老规矩,先上一段代码
// function isType(value,type) {
// return Object.prototype.toString.call(value) === `[object ${type}]`;
// }
// console.log(isType([1,2,3],'Array'))
//但是如果第二个参数传成'array','Arary'等,就会判断不是 function isType(type) {return function (value) {return Object.prototype.toString.call(value) === `[object ${type}]`;}
}
let isArray = isType('Array');
console.log(isArray([1,2,3]))
console.log(isArray(1,2,3))
console.log(isType('Array')([1,2,3]))
上面代码也就是判断变量的类型,但是第一种和第二种的写法不大相同的,第一种写法是一个多个参数的函数,第二个却是变成了单一的参数。其实这就是柯里化。
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数
上面我们虽然对函数进行了柯里化,但是我们不可能在需要柯里化的时候,都像上面不断地进行函数的嵌套;所以我们通过一个柯里化函数,实现通用的柯里化方法
1.1 确定参数的函数柯里化
const currying = (fn, arr = []) => {let len = fn.length;// return function (...args) {// arr = [...arr,...args]// console.log('arr',arr)// if(arr.length < len){// return currying(fn, arr)// }// else{// return fn(...arr)// }// }return function (...args) {let concatVal = [...arr, ...args]// console.log('arr',concatVal)if (concatVal.length < len) {return currying(fn, concatVal)}else {return fn(...concatVal)}}
}
function isType(type, value) {return Object.prototype.toString.call(value) === `[object ${type}]`;
}
let isArray = currying(isType)('Array');
let isString = currying(isType)('String');
console.log(isArray)
console.log(isArray([1, 2, 3])) //true
console.log(isArray('aaa')) //false
console.log(isString([1, 2, 3])) //false
console.log(isString('aaa')) //true
1.2参数不确定的函数柯里化
这里就有个经典的面试题了,实现sum(1,2,3,5)的效果和sum(1,2)(3)(5),sum(1,2,3)(5)一样
function sum() {let args = [...arguments];let res = function () {args.push(...arguments);// let result = args.reduce((pre, cur) => pre + cur)return res}res.toString = function(){return args.reduce((prev,cur)=>prev+cur) }return res
}
console.log(sum(1, 2, 3).toString(), sum(1).toString()) //6 1console.log(sum(1)(2,5)().toString()) // 8
1.3 用法
用法参考了点击这里跳转
1.3.1 给setTimeout传递进来的函数添加参数
function hello(name) {console.log('Hello, ' + name);
}
setTimeout(hello('kangkang'), 3600); //立即执行,不会在3.6s后执行
setTimeout(function() {hello('kangkang');
}, 3600); // 3.6s 后执行
当然,在ES5里面,我们也可以使用函数的bind方法,如下所示:
setTimeout(hello.bind(this, 'kangkang'), 3600); // 3.6s 之后执行函数
这样也是非常的方便快捷,并且可以绑定函数执行的上下文.
这里我们讨论函数的柯里化,当然我们这里也可以使用函数的柯里化来达到这个效果:
setTimeout(currying (hello, 'kangkang'), 3600); // 其中currying 是上面已经提及过的
2.回调解决异步多线程
let fs = require('fs');
let person = {}
fs.readFile('./1.txt', 'utf8', function(err,data){console.log(data);person.name = data
})
fs.readFile('./2.txt', 'utf8', function(err,data){console.log(data);person.age = data
})
console.log('person',person)
上面这段代码的结果是这样的:
挺明显的,我们想要拿到的是person {name:‘qiu’,age:‘18’},但是结果却还是个空对象。js中node的readFile方法是异步的,我们的代码也是基于node来运行的。异步是在同步代码后执行的,所以这里打印的的person还是空对象。肯定promise也是可以解决这个问题的,但这里重点讲回调。
let fs = require('fs');
let person = {}
//通过回调
let index = 0
let cb = () => {index++;if(index == 2){console.log('person',person) //person { name: 'qiu', age: '18' }}// console.log(index)
}
fs.readFile('./1.txt', 'utf8', function(err,data){person.name = datacb()
})
fs.readFile('./2.txt', 'utf8', function(err,data){person.age = datacb()
})
可以在读取文件成功后调用函数,再设置个index进行判断结束条件就可以拿到异步结束后的值了。
使用闭包,还可以让代码灵活一点
let fs = require('fs');
let person = {}
function after(index, callback) {// index--; //闭包函数,函数的定义的作用域和函数执行的作用域 不在同一个作用域下//闭包是定义在一个函数内部的函数,内层函数可以访问外层函数的局部变量,这些变量被内层函数引用不会被回收,//好处是使局部变量拥有更长的生命周期可以用来封装一段逻辑,坏处是闭包常驻内存造成内存泄露。return function () {index--;if (index == 0) {callback();}}
}
let cb = after(2, function () {console.log(person)
})
fs.readFile('./1.txt', 'utf8', function (err, data) {person.name = datacb()
})
fs.readFile('./2.txt', 'utf8', function (err, data) {person.age = datacb()
})
记录一下,持续修改更进