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
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);
这个看起来有些绕,其实很好理解。实际上,由你的第二种实现还可以推出反柯里化的第三种实现:
接下来我会先分析下你的第二种实现,再分析第三种实现。你的实现是这样的:
谁调用
uncurrying
,谁就等于this
或self
. 这意味着self
就是数组的push方法
.替换掉
self
,最终外部的push
等同如下函数:函数放在这里,我们先来理解
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的实现比较简单,如下:
想要理解必须化繁为简,理解得越简单,也就理解得越透彻。进一步简化
bind
的原理,等同于谁调用bind
,就返回一个新的function。我们假设函数
fn
调用bind
方法如fn.bind([1, 2])
,经过简化,忽略bind
绑定参数的部分,最终返回如下:以上,将
Seterusnya, saya akan menganalisis pelaksanaan kedua anda terlebih dahulu, dan kemudian menganalisis pelaksanaan ketiga anda. Pelaksanaan anda kelihatan seperti ini: 🎜 🎜Sesiapa yang memanggilfn
替换为Array.prototype.push.call
,[1, 2]
替换为Array.prototype.push
tidak menguras
akan sama denganini
atauself
Ini bermaknaself
ialah tatasusunanKaedah tolak
.menggantikan
self
danpush
luaran terakhir adalah bersamaan dengan fungsi berikut: 🎜 🎜Fungsi diletakkan di sini Mari kita fahami dahulu fungsiapply
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 denganb.a(arg1, arg2,…)
🎜 🎜Formula 1:a.apply(b, arguments) === b.a(arg1, arg2,…)
🎜 🎜Memandangkancall
danapply
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: 🎜 🎜Function.prototype.call.apply(Array.prototype.push, arguments)
adalah relatif kepada: 🎜 🎜Array.prototype.push.call(arg1, arg2,…)
, kemudian: 🎜 🎜push([], 1)
bersamaan denganArray.prototype.push.call([], 1)
, kemudian gantikannya kepada Formula 2 kuat> , bersamaan dengan: 🎜 🎜🎜Seterusnya, izinkan saya menganalisis pelaksanaan ketiga anti-kari: 🎜 🎜Untuk bahagian
this.call.bind(this);
,this
bersamaan denganArray.prototype.push
, maka kesetaraan keseluruhan ialah seperti berikut: 🎜 🎜bind
, ia adalah setara dengan sesiapa sahaja yang memanggilbind
mengembalikan fungsi baharu. 🎜 🎜Kami menganggap bahawa fungsifn
memanggil kaedahbind
sepertifn.bind([1, 2])
, yang dipermudahkan dan mengabaikanbindBahagian yang mengikat parameter akhirnya kembali seperti berikut: 🎜 rrreee 🎜Di atas, gantikanArray.prototype.push.call.bind(Array.prototype.push)
akan bersamaan dengan:fn
denganArray.prototype.push.call
dan[1, 2]
denganArray.prototype
, kemudian: 🎜Array.prototype.push.call.bind(Array.prototype.push)
将等同于: rrreee这个看起来和反柯里化的第二种实现有些不大相同,不要急,虽然表面上看起来不一致,但骨子里还是一致的。请耐心往下看:
不同的地方在于前半部分
rrreeeArray.prototype.push.call
,这里它是一个整体,实际上想代表的就是call方法。而我们都知道,所有函数的call方法,最终都是Function.prototype
的call
方法。那么,就有如下恒等式成立:那么以上函数将等同于:
rrreee褪去代入的参数,函数可还原为:
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:bind
rrreeeArray.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 kaedahpanggilan
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 tentangbind
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🎜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)
Keluarkan parameter pertama x = b ||
yang dicipta
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.
sendiri menunjuk ke Array.prototype.push
(Function.prototype.call).apply(Array.prototype.push, arguments);
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.
argumen ialah objek seperti tatasusunan [arr, 1]. Transform 3 untuk mendapatkan: Array.prototype.push.(Function.prototype.call)(arr, 1)
Kod sumber panggilan telah dijelaskan, jadi tukar 4, dan dapatkan arr.(Array.prototype.push)(1)
Tulis dengan lebih baik, arr.push(1)