javascript - 통화 및 적용에 대한 도움 요청, 카레 방지
淡淡烟草味
淡淡烟草味 2017-05-16 13:41:58
0
2
472

다음은 uncurring의 두 가지 구현입니다

1

달성 으아악

2개 달성

으아악

두 가지 결과는 동일하지만 주로 여기서 두 번째 구현 방법에 대해 약간 혼란스럽습니다

으아악

바로 클릭했네요. 감사합니다!

루이자이

으아악
淡淡烟草味
淡淡烟草味

모든 응답(2)
我想大声告诉你

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,谁就等于thisself. 这意味着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,…)

公式1a.apply(b, arguments) === b.a(arg1, arg2,…)

由于callapply 除参数处理不一致之外,其他作用一致,那么公式可以进一步演化得到:

公式2a.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); 부분의 경우 thisArray.prototype.push와 동일하며 전체적으로 동일합니다. 다음과 같습니다: 🎜 🎜Array.prototype.push.call.bind(Array.prototype.push)🎜 🎜여기서 어려운 점은 바인딩 방법에 있습니다. 바인딩의 구현은 다음과 같이 비교적 간단합니다. 으아아아 🎜이해하고 싶다면 복잡한 것을 단순화해야 합니다. 간단하게 이해할수록 더 철저하게 이해할 수 있습니다. bind의 원리를 더욱 단순화하기 위해 bind를 호출하는 사람이 새 함수를 반환하는 것과 동일합니다. 🎜 🎜우리는 fn 함수가 fn.bind([1, 2])와 같은 bind 메서드를 호출한다고 가정합니다. 이는 단순화되고 무시됩니다. bind매개변수를 바인딩하는 부분은 최종적으로 다음과 같이 반환됩니다. 🎜 으아아아 🎜위에서 fnArray.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.prototypecall方法。那么,就有如下恒等式成立:

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.prototypecall 메소드라는 것을 알고 있습니다. 그러면 다음과 같은 신원이 성립됩니다:

으아아아

그러면 위 함수는 다음과 같습니다. 🎜 으아아아 🎜대체된 매개변수가 없으면 기능을 다음 위치로 복원할 수 있습니다.🎜 으아아아 🎜결론적으로 안티 커링의 마지막 세 번째 구현은 두 번째 구현과 완전히 일치하게 됩니다. 마음에 드셨다면 좋아요를 눌러주세요~ 🎜 🎜바인드와 커링에 대한 이해를 심화하기 위해 블로그에도 작성하여 심층적으로 분석했습니다. 🎜 🎜함수형 프로그래밍의 커링 및 디커링 및 Function.prototype.bind 메서드 가이드를 참조하세요. 🎜 🎜좋아하는 학생들은 내 칼럼 루이스의 프론트엔드 심층 강좌도 따라갈 수 있습니다🎜
淡淡烟草味

기본
호출과 적용의 차이점과 기능은 자세히 설명하지 않겠습니다

소스 코드 구현 호출 및 적용
여기에서는 호출만 소개합니다. 예: a.call(b, c)

  1. 첫 번째 매개변수 x = b ||

  2. x.fn = a
  3. 첫 번째 매개변수를 제외한 매개변수를 쉼표로 구분하여 연결하면 결과는 d
  4. 입니다.

  5. 독립적인 실행 환경에서 e = new Function() 함수를 생성하고 함수 내에서 x.fn(d)를 실행합니다
  6. 생성된 e를 실행
솔루션 2의 이해

객체 메서드를 확장하기 위한 호출 및 적용 문제는 여기에서 고려하지 않습니다. 메서드는 소스 코드에서 동적으로 생성되므로 이 문제는 아래에서 자세히 설명하지 않습니다. 으아아아

    self는 Array.prototype.push
  1. 를 가리킵니다.

  2. (Function.prototype.call).apply(Array.prototype.push, 인수);
  3. 방금 설명한 소스 코드를 사용하여 2를 변환하고 Array.prototype.push.(Function.prototype.call)(인수)를 가져옵니다. 또한 여기서 호출은 배열이 아닌 변환이 필요합니다. 4를 참조하세요.
  4. arguments는 배열과 유사한 객체 [arr, 1]입니다. 3을 변환하면 Array.prototype.push.(Function.prototype.call)(arr, 1)
  5. call의 소스코드가 설명되어 있으니 4번을 변경하고 arr을 받으세요.(Array.prototype.push)(1)
  6. 더 잘 써주세요, arr.push(1)
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