Stavo solo leggendo questa domanda e volevo provare il metodo alias piuttosto che il metodo function-wrapper, ma non riuscivo a farlo funzionare in Firefox 3 o 3.5beta4 o Google Chrome, sia nelle windows di debug che in in una pagina web di prova.
Firebug:
>>> window.myAlias = document.getElementById function() >>> myAlias('item1') >>> window.myAlias('item1') >>> document.getElementById('item1')
Se lo metto in una pagina web, la chiamata a myAlias mi dà questo errore:
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///[...snip...]/test.html :: :: line 7" data: no]
Chrome (con >>> inserito per chiarezza):
>>> window.myAlias = document.getElementById function getElementById() { [native code] } >>> window.myAlias('item1') TypeError: Illegal invocation >>> document.getElementById('item1') ?
E nella pagina di test ottengo la stessa “invocazione illegale”.
- Const di livello superiore non influenza la firma di una funzione
- C'è un modo in cui un programma C / C ++ può bloccarsi prima di main ()?
- Capire come funzionano le funzioni ricorsive
- Risoluzione di sovraccarico C ++
- Passando la struttura per funzionare
Sto facendo qualcosa di sbagliato? Qualcun altro può riprodurlo?
Inoltre, stranamente, ho appena provato e funziona in IE8.
Devi associare quel metodo all’object del documento. Guarda:
>>> $ = document.getElementById getElementById() >>> $('bn_home') [Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no] >>> $.call(document, 'bn_home')
Quando si esegue un alias semplice, la funzione viene richiamata sull’object globale, non sull’object del documento. Utilizzare una tecnica chiamata chiusure per risolvere questo problema:
function makeAlias(object, name) { var fn = object ? object[name] : null; if (typeof fn == 'undefined') return function () {} return function () { return fn.apply(object, arguments) } } $ = makeAlias(document, 'getElementById'); >>> $('bn_home')
In questo modo non perdi il riferimento all’object originale.
Nel 2012, c’è il nuovo metodo di bind
di ES5 che ci consente di farlo in un modo più elaborato:
>>> $ = document.getElementById.bind(document) >>> $('bn_home')
Ho scavato in profondità per comprendere questo particolare comportamento e penso di aver trovato una buona spiegazione.
Prima di entrare nel motivo per cui non si è in grado di creare alias document.getElementById
, proverò a spiegare come funzionano le funzioni / oggetti di JavaScript.
Ogni volta che invochi una funzione JavaScript, l’interprete JavaScript determina un ambito e lo passa alla funzione.
Considera la seguente funzione:
function sum(a, b) { return a + b; } sum(10, 20); // returns 30;
Questa funzione è dichiarata nell’ambito della finestra e quando la si invoca il valore di this
all’interno della funzione sum sarà l’object Window
globale.
Per la funzione “sum”, non importa quale sia il valore di “questo” in quanto non lo utilizza.
Considera la seguente funzione:
function Person(birthDate) { this.birthDate = birthDate; this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); }; } var dave = new Person(new Date(1909, 1, 1)); dave.getAge(); //returns 100.
Quando si chiama la funzione dave.getAge, l’interprete JavaScript vede che si sta chiamando la funzione getAge sull’object dave
, quindi imposta su dave
e chiama la funzione getAge
. getAge()
restituirà correttamente 100
.
Potresti sapere che in JavaScript puoi specificare l’ambito usando il metodo apply
. Proviamoci.
var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009 var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009 dave.getAge.apply(bob); //returns 200.
Nella riga precedente, invece di consentire a JavaScript di decidere l’ambito, si passa l’ambito manualmente come object bob
. getAge
ora restituirà 200
anche se hai ‘pensato’ di aver chiamato getAge
sull’object dave
.
Qual è il punto di tutto quanto sopra? Le funzioni sono “vagamente” collegate ai tuoi oggetti JavaScript. Ad esempio puoi farlo
var dave = new Person(new Date(1909, 1, 1)); var bob = new Person(new Date(1809, 1, 1)); bob.getAge = function() { return -1; }; bob.getAge(); //returns -1 dave.getAge(); //returns 100
Facciamo il prossimo passo.
var dave = new Person(new Date(1909, 1, 1)); var ageMethod = dave.getAge; dave.getAge(); //returns 100; ageMethod(); //returns ?????
ageMethod
esecuzione ageMethod
genera un errore! Quello che è successo?
Se si leggono attentamente i miei punti sopra, si noterà che il metodo dave.getAge
è stato chiamato con dave
come object mentre JavaScript non è stato in grado di determinare l”ambito’ per ageMethod
esecuzione ageMethod
. Quindi ha superato “Window” globale come “this”. Ora che la window
non ha una proprietà ageMethod
, ageMethod
esecuzione ageMethod
fallirà.
Come risolvere questo? Semplice,
ageMethod.apply(dave); //returns 100.
Tutto ciò ha senso? Se lo fa, allora sarai in grado di spiegare perché non sei in grado di creare alias document.getElementById
:
var $ = document.getElementById; $('someElement');
$
viene chiamato con window
quanto this
e se getElementById
implementazione getElementById
si aspetta che this
sia document
, fallirà.
Ancora una volta per risolvere questo problema, puoi farlo
$.apply(document, ['someElement']);
Quindi, perché funziona in Internet Explorer?
Non conosco l’implementazione interna di getElementById
in IE, ma un commento in jQuery source ( inArray
metodo inArray
) dice che in IE, window == document
. Se questo è il caso, allora l’aliasing document.getElementById
dovrebbe funzionare in IE.
Per illustrare ulteriormente, ho creato un esempio elaborato. Dai un’occhiata alla funzione Person
qui sotto.
function Person(birthDate) { var self = this; this.birthDate = birthDate; this.getAge = function() { //Let's make sure that getAge method was invoked //with an object which was constructed from our Person function. if(this.constructor == Person) return new Date().getFullYear() - this.birthDate.getFullYear(); else return -1; }; //Smarter version of getAge function, it will always refer to the object //it was created with. this.getAgeSmarter = function() { return self.getAge(); }; //Smartest version of getAge function. //It will try to use the most appropriate scope. this.getAgeSmartest = function() { var scope = this.constructor == Person ? this : self; return scope.getAge(); }; }
Per la funzione Person
sopra, ecco come si comportano i vari metodi getAge
.
Creiamo due oggetti usando la funzione Person
.
var yogi = new Person(new Date(1909, 1,1)); //Age is 100 var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200
console.log(yogi.getAge()); //Output: 100.
Semplice, il metodo getAge ottiene object yogi
come this
ed emette 100
.
var ageAlias = yogi.getAge; console.log(ageAlias()); //Output: -1
JavaScript interepreter imposta l’object window
come this
e il nostro metodo getAge
restituirà -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
Se impostiamo l’ambito corretto, puoi utilizzare il metodo ageAlias
.
console.log(ageAlias.apply(anotherYogi)); //Output: 200
Se passiamo in qualche altro object, calcolerà comunque l’età correttamente.
var ageSmarterAlias = yogi.getAgeSmarter; console.log(ageSmarterAlias()); //Output: 100
La funzione ageSmarter
catturato l’originale di this
object, quindi ora non devi preoccuparti di fornire l’ambito corretto.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
Il problema con ageSmarter
è che non puoi mai impostare l’ambito su un altro object.
var ageSmartestAlias = yogi.getAgeSmartest; console.log(ageSmartestAlias()); //Output: 100 console.log(ageSmartestAlias.apply(document)); //Output: 100
La funzione ageSmartest
utilizzerà l’ambito originale se viene fornito un ambito non valido.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Sarai comunque in grado di passare un altro object Person
a getAgeSmartest
. 🙂
Questa è una risposta breve.
Quanto segue fa una copia di (un riferimento a) la funzione. Il problema è che ora la funzione si trova sull’object window
quando è stato progettato per la vita sull’object document
.
window.myAlias = document.getElementById
Le alternative sono
- usare un wrapper (già menzionato da Fabien Ménager)
-
oppure puoi usare due alias.
window.d = document // A renamed reference to the object window.d.myAlias = window.d.getElementById
Un’altra risposta breve, solo per il wrapping / aliasing di console.log
e metodi di registrazione simili. Tutti si aspettano di essere nel contesto della console
.
Questo è utilizzabile quando si console.log
wrapping di console.log
con alcuni fallback, nel caso in cui tu o i tuoi utenti vi siano problemi durante l’ utilizzo di un browser che non lo supporta (sempre) . Tuttavia, non è una soluzione completa a questo problema, in quanto è necessario estendere i controlli e una riserva: il tuo chilometraggio può variare.
Esempio usando gli avvertimenti
var warn = function(){ console.warn.apply(console, arguments); }
Quindi usalo come al solito
warn("I need to debug a number and an object", 9999, { "user" : "Joel" });
Se si preferisce vedere gli argomenti di registrazione racchiusi in una matrice (lo faccio, la maggior parte delle volte), sostituire .apply(...)
con .call(...)
.
Dovrebbe funzionare con console.log()
, console.debug()
, console.info()
, console.warn()
, console.error()
. Vedi anche console
su MDN .
console firebug
Oltre ad altre ottime risposte, esiste un semplice metodo jQuery $ .proxy .
Puoi alias in questo modo:
myAlias = $.proxy(document, 'getElementById');
O
myAlias = $.proxy(document.getElementById, document);
In realtà non è ansible “puro alias” una funzione su un object predefinito. Pertanto, il più vicino aliasing che puoi ottenere senza il wrapping è rimanere nello stesso object:
>>> document.s = document.getElementById; >>> document.s('myid');
- Funzione onClick "this" Restituisce l'object Window
- Come creare una funzione R a livello di codice?
- Sostituisci una funzione che viene importata in uno spazio dei nomi
- Esiste un visualizzatore di funzioni di esportazione DLL nativo?
- Come viene allocata la struttura dei risultati di localtime in C?
- Passare funzioni come argomenti in Matlab
- Due modi per definire le funzioni in Scala. Qual è la differenza?
- Imposta un valore di parametro predefinito per una funzione JavaScript