È ansible modificare una funzione Javascript dopo averla dichiarata?

Diciamo che ho var a = function() { return 1; } var a = function() { return 1; } . È ansible modificare a modo che a() restituisca 2 ? Forse modificando una proprietà dell’object, dal momento che ogni funzione è un object ?

Aggiornamento: Wow, grazie per tutte le risposte. Tuttavia, temo di non voler semplicemente riassegnare una variabile, ma in realtà modificare una funzione esistente. Sto pensando a come combinare le funzioni parziali in Scala per creare una nuova funzione PartialFunction . Mi interessa scrivere qualcosa di simile in Javascript e pensavo che la funzione esistente potesse forse essere aggiornata, piuttosto che creare un object Function completamente nuovo.

Puoi fare tutti i tipi di cose divertenti con javascript, incluse le funzioni di ridefinizione:

 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 

Ecco.

Modifica: aggiornato per mostrare questo in uno scenario più pazzo:

 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 

Potete vedere qui che anche se “test” è definito per primo, e successivamente ridefiniamo substring (), il cambiamento si applica ancora.

Nota a margine: dovresti davvero riconsiderare la tua architettura se stai facendo questo … confonderai la schifezza di qualche povero sviluppatore a 5 anni lungo la strada quando guarderà una definizione di funzione che dovrebbe restituire 1 , ma sembra sempre tornare 2 ….

Ho usato qualcosa di simile per modificare una funzione esistente la cui dichiarazione non era accessibile per me:

 // 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
);

Invece di toSource () potresti probabilmente usare toString () per ottenere una stringa contenente la dichiarazione della funzione. Alcune chiamate a replace () per preparare la stringa da utilizzare con Function Constructor e per modificare la sorgente della funzione.

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

tecnicamente, stai perdendo una definizione di funzione e la sostituisci con un’altra.

Che ne dici di questo, senza dover ridefinire la funzione:

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

Pertanto, si desidera modificare direttamente il codice di una funzione e non solo riassegnare una funzione diversa a una variabile esistente.

Odio dirlo, ma per quanto sono stato in grado di capirlo – e ho provato -, non si può fare. È vero, una funzione è un object e come tale ha metodi e proprietà che possono essere modificati e sovrascritti sull’object stesso. Sfortunatamente, il corpo della funzione non è uno di questi. Non è assegnato a una proprietà pubblica.

La documentazione su MDN elenca le proprietà e i metodi dell’object funzione. Nessuno di questi ci dà l’opportunità di manipolare il corpo della funzione dall’esterno.

Questo perché, secondo le specifiche , il corpo della funzione è memorizzato nella proprietà interna [[Code]] dell’object funzione, a cui non è ansible accedere direttamente.

Mi sto attenendo alla soluzione di jvenema, nella quale non mi piace la variabile globale “vecchia”. Sembra meglio mantenere la vecchia funzione all’interno di quella nuova:

 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 

Tutte le soluzioni possibili si attengono a un “approccio di avvolgimento di funzione”. Il più affidabile tra loro sembra essere quello di rplantiko .

Tale involucro di funzioni può essere facilmente rimosso. Il concetto / modello stesso potrebbe essere chiamato “Modificazione del metodo”. La sua implementazione appartiene sicuramente a Function.prototype . Sarebbe bello essere supportati un giorno con modificatori standard del metodo prototipale come before , after , around , after afterThrowing e after afterThrowing afterFinally .

Per quanto riguarda l’esempio di cui sopra di 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 

… e facendo uso di [around] , il codice si trasformsrebbe in …

 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()); 

Non puoi definirlo di nuovo più tardi? Quando vuoi la modifica prova a ridefinirla come:

 a = function() { return 2; } 

Se esegui il debug di javascript e vuoi vedere come le modifiche al codice influiscono sulla pagina, puoi utilizzare questa estensione di Firefox per visualizzare / modificare i javascript:

Esegui estensione firefox JS: https://addons.mozilla.org/en-US/firefox/addon/1729

Assolutamente. Assegnagli semplicemente una nuova funzione.

Questo è un chiaro esempio basato su un timepicker di controllo eworld.ui http://www.eworldui.net

Avendo un object TimePicker eworld.ui cui JavaScript è irraggiungibile dall’esterno, non è ansible trovare alcun js relativo a quei controlli. Quindi, come puoi aggiungere un evento onchange al timepicker?

C’è una funzione js chiamata quando Select un intervallo tra tutte le opzioni che il controllo ti offre. Questa funzione è: TimePicker_Up_SelectTime

Per prima cosa devi copiare il codice all’interno di questa funzione.

Valuta … 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 + "();"); 

}

Adesso

Usando il codice che hai salvato prima riassegna lo stesso codice sorgente ma aggiungi quello che vuoi ..

TimePicker_Up_SelectTime = function (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); } 

Ho aggiunto My Function alla funzione, così ora posso simulare un evento onchange quando seleziono un orario.

RaiseChange (…) potrebbe essere quello che vuoi.

Puoi cambiare funzioni come altri oggetti

 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 
  function get_func(func) {//from StackOverflow //var args = Array.prototype.slice.call(arguments); var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var ARGUMENT_NAMES = /([^\s,]+)/g; var fnStr = func.toString().replace(STRIP_COMMENTS, ''); var args = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); //var code = func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]; var code =fnStr.slice(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}")); var func_full_name=fnStr.substr(0, fnStr.indexOf('{') ); var func_name=fnStr.slice(9, fnStr.indexOf('(')); if(args === null){ args = []; } return { func_name:func_name,func_full_name:func_full_name, code:code, args:args}; } function str_trim(str){ //replaces multi-line characters return str.replace(/\n/g,'').replace(/^ +| +$/gm, '').trim(); } function edit_func(func,callback){ var a_func=get_func(func); var lines = a_func.code.split('\n'); var output=[]; for(var i=0;i 

Prova questo Cambia la funzione originale con un nuovo codice usando un callback per ispezionare ogni riga di codice.