cari

Rumah  >  Soal Jawab  >  teks badan

javascript - Meminta bantuan tentang panggilan dan memohon, anti-kari

Berikut ialah dua pelaksanaan uncurring

Capai 1

Function.prototype.uncurrying = function(){
    var self = this;

    return function(){
        // 获取传入的上下文对象
        var context = Array.prototype.shift.call(arguments);
        // 这里的this是调用uncurrying者
        return self.apply(context, arguments);
    };
};

var push = Array.prototype.push.uncurrying ();
var arr = [];
push(arr, 1); // ==> arr = [1]
push(arr, 4); // ==> arr = [1, 4]

Capai 2

Function.prototype.uncurrying = function(){
    var self = this;

    return function(){
        return Function.prototype.call.apply(self, arguments);
    };
};

var push = Array.prototype.push.uncurrying ();
var arr = [];
push(arr, 1); // ==> arr = [1]
push(arr, 4); // ==> arr = [1, 4]

Kedua-dua keputusan adalah sama, tetapi saya agak keliru tentang kaedah pelaksanaan kedua, terutamanya di sini

第一种方式显示的用self,在这里也就是push方法执行了一下,

    self.apply(context, arguments);

但是如下第二种实现方式,却没有发现self执行的痕迹,
按我的理解这里就是用apply修改call的上下文为self,这里也就是push,
但这样有执行push方法吗?难道call内部的实现帮忙执行了self?求解

    Function.prototype.call.apply(self, arguments);

Saya telah diklik oleh anda serta-merta, terima kasih!

louiszhai

Function.prototype.call.apply(self, arguments);
先用apply修改了call的上下文为self,
后续调用uncurrying,相当于在self上调用call方法,也就执行了self
淡淡烟草味淡淡烟草味2740 hari yang lalu473

