Maison > Questions et réponses > le corps du texte
Voici deux implémentations de uncurring
Atteindre 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]
Atteindre 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]
Les deux résultats sont les mêmes, mais je suis un peu confus quant à la deuxième méthode de mise en œuvre, principalement ici
第一种方式显示的用self,在这里也就是push方法执行了一下,
self.apply(context, arguments);
但是如下第二种实现方式,却没有发现self执行的痕迹,
按我的理解这里就是用apply修改call的上下文为self,这里也就是push,
但这样有执行push方法吗?难道call内部的实现帮忙执行了self?求解
Function.prototype.call.apply(self, arguments);
J'ai été instantanément cliqué par vous, merci !
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);
Cela semble un peu compliqué, mais c'est en fait facile à comprendre.
En fait, votre deuxième implémentation peut également conduire à la troisième implémentation de l'anti-currying : 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);
}
Ensuite, j'analyserai d'abord votre deuxième implémentation, puis j'analyserai votre troisième implémentation. Votre implémentation ressemble à ceci : 🎜
Array.prototype.push.call === Function.prototype.call //true
🎜Celui qui appelle uncurrying
sera égal à this
ou self
. Cela signifie que self
est le tableau . La méthode push
.self
, et le push
externe final est équivalent à la fonction suivante : 🎜
function(){
return Function.prototype.call.apply(Array.prototype.push, arguments);
}
🎜La fonction est placée ici. Comprenons d'abord que la fonction apply
a pour fonction de décomposer le tableau en paramètres. 🎜
🎜Formule de dérivation : a.apply(b, arguments)
signifie traiter b comme ce contexte, ce qui équivaut à appeler la méthode a sur b et à transmettre tous les paramètres. Si b lui-même contient une méthode, alors cela équivaut à b.a(arg1, arg2,…)
🎜
🎜Formule 1 : a.apply(b, arguments) === b.a(arg1, arg2,…)
🎜
🎜Étant donné que call
et apply
ont le même effet, à l'exception d'un traitement des paramètres incohérent, la formule peut être encore évoluée pour obtenir : 🎜
🎜Formule 2 : a.call(b, arg) === b.a(arg)
🎜
🎜Remplacez la Formule 1 dans la fonction ci-dessus, il y a : 🎜
🎜a = Function.prototype.call
Autrement dit, a est égal à la méthode d'appel. 🎜
🎜On branche ensuite la formule, on a : 🎜
🎜b = Array.prototype.push
Autrement dit, b est égal à la méthode push du tableau🎜
🎜Alors Function.prototype.call.apply(Array.prototype.push, arguments)
est relatif à : 🎜
🎜Array.prototype.push.call(arg1, arg2,…)
, puis : 🎜
🎜push([], 1)
est équivalent à Array.prototype.push.call([], 1)
, puis remplacez-le par Formule 2 fort> , équivalent à : 🎜
🎜[].push(1)
🎜
🎜La réponse est déjà évidente : ajouter le chiffre 1 à la fin du tableau. 🎜
this.call.bind(this);
, this
est équivalent à Array.prototype.push
, alors l'équivalent global est comme suit : 🎜
🎜Array.prototype.push.call.bind(Array.prototype.push)
🎜
🎜La difficulté ici réside dans la méthode bind. La mise en œuvre de bind est relativement simple, comme suit : 🎜
function(){
return Function.prototype.call.apply(self, arguments);
}
🎜Si vous voulez comprendre, vous devez simplifier le complexe. Plus vous comprenez simple, plus vous comprendrez en profondeur. Pour simplifier encore le principe de bind
, cela équivaut à celui qui appelle bind
renvoyant une nouvelle fonction. 🎜
🎜Nous supposons que la fonction fn
appelle la méthode bind
telle que fn.bind([1, 2])
, qui est simplifiée et ignore bind< /code>La partie qui lie les paramètres renvoie finalement comme suit : 🎜
rrreee
🎜Ci-dessus, remplacez fn
par Array.prototype.push.call
et [1, 2]
par Array.prototype push.
, puis : 🎜Array.prototype.push.call.bind(Array.prototype.push)
sera équivalent à : Array.prototype.push.call.bind(Array.prototype.push)
将等同于:
rrreee
这个看起来和反柯里化的第二种实现有些不大相同,不要急,虽然表面上看起来不一致,但骨子里还是一致的。请耐心往下看:
不同的地方在于前半部分 Array.prototype.push.call
,这里它是一个整体,实际上想代表的就是call方法。而我们都知道,所有函数的call方法,最终都是Function.prototype
的 call
方法。那么,就有如下恒等式成立:
rrreee
那么以上函数将等同于:
rrreee
褪去代入的参数,函数可还原为:
rrreee
综上,最终反柯里化的第三种实现将和第二种实现完全一致,推理完毕,码字不易,喜欢的请点个赞谢谢~
为了加深对bind
rrreee
Cela semble un peu différent de la deuxième implémentation de l'anti-currying. Ne vous inquiétez pas, même si cela semble incohérent en surface, c'est toujours cohérent au fond. Soyez patient et lisez ci-dessous :
La différence réside dans la première moitié de Array.prototype.push.call
, qui est ici un tout et représente en fait la méthode d'appel. Et nous savons tous que la méthode d'appel de toutes les fonctions est finalement la méthode call
de Function.prototype
. Alors, l'identité suivante est valable :
rrreee
Alors la fonction ci-dessus sera équivalente à : 🎜
rrreee
🎜En supprimant les paramètres substitués, la fonction peut être restaurée à : 🎜
rrreee
🎜Pour résumer, la troisième implémentation finale de l'anti-currying sera tout à fait cohérente avec la deuxième implémentation. Le raisonnement est complet et le codage n'est pas facile Si vous l'aimez, n'hésitez pas à l'aimer et merci~. 🎜
🎜Afin d'approfondir ma compréhension du bind
et du currying, j'ai également écrit un blog pour les analyser en profondeur. 🎜
🎜Veuillez vous référer à Currying et Decurrying dans Functional Programming et Function.prototype.bind Method Guide. 🎜
🎜Les étudiants qui l’aiment peuvent également prêter attention au cours approfondi frontal de Lewis dans ma chronique🎜répondre0
淡淡烟草味2017-05-16 13:43:58
Bases
Les différences et les fonctions d'appel et de candidature ne seront pas décrites en détail
Appelez et appliquez l'implémentation du code source
Ils sont très proches Ici, nous introduisons uniquement l'appel, par exemple : a.call(b, c)
Supprimez le premier paramètre x = b || {}
x.fn = a
Splice les paramètres sauf le premier paramètre, séparés par des virgules, le résultat est d
Créez une fonction e = new Function() dans un environnement d'exécution indépendant et exécutez x.fn(d) à l'intérieur de la fonction
Exécuter l'e créé
Compréhension de l'option 2
Le problème de l'appel et de l'application pour développer la méthode objet n'est pas pris en compte ici, car les méthodes seront créées dynamiquement à partir du code source, ce problème ne sera donc pas abordé en détail ci-dessous.
Function.prototype.call.apply(self, arguments);
var push = Array.prototype.push.uncurrying ();
self pointe vers Array.prototype.push
(Function.prototype.call).apply(Array.prototype.push, arguments);
Utilisez le code source qui vient d'être expliqué et transformez 2 pour obtenir : Array.prototype.push.(Function.prototype.call)(arguments). Il doit également être converti ici. L'appel n'accepte pas un tableau, voir 4.
arguments est un objet de type tableau [arr, 1]. Transformez 3 pour obtenir : Array.prototype.push.(Function.prototype.call)(arr, 1)
Le code source de l'appel a été expliqué, alors changez 4 et obtenez arr.(Array.prototype.push)(1)
Écrivez-le mieux, arr.push(1)