JS
函数式编程
JS
实现
call
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
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
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
是一个对应于
传递给函数的参数
的
类数组对象
-
常见的对
arguments
的操作是三个- 获取参数的长度
- 根据索引值获取某一个参数
-
callee
获取当前
arguments
所在的函数
-
argunments
转数组-
for
-
Array.prototype.slice.call(arguments)
-
[].slice.call(arguments)
-
Array.from(arguments)
-
[...arguments]
-
理解
JS
纯函数
JS
- 确定的输入,一定会产生确定的输出
-
函数在执行过程中,不能产生
副作用
副作用
-
表示
在执行一个函数
时,除了
返回函数值
之外,还对
调用函数产生了附加的影响
,比如
修改了全局变量
,修改
参数或者改变外部的存储
纯函数的优势
-
可复用性
- 纯函数仅依赖于传入的参数,这意味着你可以随意将这个函数移植到别的代码中, 只需要提供它需要的参数即可。 如果是非纯函数, 有可能你需要一根香蕉,却需要将整个香蕉树都搬过去
-
可测试性
- 纯函数非常容易进行单元测试,因为不需要考虑上下文环境, 只需要考虑输入和输出
-
并行代码
- 纯代码是健壮的, 改变执行次序不会对系统造成影响, 因此纯函数的操作可以并行执行。
-
可缓存
- 因为纯函数对相同的输入始终有相同的结果,所以可以把纯函数的结果缓存起来
- 举个例子:如果有个函数或者方法,执行起来很耗时间,但是我们又需要多次使用,这种情况对性能是有影响的,那我们想要提高这个性能的话,当这个函数第一次调用的时候将结果缓存下来,当我们第二次在调用的时候,我们不需要在等待那么长的时间,而是直接从缓存中获取结果,从而提高性能
柯里化
解释:
柯里化
(英语:
Currying
),又译为
卡瑞化
或
加里化
,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
-
总结
-
只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数
,这个过程就称为柯里化
-
柯里化作用
-
让函数的职责单一
- 一个函数处理的问题尽可能单一,而不是将一大堆的处理过程交给一个函数来处理
-
那么就可以
将每次传入的参数在单一的函数中进行处理
,处理完后在
下一个函数中在使用处理后的结果
-
逻辑的复用
组合函数
-
需要对
某一个数据
进行函数的调用,
执行俩个函数
fn1
和
fn2
,这俩个函数是
依次执行的
-
那么如果每次我们都需要
进行俩个函数的调用
,
操作上就会显得重复
-
那么是否可以将
这俩个函数组合起来,自动依次调用
呢? -
这个过程就是
对函数的组合,我们称之为 组合函数
版权声明:本文为weixin_43550660原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。