Estaba leyendo esta pregunta y quería probar el método de alias en lugar del método de envoltura de función, pero parece que no pude hacerlo funcionar en Firefox 3 o 3.5beta4, o Google Chrome, tanto en sus ventanas de depuración como en una página web de prueba.
Firebug:
>>> window.myAlias = document.getElementById
function()
>>> myAlias('item1')
>>> window.myAlias('item1')
>>> document.getElementById('item1')
<div id="item1">
Si lo pongo en una página web, la llamada a myAlias me da este error:
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 :: <TOP_LEVEL> :: line 7" data: no]
Chrome (con >>> insertado para mayor claridad):
>>> window.myAlias = document.getElementById
function getElementById() { [native code] }
>>> window.myAlias('item1')
TypeError: Illegal invocation
>>> document.getElementById('item1')
<div id=?"item1">?
Y en la página de prueba, obtengo la misma "Invocación ilegal".
¿Estoy haciendo algo mal? ¿Alguien más puede reproducir esto?
Además, por extraño que parezca, lo intenté y funciona en IE8.

Respuestas:
Tienes que vincular ese método al objeto del documento. Mira:
>>> $ = document.getElementById getElementById() >>> $('bn_home') [Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no] >>> $.call(document, 'bn_home') <body id="bn_home" onload="init();">Cuando está haciendo un alias simple, la función se llama en el objeto global, no en el objeto del documento. Utilice una técnica llamada cierres para solucionar este 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') <body id="bn_home" onload="init();">De esta forma no perderá la referencia al objeto original.
En 2012, existe el nuevo
bindmétodo de ES5 que nos permite hacer esto de una manera más elegante:>>> $ = document.getElementById.bind(document) >>> $('bn_home') <body id="bn_home" onload="init();">fuente
Investigué profundamente para comprender este comportamiento en particular y creo que he encontrado una buena explicación.
Antes de explicar por qué no puede crear un alias
document.getElementById, intentaré explicar cómo funcionan las funciones / objetos de JavaScript.Siempre que invoca una función de JavaScript, el intérprete de JavaScript determina un alcance y lo pasa a la función.
Considere la siguiente función:
function sum(a, b) { return a + b; } sum(10, 20); // returns 30;Esta función se declara en el ámbito de la ventana y cuando la invoca, el valor de
thisdentro de la función de suma será elWindowobjeto global .Para la función 'suma', no importa cuál sea el valor de 'esto' ya que no lo está usando.
Considere la siguiente función:
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.Cuando se llama a la función dave.getAge, el intérprete de JavaScript ve que está llamando la función getAge en el
daveobjeto, por lo que ponethisadavey llama a lagetAgefunción.getAge()regresará correctamente100.Es posible que sepa que en JavaScript puede especificar el alcance utilizando el
applymétodo. Probemos eso.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.En la línea anterior, en lugar de dejar que JavaScript decida el alcance, está pasando el alcance manualmente como
bobobjeto.getAgeahora regresará200a pesar de que "pensó" que llamógetAgealdaveobjeto.¿Cuál es el punto de todo lo anterior? Las funciones se adjuntan "libremente" a sus objetos JavaScript. Por ejemplo, puedes hacer
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 100Demos el siguiente paso.
var dave = new Person(new Date(1909, 1, 1)); var ageMethod = dave.getAge; dave.getAge(); //returns 100; ageMethod(); //returns ?????ageMethod¡la ejecución arroja un error! ¿Que pasó?Si usted lee mis puntos por encima con cuidado, que le cuenta que
dave.getAgeel método fue llamado condavecomothisobjeto mientras que JavaScript no pudo determinar el 'alcance' deageMethodejecución. Así que pasó la 'Ventana' global como 'esto'. Ahorawindowque no tiene unabirthDatepropiedad, laageMethodejecución fallará.¿Cómo arreglar esto? Sencillo,
ageMethod.apply(dave); //returns 100.¿Todo lo anterior tenía sentido? Si es así, entonces podrá explicar por qué no puede usar un alias
document.getElementById:var $ = document.getElementById; $('someElement');$se llama conwindowtanthisy sigetElementByIdla aplicación está a la esperathisde serdocument, se producirá un error.Nuevamente para solucionar esto, puede hacer
$.apply(document, ['someElement']);Entonces, ¿por qué funciona en Internet Explorer?
No sé la implementación interna de
getElementByIden IE, pero un comentario en la fuente de jQuery (inArrayimplementación del método) dice que en el IE,window == document. Si ese es el caso, entonces el aliasingdocument.getElementByIddebería funcionar en IE.Para ilustrar esto aún más, he creado un ejemplo elaborado. Eche un vistazo a la
Personfunción a continuación.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(); }; }Para la
Personfunción anterior, así es comogetAgese comportarán los distintos métodos.Creemos dos objetos usando la
Personfunción.var yogi = new Person(new Date(1909, 1,1)); //Age is 100 var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200console.log(yogi.getAge()); //Output: 100.Directo, el método getAge obtiene el
yogiobjeto comothisy la salida100.var ageAlias = yogi.getAge; console.log(ageAlias()); //Output: -1El intérprete de JavaScript establece el
windowobjeto comothisy nuestrogetAgemétodo regresará-1.console.log(ageAlias.apply(yogi)); //Output: 100Si configuramos el alcance correcto, puede usar el
ageAliasmétodo.console.log(ageAlias.apply(anotherYogi)); //Output: 200Si pasamos algún objeto de otra persona, aún calculará la edad correctamente.
var ageSmarterAlias = yogi.getAgeSmarter; console.log(ageSmarterAlias()); //Output: 100La
ageSmarterfunción capturó elthisobjeto original, por lo que ahora no tiene que preocuparse por suministrar el alcance correcto.console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!El problema
ageSmarteres que nunca se puede establecer el alcance en otro objeto.var ageSmartestAlias = yogi.getAgeSmartest; console.log(ageSmartestAlias()); //Output: 100 console.log(ageSmartestAlias.apply(document)); //Output: 100La
ageSmartestfunción utilizará el alcance original si se proporciona un alcance no válido.console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200Aún podrá pasar otro
Personobjeto agetAgeSmartest. :)fuente
Esta es una respuesta corta.
Lo siguiente hace una copia de (una referencia a) la función. El problema es que ahora la función está en el
windowobjeto cuando fue diseñado para vivir en eldocumentobjeto.window.myAlias = document.getElementByIdLas alternativas son
o puede utilizar dos alias.
window.d = document // A renamed reference to the object window.d.myAlias = window.d.getElementByIdfuente
Otra respuesta corta, solo para envoltura / aliasing
console.logy métodos de registro similares. Todos esperan estar en elconsolecontexto.Esto se puede utilizar cuando se envuelve
console.logcon algunas alternativas, en caso de que usted o sus usuarios tengan problemas al usar un navegador que (siempre) no lo admite . Sin embargo, esta no es una solución completa para ese problema, ya que necesita una revisión ampliada y una alternativa; su kilometraje puede variar.Ejemplo usando advertencias
var warn = function(){ console.warn.apply(console, arguments); }Entonces úsalo como de costumbre
warn("I need to debug a number and an object", 9999, { "user" : "Joel" });Si prefiere ver sus argumentos de registro envueltos en una matriz (yo lo hago, la mayoría de las veces), sustitúyalos
.apply(...)por.call(...).En caso de trabajar con
console.log(),console.debug(),console.info(),console.warn(),console.error(). Consulte tambiénconsoleMDN .consola chinche
fuente
Además de otras excelentes respuestas, existe un método simple de jQuery $ .proxy .
Puedes usar un alias como este:
myAlias = $.proxy(document, 'getElementById');O
myAlias = $.proxy(document.getElementById, document);fuente
$.proxytambién es realmente un envoltorio.En realidad , no puede "crear un alias puro" de una función en un objeto predefinido. Por lo tanto, lo más cercano al alias que puede obtener sin ajustar es permanecer dentro del mismo objeto:
>>> document.s = document.getElementById; >>> document.s('myid'); <div id="myid">fuente