javascript - Demander de l'aide pour appeler et postuler, anti-curry
淡淡烟草味
淡淡烟草味 2017-05-16 13:41:58
0
2
508

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
淡淡烟草味
淡淡烟草味

répondre à tous(2)
我想大声告诉你

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,谁就等于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);
}
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.
remplace 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. 🎜

🎜Ensuite, permettez-moi d'analyser la troisième implémentation de l'anti-currying : 🎜 🎜Pour la partie 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 bindLa 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.prototypecall方法。那么,就有如下恒等式成立:

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🎜
淡淡烟草味

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)

.
  1. Supprimez le premier paramètre x = b || {}

  2. x.fn = a

  3. Splice les paramètres sauf le premier paramètre, séparés par des virgules, le résultat est d

  4. 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

  5. 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 ();
  1. self pointe vers Array.prototype.push

  2. (Function.prototype.call).apply(Array.prototype.push, arguments);

  3. 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.

  4. arguments est un objet de type tableau [arr, 1]. Transformez 3 pour obtenir : Array.prototype.push.(Function.prototype.call)(arr, 1)

  5. Le code source de l'appel a été expliqué, alors changez 4 et obtenez arr.(Array.prototype.push)(1)

  6. Écrivez-le mieux, arr.push(1)

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal