导航[[深入01]执行上下文](https://juejin.im/post/684490...[[深入02]原型链](https://juejin.im/post/684490...[[深入03]继承](https://juejin.im/post/684490...[[深入04]事件循环](https://juejin.im/post/684490...[[深入05]CurryingPartialfunction函数记忆](https://juejin.im/post/684490...[[深入06]隐式转换与运算符](https://juejin.im/post/684490...[[深入07]浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...[[深入08]前端安全](https://juejin.im/post/684490...[[深入09]DebounceThrottle](https://juejin.im/post/684490...[[深入10]DebounceThrottle](https://juejin.im/post/684490...[[深入11]前端路由](https://juejin.im/post/684490...[[深入12]前端模块化](https://juejin.im/post/684490...[【深入13】观察者模式发布订阅模式双向数据绑定】(https://juejin.im/post/684490...[[深度14]画布](高ttps://juejin.im/post/684490...[[深入15]webSocket](https://juejin.im/post/684490...[[深入16]webpack](https://juejin.im/post/684490...[[深入17]http和https](https://juejin.im/post/684490...[[深入18]CSS-interview](https://juejin.im/post/684490...[[深入19]手写承诺](https://juejin.im/post/684490...[[深入20]手写功能](https://juejin.im/post/684490..[[react]Hooks](https://juejin.im/post/684490...[[部署01]Nginx](https://juejin.im/post/684490...[[部署02]DockerDeployvue项目](https://juejin.im/post/684490...[[部署03]gitlab-CI](https://juejin.im/post/684490...[[source-webpack01-front知识集]AST抽象语法树](https://juejin.im/post/684490...[[源码-webpack02-pre-knowledge]Tapable](https://juejin.im/post/684490...[[源码-webpack03]手写webpack-compiler简单编译过程](https://juejin.im/post/684490...[[源码]ReduxReact-Redux01](https://juejin.im/post/684490...[[源码]axios](https://juejin.im/post/684490...[[源码]vuex](https://juejin.im/post/684490...[[源码-vue01]数据响应及初始化渲染](https://juejin.im/post/684490...pre-kn的参数长度owledgefunction:函数的legth属性,返回函数期望的参数个数(parameters)arguments:arguments对象,包含程序运行时的所有参数(实参)。类数组对象转换为数组[].slice.call(类数组对象)[].slice.apply(类数组对象)Array.prototype.slice.call(类数组对象,x)//x是arra绑定this后传递给slice函数的参数y.from()偏函数和柯里化的概念柯里化柯里:将一个接收多个参数的函数转换为一个接收单个参数的函数,并返回一个接收剩余参数并返回最终结果的新函数即当参数小于期望参数时,返回一个可以接收剩余参数的函数,当参数大于等于期望参数时,返回最终结果部分应用:就是固定一个或多个参数,生成另外一个元素较小的函数n-elementfunction=>转化为n-x-elementfunctioncurrycurryCurryfunction,它接收函数A作为参数,运行后可以返回一个新的函数,而这个新函数可以处理函数A1的剩余参数。currying阶段1的要求:将add(1,2,3)转换为curryAdd(1)(2)(3)缺点:只有3参数可以是processed,不能处理任意数量的参数,也不需要可扩展性:将add(1,2,3)转换成curryAdd(1)(2)(3)缺点:只能处理3个参数,不能处理任意数量的参数,无可扩展性log(res,'res1')2.柯里化阶段2的要求:处理任意数量的参数来相加缺点:1.处理相加逻辑的代码只有在没有参数的时候才会执行。其他部分在处理如何收集所有的参数,后面还会有一个不带参数的调用。比较合理的方式是通过判断函数可以接收的参数的总和来判断参数是否被收集。2.加法逻辑可以从函数中分离出来curryAdd(){letparams_arr=[]//用来收集所有的实际参数每次调用闭包函数传入的参数可以是多个group,不改变原来的数组returnclosure//如果还有参数,继续返回闭包函数,然后继续传参调用}returnparams_arr.reduce((total,current)=>total+current)//如果没有再传入参数,则将传入的参数全部相加,缺点是多了一个无参调用。}returnclosure//第一次调用curryAdd返回的闭包}constfn=curryAdd()constres=fn(1,2)(3)(4)()console.log(res,'res');//103.Curryingstagethreefunctionadd(a,b,c,d,e){returnArray.prototype.slice.call(arguments).reduce((total,current)=>total+current)//注意:这里得到的是实参的实际个数,即实参可能大于形参,当实参(大于等于)为形参时,进行加法}functioncurryAdd(fn){letparamsArr=[]constparamsMaxLength=fn.length//function.length返回函数的形参个数,期望参数个数为最大参数个数,即加法执行条件函数closure(){constargs=Array.prototype.slice.call(arguments)paramsArr=paramsArr.concat(args)if(paramsArr.lengthtotal+current)}functioncurrentAdd(fn){letparamsArr=[]functionclosure(){//闭包函数只负责收集参数,可以在闭包上挂载新方法getSum来处理加法。constargs=Array.from(arguments)paramsArr=paramsArr.concat(args)returnclosure}closure.getSum=function(){returnfn.apply(this,paramsArr)//getSum负责计算,使用变量paramsArrin闭包}返回闭包}constfn=currentAdd(add)constresAdd=fn(1)(2,3)constres=resAdd.getSum();//这种方法的缺点是需要单独调用getSum函数console.log(res,'res')partialfunctionpartial将一个或多个参数固定到一个函数中,生成一个返回较小元素函数的函数add(a,b){returna+b}functionpartial(fn){...}constaddPartial=partial(add,1)//-----------------实现固定部分参数1constres=addPartial(2)//3----------------------只传递部分参数2部分函数实现方法一通过bind方法实现bind方法绑定这个点,同时也可以传入fn的部分和全部参数,返回一个New函数,new函数可以传入参数作为fn函数add(a,b,c,d)的剩余参数{returna+b+c+d}functionpartail(){constparams=Array.prototype.slice.call(arguments)constfn=params.shift()//删除数组的第一个元素,返回这个元素,改变原数组返回fn。bind(this,...params)//执行shift后params发生了变化\//展开后params数组的所有成员都会作为fn参数//并且bind返回的新函数也可以传参}constfn=partail(add,1,2)//固定两个参数1和2constres=fn(3,4)//除了固定的参数,剩下的参数在这里传递给console.log(res,'res')部分函数实现2functionadd(a,b,c,d){returnArray.from(arguments).reduce((total,current)=>total+current)//添加实际参数//因为实际parametersmaybegreaterthantheformalparameter}functionpartialAdd(fn){letparamsFixed=Array.from(arguments).slice(1)//去掉fn剩余的参数//注意:这个方法和curry很像,并且current的第一次调用不需要如果传了fn参数,声明了一个空数组,需要在局部传一个固定参数constparamsMaxLength=fn.length//形式参数的数量functionclosure(){constargs=Array.from(arguments)paramsFixed=paramsFixed.concat(args)if(paramsFixed.length×?f():g();//f()和g()都是尾调用consta=()=>f()||g()//f()不是尾调用,然后判断consta=()=>f()&&g();//f()不是尾调用调用尾递归Recursion--Tailrecursionandtailcall1.构成递归的条件-边界条件-递归前向段-递归返回段-不满足边界条件时,递归前向-满足边界条件时,递归返回2.递归:递归阶乘:阶乘3.Tailcallandnon-tailcall——尾调用和非尾调用的区别在于执行下面的栈不同-forcalls:调用在函数的末尾-尾调用的执行上下文栈,执行完外层函数后会出栈,不会逐层嵌套,并且不会造成内存溢出——tailcall本身叫做tailRecursion//Tailcall//因为在调用g(x)的时候,f(x)已经执行完了,会pop出栈,不会push栈,并且不会造成内存溢出functionf(x){returng(x);}//非尾调用//因为在调用g(x)的时候,f(x)还没有执行,g(x)+1需要先执行g(x)函数再添加,返回f(x)后)将执行函数f(x){returng(x)+1;}--------------------------------------------------------------------------------+++(示例1)factorial//递归递归函数factorial(n){if(n<2)returnnreturnn*factorial(n-1)}constres=factorial(3)//1.3=>3*factorial(2)=>3*2*factorial(1)=>3*2*1(分析)1.递归函数每次返回都会创建一个闭包2.所以维护这个Multiple执行上下文栈,开销大,用来造成内存泄漏3.优化方式:尾调用+++(示例1升级)factorialoptimizationfunctionfactorial(n,res){if(n===1){returnres}returnfactorial(n-1,n*res)}(分析)第一次:factorial(3,4*1)第二次:factorial(2,3*4)第三次:factorial(1,2*12)第四次:24+++(example1andthenupgrade)factorialoptimization,多传一个参数,functionfactorial(res,n){if(n===1)返回资源;returnfactorial(n*res,n-1)}functioncurring(fn){letpar_arr=Array.prototype.slice.call(arguments,1)constclosure=function(){par_arr=par_arr.concat(Array.prototype.slice.call(arguments))console.log(par_arr,'par_arr')if(par_arr.length