Rumah > Soal Jawab > teks badan
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
我想大声告诉你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
,谁就等于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
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
.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: 🎜
🎜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 kuat> , bersamaan dengan: 🎜
🎜this.call.bind(this);
, this
bersamaan dengan Array.prototype.push
, maka kesetaraan keseluruhan ialah 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.prototype
的 call
方法。那么,就有如下恒等式成立:
那么以上函数将等同于:
rrreee褪去代入的参数,函数可还原为:
rrreee综上,最终反柯里化的第三种实现将和第二种实现完全一致,推理完毕,码字不易,喜欢的请点个赞谢谢~
为了加深对bind
rrreee
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 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🎜淡淡烟草味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)
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.
Function.prototype.call.apply(self, arguments);
var push = Array.prototype.push.uncurrying ();