web-dev-qa-db-fra.com

Pouvez-vous modifier une fonction Javascript après l'avoir déclarée?

Disons que j'ai var a = function() { return 1; }. Est-il possible de modifier a afin que a() renvoie 2? Peut-être en modifiant une propriété de l'objet a, puisque chaque fonction est un objet ?

Mise à jour: Wow, merci pour toutes les réponses. Cependant, j'ai bien peur de ne pas chercher simplement à réaffecter une variable mais à éditer une fonction existante. Je réfléchis à la manière dont vous pouvez combiner des fonctions partielles dans Scala pour créer une nouvelle variable PartialFunction. Je voudrais écrire quelque chose de similaire en Javascript et je pensais que la fonction existante pourrait peut-être être mise à jour, plutôt que de créer un tout nouvel objet Function.

56
pr1001

Vous pouvez faire toutes sortes de choses amusantes avec JavaScript, y compris les fonctions de redéfinition:

var a = function(){ return 1; }

alert(a()); //1

// keep a reference
var old = a;

// redefine
a = function(){
  // call the original function with any arguments specified, storing the result
  var originalResult = old.apply(old, arguments);
  // add one
  return originalResult + 1;
};
alert(a()); //2

Voila.

Edit: mis à jour pour afficher ceci dans un scénario plus fou:

var test = new String("123");
console.log(test.toString()); // logs 123
console.log(test.substring(0)); // logs 123
String.prototype.substring = function(){ return "hahanope"; }
console.log(test.substring(0)); // logs hahanope

Vous pouvez voir ici que même si "test" est défini en premier et que nous redéfinissons ensuite substring (), la modification s'applique toujours.

Note latérale: vous devriez vraiment reconsidérer votre architecture si vous faites cela ... vous allez confondre la merde d'un développeur médiocre dans 5 ans s'il cherche une définition de fonction qui est supposée revenir 1 , mais semble toujours revenir 2 ....

41
jvenema

J'ai utilisé quelque chose comme ceci pour modifier une fonction existante dont la déclaration n'était pas accessible pour moi:

// declare function foo
var foo = function (a) { alert(a); };

// modify function foo
foo = new Function (
  "a",
  foo.toSource()
    .replace("alert(a)", "alert('function modified - ' + a)")
    .replace(/^function[^{]+{/i,"")  // remove everything up to and including the first curly bracket
    .replace(/}[^}]*$/i, "")  // remove last curly bracket and everything after<br>
);

Au lieu de toSource (), vous pourriez probablement utiliser toString () pour obtenir une chaîne contenant la déclaration de la fonction. Certains appels à replace () pour préparer la chaîne à utiliser avec le constructeur de fonctions et pour modifier le source de la fonction.

39
hmundt
var a = function() { return 1; }
alert(a()) // 1
a = function() { return 2; }
alert(a()) // 2

techniquement, vous perdez une définition de fonction et la remplacez par une autre.

23
Sam Hasler

Que diriez-vous de cela, sans avoir à redéfinir la fonction:

var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2
15
jpsimons

Vous voulez donc modifier le code d'une fonction directement, à la place, et pas simplement réaffecter une fonction différente à une variable existante.

Je déteste le dire, mais autant que j'ai pu le comprendre - et j'ai essayé -, cela ne peut être fait. Certes, une fonction est un objet et, à ce titre, elle a des méthodes et des propriétés qui peuvent être modifiées et remplacées sur l’objet même. Malheureusement, le corps de fonction n'en fait pas partie. Il n'est pas affecté à une propriété publique.

La documentation sur MDN répertorie les propriétés et les méthodes de l'objet fonction. Aucun d'entre eux ne nous donne l'occasion de manipuler le corps de la fonction de l'extérieur.

En effet, conformément à la spécification , le corps de la fonction est stocké dans la propriété interne [[Code]] de l'objet fonction auquel il est impossible d'accéder directement.

14
hashchange

Je m'en tiens à la solution de jvenema, dans laquelle je n'aime pas la variable globale "old". Il semble préférable de conserver l'ancienne fonction dans la nouvelle:

function a() { return 1; }

// redefine
a = (function(){
  var _a = a;
  return function() {
  // You may reuse the original function ...
  // Typical case: Conditionally use old/new behaviour
    var originalResult = _a.apply(this, arguments);
  // ... and modify the logic in any way
    return originalResult + 1;
    }
})();
a()  // --> gives 2
10
rplantiko