membalas semua(2)saya akan balas

  • 我想大声告诉你

    我想大声告诉你2017-05-16 13:43:58

    Function.prototype.call.apply(self, arguments);Ini kelihatan agak berbelit, tetapi sebenarnya mudah difahami.
    Malah, pelaksanaan kedua anda juga boleh membawa kepada pelaksanaan ketiga anti-kari: 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

    function(){
      return Array.prototype.push.call.apply(Array.prototype.push, arguments);
    }

    Seterusnya, saya akan menganalisis pelaksanaan kedua anda terlebih dahulu, dan kemudian menganalisis pelaksanaan ketiga anda. Pelaksanaan anda kelihatan seperti ini: 🎜
    Array.prototype.push.call === Function.prototype.call //true
    🎜Sesiapa yang memanggil tidak menguras akan sama dengan ini atau self Ini bermakna self ialah tatasusunan Kaedah tolak.
    menggantikan self dan push luaran terakhir adalah bersamaan dengan fungsi berikut: 🎜
    function(){
      return Function.prototype.call.apply(Array.prototype.push, arguments);
    }
    🎜Fungsi diletakkan di sini Mari kita fahami dahulu fungsi apply apply mempunyai fungsi menguraikan tatasusunan kepada parameter. 🎜 🎜Formula terbitan: a.apply(b, arguments) bermaksud menganggap b sebagai konteks ini, yang bersamaan dengan memanggil kaedah a pada b dan menghantar semua parameter. Jika b itu sendiri mengandungi kaedah, maka ia bersamaan dengan b.a(arg1, arg2,…)🎜 🎜Formula 1: a.apply(b, arguments) === b.a(arg1, arg2,…)🎜 🎜Memandangkan call dan apply mempunyai kesan yang sama kecuali untuk pemprosesan parameter yang tidak konsisten, formula boleh diubah lagi untuk mendapatkan: 🎜 🎜Formula 2: a.call(b, arg) === b.a(arg)🎜 🎜Ganti Formula 1 ke dalam fungsi di atas, terdapat: 🎜 🎜a = Function.prototype.call Iaitu, a adalah sama dengan kaedah panggilan. 🎜 🎜Kami kemudian masukkan formula, kami ada: 🎜 🎜b = Array.prototype.push Iaitu, b adalah sama dengan kaedah tolak tatasusunan🎜 🎜Kemudian Function.prototype.call.apply(Array.prototype.push, arguments) adalah relatif kepada: 🎜 🎜Array.prototype.push.call(arg1, arg2,…), kemudian: 🎜 🎜push([], 1) bersamaan dengan Array.prototype.push.call([], 1), kemudian gantikannya kepada Formula 2 , bersamaan dengan: 🎜 🎜[].tekan(1)🎜 🎜Jawapannya sudah jelas iaitu menambah nombor 1 pada hujung tatasusunan. 🎜

    🎜Seterusnya, izinkan saya menganalisis pelaksanaan ketiga anti-kari: 🎜 🎜Untuk bahagian this.call.bind(this);, this bersamaan dengan Array.prototype.push, maka kesetaraan keseluruhan ialah seperti berikut: 🎜 🎜Array.prototype.push.call.bind(Array.prototype.push)🎜 🎜Kesukaran di sini terletak pada kaedah bind Perlaksanaan bind agak mudah, seperti berikut: 🎜
    function(){
      return Function.prototype.call.apply(self, arguments);
    }
    🎜Jika anda ingin memahami, anda mesti mudahkan yang kompleks Lebih mudah anda faham, lebih teliti anda akan faham. Untuk memudahkan lagi prinsip bind, ia adalah setara dengan sesiapa sahaja yang memanggil bind mengembalikan fungsi baharu. 🎜 🎜Kami menganggap bahawa fungsi fn memanggil kaedah bind seperti fn.bind([1, 2]), yang dipermudahkan dan mengabaikan bind< /code>Bahagian yang mengikat parameter akhirnya kembali seperti berikut: 🎜 rrreee 🎜Di atas, gantikan fn dengan Array.prototype.push.call dan [1, 2] dengan Array.prototype , kemudian: 🎜

    Array.prototype.push.call.bind(Array.prototype.push) akan bersamaan dengan: Array.prototype.push.call.bind(Array.prototype.push) 将等同于:

    rrreee

    这个看起来和反柯里化的第二种实现有些不大相同,不要急,虽然表面上看起来不一致,但骨子里还是一致的。请耐心往下看:

    不同的地方在于前半部分 Array.prototype.push.call,这里它是一个整体,实际上想代表的就是call方法。而我们都知道,所有函数的call方法,最终都是Function.prototypecall方法。那么,就有如下恒等式成立:

    rrreee

    那么以上函数将等同于:

    rrreee

    褪去代入的参数,函数可还原为:

    rrreee

    综上,最终反柯里化的第三种实现将和第二种实现完全一致,推理完毕,码字不易,喜欢的请点个赞谢谢~

    为了加深对bind rrreee

    Ini kelihatan sedikit berbeza daripada pelaksanaan kedua anti-kari Jangan risau, walaupun ia kelihatan tidak konsisten di permukaan, ia tetap konsisten pada intinya. Harap bersabar dan baca di bawah:

    Perbezaannya terletak pada separuh pertama Array.prototype.push.call, yang merupakan keseluruhan di sini dan sebenarnya mewakili kaedah panggilan. Dan kita semua tahu bahawa kaedah panggilan semua fungsi pada akhirnya adalah kaedah panggilan Function.prototype. Kemudian, identiti berikut dipegang:

    rrreee

    Maka fungsi di atas akan bersamaan dengan: 🎜 rrreee 🎜Mengalih keluar parameter yang diganti, fungsi boleh dipulihkan kepada: 🎜 rrreee 🎜Ringkasnya, pelaksanaan ketiga terakhir anti-kari akan benar-benar konsisten dengan pelaksanaan kedua Penaakulannya lengkap dan pengekodan tidak mudah Jika anda suka, sila berikan ia dan terima kasih~ 🎜 🎜Untuk mendalami pemahaman saya tentang bind dan kari, saya juga menulis blog untuk menganalisisnya secara mendalam. 🎜 🎜Sila rujuk Currying and Decurrying in Functional Programming and Function.prototype.bind Panduan Kaedah. 🎜 🎜Pelajar yang menyukainya juga boleh mengikuti kolum saya kursus mendalam Lewis di hadapan🎜

    balas
    0
  • 淡淡烟草味

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

    Asas
    Perbezaan dan fungsi panggilan dan penggunaan tidak akan diterangkan secara terperinci

    Panggil dan gunakan pelaksanaan kod sumber
    Mereka sangat rapat Di sini kami hanya memperkenalkan panggilan, contohnya: a.call(b, c)

    1. Keluarkan parameter pertama x = b ||

    2. x.fn = a
    3. Sambungkan parameter kecuali parameter pertama, dipisahkan dengan koma, hasilnya d
    4. Buat fungsi e = Fungsi() baharu dalam persekitaran pelaksanaan bebas, dan laksanakan x.fn(d) di dalam fungsi
    5. Laksanakan e
    6. yang dicipta

    Pemahaman Pilihan 2

    Masalah panggilan dan memohon untuk mengembangkan kaedah objek tidak dipertimbangkan di sini, kerana kaedah akan dibuat secara dinamik daripada kod sumber, jadi isu ini tidak akan dibincangkan secara terperinci di bawah.

        Function.prototype.call.apply(self, arguments);
        
        var push = Array.prototype.push.uncurrying ();

      sendiri menunjuk ke Array.prototype.push
    1. (Function.prototype.call).apply(Array.prototype.push, arguments);
    2. Gunakan kod sumber yang baru diterangkan dan ubah 2 untuk mendapatkan: Array.prototype.push.(Function.prototype.call)(argumen juga perlu ditukar di sini, bukan array, lihat 4.
    3. argumen ialah objek seperti tatasusunan [arr, 1]. Transform 3 untuk mendapatkan: Array.prototype.push.(Function.prototype.call)(arr, 1)
    4. Kod sumber panggilan telah dijelaskan, jadi tukar 4, dan dapatkan arr.(Array.prototype.push)(1)
    5. Tulis dengan lebih baik, arr.push(1)
    6. balas
      0
  • Batalbalas