Ceci est la suite de cette question mais pour ARRAYS. Supposons que je veuille appeler la fonction de tableau avec 2 paramètres, par exemple

console.log(
  [3,4,5].slice(1,2)
)

Dans la première étape, je réduis les caractères définis à la convention jsfuck où nous avons 6 caractères disponibles : []()!+ (et pour plus de clarté: avec az lettres AZ entourées de " (chaînes JS) et de nombres - qui sont faciles à convertir en ces 6 caractères):

console.log(
  [3,4,5]["slice"](1,2)
)

Le problème ici était la virgule (caractère interdit) mais nous pouvons surmonter ce problème en utilisant la technique intelligente suivante découverte par trincot:

console.log(
  [1]["concat"](2)["reduce"]([]["slice"]["bind"]([3,4,5]))
)

Mais la nouvelle question se pose:

Il est possible d'appeler une séquence de fonctions avec 2 (ou plus) paramètres sans les imbriquer (ce qui est imposé par la technique ci-dessus) mais de manière "flow" où nous appelons la fonction suivante à droite par exemple: [3,4,5].slice(1,2).concat(6).. (sans utiliser 'eval' comme solution où la chaîne est interprétée comme du code)? (pour une fonction avec un paramètre, c'est possible par exemple: [3,4,5].slice(1).concat(6))

-1
Kamil Kiełczewski 28 août 2020 à 13:21

3 réponses

Meilleure réponse

La technique existante pour envelopper le sujet de la méthode dans un tableau, qui est mentionnée ici, était destiné spécifiquement aux chaînes, transformant "chaîne" en ["chaîne"]. L'astuce consistait à utiliser .split() sans arguments. Après avoir appliqué cette astuce, il n'était pas si difficile d'utiliser les autres petites astuces pour appliquer la méthode souhaitée et permettre le chaînage sur le résultat.

Bien sûr, maintenant que le sujet est un tableau, nous ne pouvons pas utiliser .split().

Il s'avère que vous pouvez utiliser la méthode suivante pour que cela se produise pour les tableaux:

console.log(
  [3, 4, 5].reduce([].constructor).slice(-1)
)

Ceci est plutôt inefficace, car reduce va en fait itérer le tableau de sujets, détruisant le résultat de l'itération précédente, et donc seul le résultat d'une (la dernière) itération détermine le résultat. Vous obtenez les quatre arguments, qui sont passés au callback, dans un tableau, en utilisant le constructeur Array (ici [].constructor). Comme le quatrième argument est le tableau d'origine, nous pourrions le faire apparaître: mais cela nous laisserait avec le tableau d'origine. Nous le découpons : de cette façon, nous obtenons le tableau imbriqué.

En utilisant ceci avec les autres astuces, vous obtenez cette expression pour exécuter [3,4,5].slice(1,2):

console.log(
  [3].concat(4).concat(5).reduce([].constructor)
     .slice(-1)
     .concat([[1].concat(2)])
     .reduce([].fill.apply.bind([].slice))
)

Toutes les références de méthode peuvent être écrites en notation ["method"] afin que vous ne puissiez plus produire ces littéraux de chaîne avec JSF:

console.log(
  [3]["concat"](4)["concat"](5)["reduce"]([]["constructor"])
     ["slice"](-1)
     ["concat"]([[1]["concat"](2)])
     ["reduce"]([]["fill"]["apply"]["bind"]([]["slice"]))
)

Caveat

Cette solution repose sur l'appel de la fonction de rappel de réduction. Sachez qu'il n'est pas appelé lorsque le tableau sujet n'a qu'un seul élément. Dans ce cas, reduce renvoie simplement le tableau d'origine, ce qui n'est pas souhaité. En outre, cette méthode produira une exception lorsque le tableau de sujets est vide.

1
trincot 28 août 2020 à 15:08

Ici, je développe réponse trincot - sa belle solution a un problème pour le cas où le tableau est vide ou n'a qu'un seul élément. En utilisant son idée, je trouve une solution qui résout le problème avec un élément (mais un problème avec un tableau vide existe toujours).

Le problème clé: envelopper le tableau [1,2,3] dans un autre tableau pour obtenir [[1,2,3]] de manière fluide (sans emballage de code) - pour ce faire, nous pouvons utiliser le code suivant

console.log(
   [3,4,5].map([].constructor)[0].slice(-1)
)

console.log(
   [3].map([].constructor)[0].slice(-1)
)

La solution complète ressemble donc à

console.log(
  [3,4,5]
    // call slice (repeat this pattern for multi-param methods)
    .map([].constructor)[0].slice(-1)
    .concat([[1,2]]).reduce([].slice.apply.bind([].slice))
    // next method call in "flow" style
    .concat(6)   
)

Le code après avoir supprimé les virgules et les points se présente comme suit

console.log(
  [3]["concat"](4)["concat"](5)
    ["map"]([]["constructor"])[0]["slice"](-1)
    ["concat"]([[1]["concat"](2)])["reduce"]([]["slice"]["apply"]["bind"]([]["slice"]))
    ["concat"](6)   
)
1
Kamil Kiełczewski 28 août 2020 à 18:58

Ici, je développe ma propre réponse (basée sur idée trincot) - pour plus de clarté, j'ai fait une réponse séparée. Enfin, j'ai trouvé une solution qui fonctionne avec un tableau avec zéro, un et plusieurs éléments. Donc, le problème clé: envelopper le tableau d'entrée [3,4,5] par un autre tableau pour obtenir [[3,4,5]] dans "flow-way" en utilisant uniquement les opérateurs de droite est résolu :)

console.log(
       [].map([].constructor).concat([[[]]])[0].slice(-1)
)

console.log(
      [5].map([].constructor).concat([[[]]])[0].slice(-1)
)

console.log(
  [3,4,5].map([].constructor).concat([[[]]])[0].slice(-1)
)

Solution complète:

console.log(
  [3,4,5]
    // call slice (repeat this pattern for multi-param methods)
    .map([].constructor).concat([[[]]])[0].slice(-1)
    .concat([[1,2]]).reduce([].slice.apply.bind([].slice))
    // next method call in "flow" style
    .concat(6)   
)

Code final après suppression des virgules, des points

console.log(
  [3]["concat"](4)["concat"](5)
    ["map"]([]["constructor"])["concat"]([[[]]])[0]["slice"](-1)
    ["concat"]([[1]["concat"](2)])["reduce"]([]["slice"]["apply"]["bind"]([]["slice"]))
    ["concat"](6)   
)
1
Kamil Kiełczewski 28 août 2020 à 20:15