title: 函数柯里化
categories: Javascript
tag:
- 实现apply,call,bind
date: 2021-11-16 09:16:34
实现call
, apply
,bind
实现 call
Function.prototype.Dhcall = function (thisArg, ...args) {
//获取需要被执行的函数
var fn = this
//对thisArg转换为对象类型,防止传入的是非对象类型
thisArg = thisArg != null && thisArg != undefined ? Object(thisArg) : window
thisArg.fn = fn
var result = thisArg.fn(...args)
//会多出来属性,所以要删掉
delete thisArg.fn
return result
}
//测试代码======================================
function foo() {
console.log('foo被执行', this)
}
function bar(num1, num2, num3) {
console.log('bar被执行', this, num1, num2, num3)
return num1 + num2 + num3
}
foo.Dhcall({ name: 'why' })
var result = bar.Dhcall('abc', 10, 20, 30)
console.log(result)
实现 apply
Function.prototype.Dhapply = function (thisArg, argsArray) {
//获取到要执行的函数,也就是this
var fn = this
//处理绑定的thisArg
thisArg = thisArg != null && thisArg != undefined ? Object(thisArg) : window
thisArg.fn = fn
var result
//1. 可以用条件判断==================
/*
if (!argsArray) {
result = thisArg.fn()
} else {
result = thisArg.fn(...argsArray)
}
*/
//2. 可以使用三元运算符呀=============
/*
argsArray = argsArray ? argsArray : []
*/
//3. 可以使用逻辑
argsArray = argsArray || []
result = thisArg.fn(...argsArray)
delete thisArg.fn
return result
}
//测试代码====================================
// 两个参数
function sum(num1, num2) {
console.log('sum被调用', this, num1, num2)
return num1 + num2
}
// 一个参数
function single(num1) {
console.log('single被调用', this, num1)
return num1
}
function none() {
console.log('none被调用', this)
}
// 两个参数
var result = sum.Dhapply('a', [10, 20])
console.log(result)
// 一个参数也必须是数组类型
var result = single.Dhapply('a', [10])
console.log(result)
// 没有参数.那么Dhapply第二个参数是undefined,所以不能被迭代。会报错。
var result = none.Dhapply('a')
console.log(result)
实现 bind
这是原生的 bind 实现
function foo() {
console.log('foo被执行', this)
}
function sum(num1, num2, num3, num4) {
console.log(num1, num2, num3, num4)
}
//没有参数
var bar = foo.bind('abc')
bar()
//有参数,在bind的时候传
var newSum = sum.bind('aaa', 10, 20, 30, 40)
newSum()
//有参数,在调用的时候传
var newSum = sum.bind('aaa')
newSum(10, 20, 30, 40)
//有参数,两边都传
var newSum = sum.bind('aaa', 10, 20)
newSum(30, 40)
下面手写 bind 进行实现
Function.prototype.Dhbind = function (thisArg, ...argArray) {
//1. 获取到真实需要调用的函数
var fn = this
//2. 绑定this
thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
function proxyFn(...args) {
thisArg.fn = fn
var finalArgs = [...argArray, ...args]
var result = thisArg.fn(...finalArgs)
delete thisArg.fn
return result
}
return proxyFn
}
//测试代码================================================
function sum(num1, num2, num3, num4) {
console.log(this, num1, num2, num3, num4)
return num1 + num2 + num3 + num4
}
var newSum = sum.Dhbind('abc', 10, 20)
var res = newSum(30, 40)
console.log(res) //100
认识 arguments
arguments 是一个 对应于 传递给函数的参数 的 类数组(array-like)对象。
默认会有一个 arguments,类数组对象中(长的像是一个数组,本质上是一个对象:arguments)
function foo(num1, num2, num3) {
//默认会有一个arguments,类数组对象中(长的像是一个数组,本质上是一个对象:arguments)
console.log(arguments)
console.log(num1, num2, num3)
}
foo(10, 20, 30, 40, 50)
arguments 操作
array-like 意味着它不是一个数组类型,而是一个对象类型:
- 但是它却拥有数组的一些特性,比如说 length,比如可以通过 index 索引来访问;
- 但是它却没有数组的一些方法,比如 forEach、map 等;
常见的对 arguments 的操作有三个
- 获取参数的长度
console.log(arguments.length)
- 根据索引值获取某一参数
console.log(arguments[2])
console.log(arguments[3])
console.log(arguments[4])
- callee 获取当前 arguments 所在的函数
console.log(arguments.callee)
所以为了可以使用数组方法,我们把 arguments 转换为数组
//把arguments转换为数组.slice全部放到数组里面,然后返回这个新数组
var newArr = Array.prototype.slice.call(arguments)
console.log(newArr)
那么 Array 中 slice 的实现原理
//这是slice原理
Array.prototype.Dhslice = function (start, end) {
start = start || 0
end = end || arr.length
var arr = this
var newArray = []
for (let i = start; i < end; i++) {
newArray.push(arr[i])
}
return newArray
}
var newArray = Array.prototype.Dhslice.call(['a', 'b', 'c', 'd'], 1, 4)
console.log(newArray) // [10, 20, 30, 40, 50]
把 arguments 转换为数组另外的方法
//ES6语法
var newArr = Array.from(arguments)
console.log(newArr)
//展开运算符
var newArr = [...arguments]
console.log(newArr)
注意,箭头函数没有 arguments
箭头函数是不绑定 arguments 的,所以我们在箭头函数中使用 arguments 会去上层作用域查找
var foo = () => {
console.log(arguments)
}
foo() //浏览器中没有arguments,node中有arguments
那我们在箭头函数中,应该使用剩余参数