一、柯里化函数 柯里化:
把接收多个参数的函数,变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,而且返回 结果的新函数的技术
只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数
实现多数字加法的柯里化 加法函数:
1 2 3 var add0 = function (x,y,z ){ return x + y + z }
柯里化函数:
1 2 3 4 5 6 7 var add1 = function (x ){ return function (y ){ return function (z ){ return x + y + z } } }
箭头函数优化:
1 var add2 = x=>y =>z => x+y+z
考虑会同时传递进去1个或2个参数 :
1 2 3 4 5 6 7 var add3 = (...args )=>{ if (args.length ===3 ) return args.reduce ((prev,curr )=> prev+curr) return (...other )=> { return add3 (...args,...other) } }
如果我们想得到可以获取不同个参数的柯里化函数呢,自动柯里化:
1 2 3 4 5 6 7 8 9 10 11 12 13 var fn = function (x,y,z,g ){ return x+y+z+g } var curryMyFn= function (fn ){ return curryFn = function (...args ){ if (args.length >=fn.length ) return fn (...args) return (...newArgs )=> { return curryFn (...args.concat (newArgs)) } } } var bar = curryMyFn (fn)console .log (bar (10 ,20 )(40 ,50 ))
二、apply、call、bind的手写 this绑定
this绑定共4种,默认绑定、隐式绑定、显示绑定、new绑定
实现显示绑定即是通过其余简单绑定方式实现,而默认绑定的this一般为windows,所以这里只能用隐式绑定实现
apply与call的手写实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 Function .prototype .myApply = function (thisArgs, args ){ thisArgs = (thisArgs===null || thisArgs ===undefined )?window :Object (thisArgs) let symbol = Symbol () thisArgs[symbol] = this let fn = thisArgs[symbol](...args) delete thisArgs[symbol] return fn } Function .prototype .myCall = function (thisArgs, ...args ){ thisArgs = (thisArgs===null || thisArgs ===undefined )?window :Object (thisArgs) let symbol = Symbol () thisArgs[symbol] = this let fn = thisArgs[symbol](...args) delete thisArgs[symbol] return fn } Function .prototype .myApply1 = function (thisArgs, args ){ thisArgs = (thisArgs===null || thisArgs ===undefined )?window :Object (thisArgs) Object .defineProperty (thisArgs, "temp" ,{ configurable :true , Enumerable :false , value :this }) let fn = thisArgs["temp" ](...args) delete thisArgs["temp" ] return fn } Function .prototype .myApply2 = function (thisArgs, args ){ thisArgs = (thisArgs===null || thisArgs ===undefined )?window :Object (thisArgs) thisArgs.temp = this let fn = thisArgs.temp (...args) delete thisArgs.temp return fn }
首先要排除thisArgs为null或undefined的情况,同时对数字或字符串包装为对象(Object(object)还是object)
方法添加到Function的原型上,使得所有函数都可以直接调用
使用symbol是因为Symbol()可以创建出一个独一无二的值,那么肯定不会覆盖掉原来对象中可能存在的值,同时Symbol属性不可以通过简单的属性获取得到,在后续的逻辑编写中不会出现错误
如果不适用Symbol,则需要通过Object.defineProperty使其不可枚举Object.defineProperty
测试:
1 2 3 4 5 6 7 8 let bar = function (name,age ){ console .log (this , Object .keys (this ),name,age) } bar.myApply ({method :"myApply-symbol" },["ouwenwu" ,18 ]) bar.myApply1 ({method :"myApply-没有symbol-不枚举" },["ouwenwu" ,18 ]) bar.myApply2 ({method :"myApply-没有symbol-枚举" },["ouwenwu" ,18 ]) bar.apply ({method :"apply-js自带" },["ouwenwu" ,18 ])
综上: 直接使用symbol属性来完成手写
bind的手写实现 根据上面的经验,这里直接用symbol
bind与apply、call的区别主要是返回一个函数
1 2 3 4 5 6 7 Function .prototype .myBind = function (thisArgs,...args ){ let symbol = Symbol () thisArgs[symbol] = this return function (...args ){ return thisArgs[symbol](...args) } }
三、es5继承的实现 继承:子类继承父类的函数与属性
注:类具有显示原型、对象具有隐式原型
1.原型链继承 父类的实例化对象作为子类的显示原型——就可以通过原型链去访问得到父类的属性与方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script src ="./jquery.js" > </script > <style > </style > </head > <body > <script > function Person (name,age ){ this .name = name, this .age = age } Person .prototype .eating = function ( ){ console .log ("eating" ) } const person = new Person ("oww" , 23 ) function Student (sno ){ this .sno = sno } Student .prototype = person Student .prototype .studying = function ( ){ console .log ("studying" ) } const student = new Student ("111" ) student.eating () student.studying () </script > </body > </html >
有一个很大的弊端:某些属性其实是保存在p对象上的:
我们通过直接打印对象是看不到这个属性的
这个属性会被多个对象共享,如果这个对象是一个引用类型,那么就会造成问题——其他子类修改会同时改变这边
不能给Person传递参数(让每个stu有自己的属性),因为这个对象是一次性创建的(没办法定制化)——子类的name、age在student中写死了
2.借用构造函数继承 原型链继承子类中的属性是通过父类实例定义的,没有自己的属性,不能传入值更改,借用构造函数可以解决这个问题
通过apply()和call()方法也可以在新创建的对象上执行父类构造函数