柯里化: 一个函数原本有多个参数, 之传入一个参数, 生成一个新函数, 由新函数接收剩下的参数来运行得到结构.
var add = function (x) {
return function (y) {
return x + y
}
}
var increment = add(1) // 参数x被封印在了返回的新函数中,值为1不变化
var addTen = add(10) // 参数x被封印在了返回的新函数中,值为10不变化
increment(2) // 3
addTen(10) // 12
add(10)(10) // 20
increment(1) // 2
为什么要使用科里化? 为了提升性能. 使用科里化可以缓存一部分能力.
高阶函数: 一个函数参数是一个函数, 该函数对参数这个函数进行加工, 得到一个函数, 这个加工用的函数就是高阶函数.
Array.prototype.map((item,index,arr)=>{}) //高级函数的参数为函数
柯里化函数原理其实是 闭包,
函数即能力, 将某些能力作为新能力的基础能力
有点类似于层层递进的能力等级
柯里化函数返回的是函数, 是下一次操作的调用者
柯里化的对比
// 存在硬编码问题的函数
function checkAge (age) {
const min = 18
return age >= min
}
console.log(checkAge(20))
// 使用普通纯函数解决方案
function checkage (min, age) {
return age >= min
}
console.log(checkAge(18, 20))
// 使用闭包配合柯里化解决方案
function checkAge (min) {
return function (age) {
return age >= min
}
}
const checkAge18 = checkAge(18)
console.log(checkAge18(20))
思考: 虚拟DOM的render方法
思考: Vue 项目模版转换为抽象语法树需要执行几次?
页面一开始加载需要渲染
每一个属性( 响应式 )数据在发生变化的时候需要渲染
watch,computed等等
之前的代码 每次需要渲染的时候,模版就会解析一次
reder 的作用是将虚拟DOM转换为真正DOM加到页面中
虚拟DOM可以降级理解为 AST
一个项目运行时候,模版是不会变的,就表示 AST 是不会变的
我们可以将代码进行优化,将虚拟DOM缓存起来,生成一个函数,函数只需要传入数据,就可以得到真正的DOM.
function ad(a) {
return function(b) {
return function(c) {
return a + b + c;
// ... 不限制层级如何处理?
}
}
}
// 先理解一下toString()
function add (a) {
function sum(b) { // 使用闭包
a = a + b; // 累加
return sum;
}
sum.toString = function() { // 重写toSting() 方法
return a;
}
return sum; // 返回一个函数
}
console.log(add(1)(3)) // 4
console.log(add(1)(3)(5)) // 9
// 解决方式
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = [].slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var adder = function () {
var _adder = function() {
[].push.apply(_args, [].slice.call(arguments));
return _adder;
};
// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
// 打印函数时会自动调用 toString()方法
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
return adder.apply(null, [].slice.call(arguments));
}
// 输出结果,可自由组合的参数
console.log(add(1, 2, 3, 4, 5)); // 15
console.log(add(1, 2, 3, 4)(5)); // 15
字符串正则判断的应用
function checkEmail(email) {
return /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/.test(email);
}
function check(targetString, reg) {
return reg.test(targetString);
}
check(/^1[34578]\d{9}$/, '14900000088');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com');
// 如何封装通用能力 ?
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true
// Currying后
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)
柯里化可以让我们给一个函数传递较少的参数,得到一个已经记住了某些固定参数的新函数,者就是柯里化的核心。在柯里化内部就是使用闭包,对函数的参数进行缓存。柯里化让函数变得更灵活,因为我们可以通过一个函数生成一些细粒度更小的函数。这么做的目的是为了在后续函数组合的时候在使用。柯里化可以把多元函数转换成一元函数,目的是可以组合使用函数产生强大的功能。
lodash_curry函数柯里化的实现? 有兴趣的可以查看lodash源码,这里就不讲了哈.