JS
函数式编程
实现 call
第一版
Function.prototype.mycall = function(){
// 1. 获取需要被执行的函数 foo.mycall 这里的 this 就是 foo 该函数
let fn = this
console.log('Function=>',this)
fn()
}
// 测试用例
function foo(){
console.log('foo=>',this)
}
foo.mycall()
此时已经可以调用了,但是 foo.mycall()
并不能携带参数
第二版
Function.prototype.mycall = function(thisArgs){
// 1. 获取需要被执行的函数
let fn = this
// 2. 调用需要被执行的函数
thisArgs.fn = fn
thisArgs.fn()
delete thisArgs.fn
console.log('Function=>',this)
}
// 测试用例
function foo(){
console.log('foo=>',this)
}
foo.mycall({})
上述例子可以运行,但是foo.mycall(123)
,当参数不为对象的时候,将会报错thisArgs.fn is not a function
第三版
Function.prototype.mycall = function(thisArgs){
// 1. 获取需要被执行的函数
let fn = this
// 如果传递的第一个参数有值的话 将其转换成 对象 object(123) ==> Number {123}
thisArgs = thisArgs ? Object(thisArgs) : window
// 2. 调用需要被执行的函数
thisArgs.fn = fn
thisArgs.fn()
delete thisArgs.fn
console.log('Function=>',this)
}
// 测试用例
function foo(){
console.log('foo=>',this)
}
foo.mycall(null)
foo.mycall(undefined)
但是call
是可以传递多个参数的,第三版也未满足传递多个参数
// ...args 剩余运算符 除开第一项参数,剩余其他参数
Function.prototype.mycall = function(thisArgs,...args){
// 1. 获取需要被执行的函数
let fn = this
// 2. 如果传递的第一个参数有值的话 将其转换成 对象(防止它传入的是非对象类型) object(123) ==> Number {123}
thisArgs = thisArgs ? Object(thisArgs) : window
// 3. 调用需要被执行的函数
thisArgs.fn = fn
let result = thisArgs.fn(...args)
delete thisArgs.fn
console.log('Function=>',this)
// 返回结果
return result
}
// 测试用例
function foo(num1,num2){
return num1 + num2
console.log('foo=>',this)
}
foo.mycall(null,12,23)
foo.mycall(undefined,23,34)
foo.mycall({},23,34)
实现 apply
类似于 call
,只是apply
第二个参数可以没有,也可以为数组
// ...args 剩余运算符 除开第一项参数,剩余其他参数
Function.prototype.myapply = function(thisArgs,args){
// 1. 获取需要被执行的函数
let fn = this
// 2. 如果传递的第一个参数有值的话 将其转换成 对象(防止它传入的是非对象类型) object(123) ==> Number {123}
thisArgs = (thisArgs !== null && thisArgs !== undefined) ? Object(thisArgs) : window
// 3. 调用需要被执行的函数
thisArgs.fn = fn
args = args || []
let result = thisArgs.fn(...args)
delete thisArgs.fn
console.log('Function=>',this)
// 返回结果
return result
}
// 测试用例
function foo(num1,num2){
return num1 + num2
console.log('foo=>',this)
}
foo.myapply('abc',[12,23])
foo.myapply(123)
foo.myapply({},[23,34])
实现bind
// ...args 剩余运算符 除开第一项参数,剩余其他参数
Function.prototype.myBind = function(thisArgs,...args){
// 1. 获取需要被执行的函数
let fn = this
// 2. 如果传递的第一个参数有值的话 将其转换成 对象(防止它传入的是非对象类型) object(123) ==> Number {123}
thisArgs = (thisArgs !== null && thisArgs !== undefined) ? Object(thisArgs) : window
// 因为是需要返回函数
function proxyFn(...arg){
// 3. 调用需要被执行的函数
thisArgs.fn = fn
// let bar = foo.myBind('abc',1,2) bar(3,4) 因为参数可能不会一起传,所以需要自己合并
let params = [...args,...arg]
let result = thisArgs.fn(...params)
delete thisArgs.fn
return result
}
// 返回函数
return proxyFn
}
Function.prototype.myBind = function (context) {
// 必须的是 函数
if (typeof this !== 'function') {
throw new TypeError('Error')
}
// 获取需要被执行的函数
var _this = this
// 获取参数
var args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
认识arguments
arguments
是一个对应于 传递给函数的参数 的 类数组对象- 常见的对
arguments
的操作是三个- 获取参数的长度
- 根据索引值获取某一个参数
callee
获取当前arguments
所在的函数
argunments
转数组for
Array.prototype.slice.call(arguments)
[].slice.call(arguments)
Array.from(arguments)
[...arguments]
理解JS
纯函数
- 确定的输入,一定会产生确定的输出
- 函数在执行过程中,不能产生副作用
副作用
- 表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储
纯函数的优势
- 可复用性
- 纯函数仅依赖于传入的参数,这意味着你可以随意将这个函数移植到别的代码中, 只需要提供它需要的参数即可。 如果是非纯函数, 有可能你需要一根香蕉,却需要将整个香蕉树都搬过去
- 可测试性
- 纯函数非常容易进行单元测试,因为不需要考虑上下文环境, 只需要考虑输入和输出
- 并行代码
- 纯代码是健壮的, 改变执行次序不会对系统造成影响, 因此纯函数的操作可以并行执行。
- 可缓存
- 因为纯函数对相同的输入始终有相同的结果,所以可以把纯函数的结果缓存起来
- 举个例子:如果有个函数或者方法,执行起来很耗时间,但是我们又需要多次使用,这种情况对性能是有影响的,那我们想要提高这个性能的话,当这个函数第一次调用的时候将结果缓存下来,当我们第二次在调用的时候,我们不需要在等待那么长的时间,而是直接从缓存中获取结果,从而提高性能
柯里化
解释:柯里化(英语:
Currying
),又译为卡瑞化
或加里化
,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
- 总结
- 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数,这个过程就称为柯里化
柯里化作用
-
让函数的职责单一
- 一个函数处理的问题尽可能单一,而不是将一大堆的处理过程交给一个函数来处理
- 那么就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中在使用处理后的结果
-
逻辑的复用
组合函数
- 需要对 某一个数据 进行函数的调用,执行俩个函数
fn1
和fn2
,这俩个函数是依次执行的 - 那么如果每次我们都需要进行俩个函数的调用,操作上就会显得重复
- 那么是否可以将这俩个函数组合起来,自动依次调用呢?
- 这个过程就是对函数的组合,我们称之为 组合函数