찾다

 >  Q&A  >  본문

javascript - 통화 및 적용에 대한 도움 요청, 카레 방지

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

1

달성 으아악

2개 달성

으아악

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

으아악

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

루이자이

으아악
淡淡烟草味淡淡烟草味2740일 전474

모든 응답(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,谁就等于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< /code>매개변수를 바인딩하는 부분은 최종적으로 다음과 같이 반환됩니다. 🎜 으아아아 🎜위에서 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 메서드 가이드를 참조하세요. 🎜 🎜좋아하는 학생들은 내 칼럼 루이스의 프론트엔드 심층 강좌도 따라갈 수 있습니다🎜

    회신하다
    0
  • 淡淡烟草味

    淡淡烟草味2017-05-16 13:43:58

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

    소스 코드 구현 호출 및 적용
    여기에서는 호출만 소개합니다. 예: 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)
    7. 회신하다
      0
  • 취소회신하다