다음은 uncurring의 두 가지 구현입니다
1
달성 으아악2개 달성
으아악두 가지 결과는 동일하지만 주로 여기서 두 번째 구현 방법에 대해 약간 혼란스럽습니다
으아악바로 클릭했네요. 감사합니다!
으아악루이자이
我想大声告诉你2017-05-16 13:43:58
Function.prototype.call.apply(self, 인수);
좀 복잡해 보이지만 실제로는 이해하기 쉽습니다.
실제로 두 번째 구현은 커링 방지의 세 번째 구현으로 이어질 수도 있습니다. Function.prototype.call.apply(self, arguments);
这个看起来有些绕,其实很好理解。
实际上,由你的第二种实现还可以推出反柯里化的第三种实现:
Function.prototype.unCurrying = function () {
return this.call.bind(this);
};
var push = Array.prototype.push.unCurrying(), obj = {};
push(obj, '123', '456');
console.log(obj); //Object {0: "123", 1: "456", length: 2}
接下来我会先分析下你的第二种实现,再分析第三种实现。你的实现是这样的:
Function.prototype.uncurrying = function(){
var self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
};
};
var push = Array.prototype.push.uncurrying();
谁调用uncurrying
,谁就等于this
或self
. 这意味着self
就是数组的push方法
.
替换掉self
,最终外部的push
等同如下函数:
function(){
return Function.prototype.call.apply(Array.prototype.push, arguments);
};
函数放在这里,我们先来理解apply
函数,apply
有分解数组为一个个参数的作用。
推导公式:a.apply(b, arguments)
意味着把b当做this上下文,相当于是在b上调用a方法,并且传入所有的参数,如果b中本身就含有a方法,那么就相当于 b.a(arg1, arg2,…)
公式1:a.apply(b, arguments) === b.a(arg1, arg2,…)
由于call
和 apply
除参数处理不一致之外,其他作用一致,那么公式可以进一步演化得到:
公式2:a.call(b, arg) === b.a(arg)
将公式1这些代入上面的函数,有:
a = Function.prototype.call
即a等于call方法。
我们接着代入公式,有:
b = Array.prototype.push
即b等于数组的push方法
那么 Function.prototype.call.apply(Array.prototype.push, arguments)
就相对于:
Array.prototype.push.call(arg1, arg2,…)
,那么:
push([], 1)
就相当于 Array.prototype.push.call([], 1)
,再代入公式2,相当于:
[].push(1)
答案已经呼之欲出了,就是往数组中末尾添加数字1。
接下来我来分析反柯里化的第三种实现:
对于this.call.bind(this);
部分,this
相当于Array.prototype.push
,那么整体等同于如下:
Array.prototype.push.call.bind(Array.prototype.push)
这里的难点在于bind方法,bind的实现比较简单,如下:
Function.prototype.bind = function(thisArg){
var _this = this;
var _arg = _slice.call(arguments,1);
return function(){
var arg = _slice.call(arguments);
arg = _arg.concat(arg);
return _this.apply(thisArg,arg);
}
}
想要理解必须化繁为简,理解得越简单,也就理解得越透彻。进一步简化bind
的原理,等同于谁调用bind
,就返回一个新的function。
我们假设函数fn
调用bind
方法如fn.bind([1, 2])
,经过简化,忽略bind
绑定参数的部分,最终返回如下:
function(){
return fn.apply([1, 2], arguments);
}
以上,将fn
替换为 Array.prototype.push.call
,[1, 2]
替换为 Array.prototype.push
으아아아
uncurring
을 호출하는 사람은 this
또는 self
와 같습니다. 이는 self
가 배열임을 의미합니다. 푸시 메소드
.self
를 대체하며 최종 외부 push
는 다음 함수와 동일합니다. 🎜
으아아아
🎜여기에 함수가 배치되어 있습니다. 먼저 apply
함수에 대해 알아보겠습니다. apply
에는 배열을 매개변수로 분해하는 기능이 있습니다. 🎜
🎜파생 공식: a.apply(b, 인수)
는 b를 이 컨텍스트로 처리한다는 의미입니다. 이는 b에서 a 메서드를 호출하고 모든 매개변수를 전달하는 것과 동일합니다. b 자체에 메서드가 포함되어 있으면 b.a(arg1, arg2,…)
🎜와 동일합니다.
🎜수식 1: a.apply(b, 인수) === b.a(arg1, arg2,…)
🎜
🎜 호출
과 적용
은 일관되지 않은 매개변수 처리를 제외하고 동일한 효과를 갖기 때문에 공식을 더욱 발전시켜 다음을 얻을 수 있습니다. 🎜
🎜공식 2: a.call(b, arg) === b.a(arg)
🎜
🎜위 함수에 공식 1을 대입하면 다음과 같습니다. 🎜
🎜a = Function.prototype.call
즉, a는 호출 방법과 같습니다. 🎜
🎜그런 다음 공식을 대입하면 다음과 같습니다. 🎜
🎜b = Array.prototype.push
즉, b는 배열의 푸시 방법과 같습니다🎜
🎜그러면 Function.prototype.call.apply(Array.prototype.push, 인수)
는 다음을 기준으로 합니다. 🎜
🎜Array.prototype.push.call(arg1, arg2,…)
, 다음: 🎜
🎜push([], 1)
는 Array.prototype.push.call([], 1)
과 동일하며 이를 수식 2로 대체합니다. Strong> , 다음과 동일: 🎜
🎜[].push(1)
🎜
🎜답은 이미 명확합니다. 배열 끝에 숫자 1을 추가하는 것입니다. 🎜
<시간>
<시간>
🎜다음으로 안티커링의 세 번째 구현을 분석하겠습니다. 🎜
🎜this.call.bind(this);
부분의 경우 this
는 Array.prototype.push
와 동일하며 전체적으로 동일합니다. 다음과 같습니다: 🎜
🎜Array.prototype.push.call.bind(Array.prototype.push)
🎜
🎜여기서 어려운 점은 바인딩 방법에 있습니다. 바인딩의 구현은 다음과 같이 비교적 간단합니다.
으아아아
🎜이해하고 싶다면 복잡한 것을 단순화해야 합니다. 간단하게 이해할수록 더 철저하게 이해할 수 있습니다. bind
의 원리를 더욱 단순화하기 위해 bind
를 호출하는 사람이 새 함수를 반환하는 것과 동일합니다. 🎜
🎜우리는 fn
함수가 fn.bind([1, 2])
와 같은 bind
메서드를 호출한다고 가정합니다. 이는 단순화되고 무시됩니다. bind< /code>매개변수를 바인딩하는 부분은 최종적으로 다음과 같이 반환됩니다. 🎜
으아아아
🎜위에서 fn
을 Array.prototype.push.call
로 바꾸고 [1, 2]
를 Array.prototype push로 바꿉니다.
, 다음: 🎜Array.prototype.push.call.bind(Array.prototype.push)
는 다음과 같습니다. Array.prototype.push.call.bind(Array.prototype.push)
将等同于:
function(){
return Array.prototype.push.call.apply(Array.prototype.push, arguments);
}
这个看起来和反柯里化的第二种实现有些不大相同,不要急,虽然表面上看起来不一致,但骨子里还是一致的。请耐心往下看:
不同的地方在于前半部分 Array.prototype.push.call
,这里它是一个整体,实际上想代表的就是call方法。而我们都知道,所有函数的call方法,最终都是Function.prototype
的 call
方法。那么,就有如下恒等式成立:
Array.prototype.push.call === Function.prototype.call //true
那么以上函数将等同于:
function(){
return Function.prototype.call.apply(Array.prototype.push, arguments);
}
褪去代入的参数,函数可还原为:
function(){
return Function.prototype.call.apply(self, arguments);
}
综上,最终反柯里化的第三种实现将和第二种实现完全一致,推理完毕,码字不易,喜欢的请点个赞谢谢~
为了加深对bind
으아아아
두 번째 안티 커링 구현과는 조금 달라 보이지만 걱정하지 마세요. 표면적으로는 일관성이 없어 보이지만 핵심은 여전히 일관성이 있습니다. 인내심을 갖고 아래 내용을 읽어주세요:
차이점은 Array.prototype.push.call
의 전반부에 있는데, 이는 여기서 전체이고 실제로 호출 방법을 나타냅니다. 그리고 우리 모두는 모든 함수의 호출 메소드가 궁극적으로 Function.prototype
의 call
메소드라는 것을 알고 있습니다. 그러면 다음과 같은 신원이 성립됩니다:
으아아아
그러면 위 함수는 다음과 같습니다. 🎜
으아아아
🎜대체된 매개변수가 없으면 기능을 다음 위치로 복원할 수 있습니다.🎜
으아아아
🎜결론적으로 안티 커링의 마지막 세 번째 구현은 두 번째 구현과 완전히 일치하게 됩니다. 마음에 드셨다면 좋아요를 눌러주세요~ 🎜
🎜바인드
와 커링에 대한 이해를 심화하기 위해 블로그에도 작성하여 심층적으로 분석했습니다. 🎜
🎜함수형 프로그래밍의 커링 및 디커링 및 Function.prototype.bind 메서드 가이드를 참조하세요. 🎜
🎜좋아하는 학생들은 내 칼럼 루이스의 프론트엔드 심층 강좌도 따라갈 수 있습니다🎜회신하다0
淡淡烟草味2017-05-16 13:43:58
기본
호출과 적용의 차이점과 기능은 자세히 설명하지 않겠습니다
소스 코드 구현 호출 및 적용
여기에서는 호출만 소개합니다. 예: a.call(b, c)
첫 번째 매개변수 x = b ||
입니다.
객체 메서드를 확장하기 위한 호출 및 적용 문제는 여기에서 고려하지 않습니다. 메서드는 소스 코드에서 동적으로 생성되므로 이 문제는 아래에서 자세히 설명하지 않습니다.
으아아아
를 가리킵니다.