Toutes les solutions envisageables s’en tiennent à une "approche de recouvrement des fonctions" . La plus fiable d'entre elles semble être celle de rplantiko .

Un tel habillage de fonctions peut facilement être extrait. Le concept/modèle Lui-même pourrait être appelé "Méthode de modification". Son implémentation est bien Appartient à Function.prototype. Il serait agréable d’être sauvegardé. Un jour par des modificateurs de méthode de prototype standard tels que before, after, around, afterThrowing et afterFinally.

En ce qui concerne l'exemple susmentionné de rplantiko ...

function a () { return 1; }

// redefine
a = (function () {
  var _a = a;
  return function () {
    // You may reuse the original function ...
    // Typical case: Conditionally use old/new behaviour
    var originalResult = _a.apply(this, arguments);
    // ... and modify the logic in any way
    return originalResult + 1;
  };
})();

a(); // --> gives 2

... et en utilisant [around], le code se transformerait en ...

function a () { return 1; }

console.log("a : ", a);
console.log("a() : ", a());


a = a.around(function (proceed, interceptor, args) {
  return (proceed() + 1);
});

console.log("a : ", a);
console.log("a() : ", a());
3
Peter Seliger

Vous pouvez changer les fonctions comme d'autres objets

var a1 = function(){return 1;}
var b1 = a1;
a1 = function(){
  return b1() + 1;
};
console.log(a1()); // return 2

// OR:
function a2(){return 1;}
var b2 = a2;
a2 = function(){
  return b2() + 1;
};
console.log(a2()); // return 2

0
morteza ataiy

Ceci est un Exemple clair basé sur un timepicker de contrôle eworld.uiwww.eworldui.net

Avec un code TimePicker eworld.ui où JavaScript est inaccessible de l'extérieur, vous ne pouvez trouver aucun fichier js associé à ces contrôles. Alors, comment pouvez-vous ajouter un événement onchange au timepicker?

Il existe une fonction js appelée lorsque vous Select un temps entre toutes les options proposées par le contrôle. Cette fonction est: TimePicker_Up_SelectTime

Vous devez d’abord copier le code dans cette fonction.

Evaluer ... quikwatch ...TimePicker_Up_SelectTime.toString()

function TimePicker_Up_SelectTime(tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
    document.getElementById(tbName).value = selTime;
    if(lblName != '')
    document.getElementById(lblName).innerHTML = selTime;
    document.getElementById(divName).style.visibility = 'hidden';
    if(enableHide)
    TimePicker_Up_ShowHideDDL('visible');
    if(customFunc != "")
    eval(customFunc + "('" + selTime + "', '" + tbName + "');");
    eval(postbackFunc + "();");

}

À présent

En utilisant le code que vous avez enregistré avant de réaffecter le même code source mais en ajoutant ce que vous voulez.

TimePicker_Up_SelectTime = fonction (tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) { document.getElementById (tbName) .value = selTime; if (lblName! = '') document.getElementById (lblName) .innerHTML = selTime; document.getElementById (divName) .style.visibility = 'hidden'; if (enableHide) TimePicker_Up_ShowHideDDL ('visible'); if (customFunc! = "") eval (customFunc + "('" + selTime + "'," "+ tbName +" '); ");). eval (postbackFunc + "();");

  >>>>>>>  My function  >>>>>   RaiseChange(tbName);
}

J'ai ajouté ma fonction à la fonction pour pouvoir maintenant simuler un événement onchange lorsque je sélectionne une heure.

RaiseChange (...) pourrait être ce que vous voulez.

0
Pocho La Pantera

Absolument. Il suffit de lui attribuer une nouvelle fonction. 

0
Fitzchak Yitzchaki

Ne pouvez-vous pas simplement le redéfinir plus tard? Quand vous voulez le changement, essayez simplement de le redéfinir comme suit:

a = function() { return 2; }
0
Wayne Koorts

Si vous êtes en train de déboguer du javascript et que vous souhaitez voir comment les modifications apportées au code affectent la page, vous pouvez utiliser cette extension Firefox pour afficher/modifier les javascripts:

Exécutez l'extension JS firefox: https://addons.mozilla.org/en-US/firefox/addon/1729

0
Jon Onstott