w3schools tipos que llamar insertar funciones funcion desde codigo archivo javascript function closures alias

tipos - llamar javascript desde html



El alias de la función de JavaScript no parece funcionar (6)

Estaba leyendo esta pregunta y quería probar el método de alias en lugar del método de función-envoltura, pero parecía que no podía hacerlo funcionar en Firefox 3 o 3.5beta4, o Google Chrome, tanto en sus ventanas de depuración y 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, recibo la misma "invocación ilegal".

¿Estoy haciendo algo mal? ¿Alguien más puede reproducir esto?

Además, curiosamente, lo intenté y funciona en IE8.


Además de otras excelentes respuestas, hay un método jQuery simple $.proxy .

Puedes alias así:

myAlias = $.proxy(document, ''getElementById'');

O

myAlias = $.proxy(document.getElementById, document);


Debe 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 invoca en el objeto global, no en el objeto del documento. Use una técnica llamada cierres para arreglar esto:

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 método de vinculación 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();">


En realidad , no puede "alias puro" una función en un objeto predefinido. Por lo tanto, lo más parecido al aliasing que puede obtener sin envolverse es permanecer dentro del mismo objeto:

>>> document.s = document.getElementById; >>> document.s(''myid''); <div id="myid">


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 objeto window cuando fue diseñado para vivir en el objeto del document .

window.myAlias = document.getElementById

Las alternativas son

  • usar una envoltura (ya mencionado por Fabien Ménager)
  • o puede usar dos alias.

    window.d = document // A renamed reference to the object window.d.myAlias = window.d.getElementById


Otra respuesta corta, solo para envolver / aliasing console.log y métodos de registro similares. Todos esperan estar en el contexto de la console .

Esto se puede usar al envolver console.log con algunos errores, en caso de que usted o sus usuarios tengan problemas al usar un navegador que no (siempre) lo admite . Sin embargo, esta no es una solución completa para ese problema, ya que es necesario ampliar los controles y una alternativa: su kilometraje puede variar.

Ejemplo de uso de 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 (lo hago, la mayoría de las veces), sustituya .apply(...) con .call(...) .

Debería funcionar con console.log() , console.debug() , console.info() , console.warn() , console.error() . Ver también console en MDN .

console firebug


Profundicé para entender este comportamiento particular y creo que encontré una buena explicación.

Antes de acceder a por qué no puede alias document.getElementById , intentaré explicar cómo funcionan los objetos / funciones de JavaScript.

Siempre que invoque una función de JavaScript, el intérprete de JavaScript determina un alcance y lo pasa a la función.

Considera seguir la 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 se invoca, el valor de this dentro de la función suma será el objeto de Window global.

Para la función ''suma'', no importa cuál sea el valor de ''esto'' ya que no lo está usando.

Considera seguir la 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 llamas a la función dave.getAge, el intérprete de JavaScript ve que estás llamando a la función getAge en el objeto dave , por lo que establece this para getAge función getAge . getAge() devolverá 100 correctamente.

Puede saber que en JavaScript puede especificar el alcance utilizando el método apply . 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 el objeto bob . getAge ahora devolverá 200 aunque haya pensado que ha llamado getAge al objeto dave .

¿Cuál es el punto de todo lo anterior? Las funciones están "sueltas" unidas a sus objetos de 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 100

Tomemos el siguiente paso.

var dave = new Person(new Date(1909, 1, 1)); var ageMethod = dave.getAge; dave.getAge(); //returns 100; ageMethod(); //returns ?????

ageMethod ejecución de ageMethod arroja un error! ¿Que pasó?

Si lee cuidadosamente los puntos anteriores, dave.getAge que el método dave.getAge se dave.getAge con dave como this objeto, mientras que JavaScript no pudo determinar el ''alcance'' para la ejecución de ageMethod . Pasó la ''Ventana'' global como ''esto''. Ahora, como window no tiene una propiedad ageMethod , la ejecución de ageMethod fallará.

¿Cómo arreglar esto? Sencillo,

ageMethod.apply(dave); //returns 100.

¿Todo lo anterior tiene sentido? Si lo hace, podrá explicar por qué no puede alias document.getElementById :

var $ = document.getElementById; $(''someElement'');

$ se llama con una window como this y si la implementación getElementById espera que this sea ​​un document , fallará.

Nuevamente para arreglar esto, puedes hacer

$.apply(document, [''someElement'']);

Entonces, ¿por qué funciona en Internet Explorer?

No conozco la implementación interna de getElementById en IE, pero un comentario en jQuery source (en la implementación del método inArray ) dice que en IE, window == document . Si ese es el caso, entonces aliasing document.getElementById debería funcionar en IE.

Para ilustrar esto más a fondo, he creado un ejemplo elaborado. Echa un vistazo a la función Person 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 función Person anterior, así es como se comportarán los diversos métodos getAge .

Vamos a crear dos objetos usando la función 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.

En línea recta, el método getAge obtiene el objeto yogi como this y emite 100 .

var ageAlias = yogi.getAge; console.log(ageAlias()); //Output: -1

JavaScript interepreter establece el objeto window como this y nuestro método getAge devolverá -1 .

console.log(ageAlias.apply(yogi)); //Output: 100

Si establecemos el alcance correcto, puede usar el método ageAlias .

console.log(ageAlias.apply(anotherYogi)); //Output: 200

Si pasamos en algún otro objeto de persona, todavía calculará la edad correctamente.

var ageSmarterAlias = yogi.getAgeSmarter; console.log(ageSmarterAlias()); //Output: 100

La función ageSmarter capturó el original de this objeto, por lo que ahora no tiene que preocuparse por el alcance correcto.

console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!

El problema con ageSmarter es que nunca puedes establecer el alcance para algún otro objeto.

var ageSmartestAlias = yogi.getAgeSmartest; console.log(ageSmartestAlias()); //Output: 100 console.log(ageSmartestAlias.apply(document)); //Output: 100

La función ageSmartest utilizará el alcance original si se proporciona un alcance no válido.

console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200

Aún podrá pasar otro objeto Person para getAgeSmartest . :)