2010-10-21 18 views
7

Pido disculpas de antemano si esta pregunta es demasiado amplia. De hecho, se trata de 4 preguntas diferentes, pero todas relacionadas con el mismo fragmento de código, y creo que todas giran en torno al mismo principio.Javascript: ¿Qué hace este código?

Decidí hoy, después de usar JS durante años, comenzar a aprender realmente cómo funciona JS en lugar de tratarlo como C que se ejecuta en el navegador. Así que comencé a profundizar en el código jQuery para ver cómo los desarrolladores reales de JS usan el lenguaje. Fue entonces cuando encontré un bloque de código que se parece al código a continuación. Tenga en cuenta que tomé este código de otra publicación apilada aquí In Javascript, can you extend the DOM?. Así que eso no significa que la persona que escribió este código ni siquiera sabía de lo que estaba hablando.

var myDOM = (function(){ // #1 
    var myDOM = function(elems){ // #2 
      return new MyDOMConstruct(elems); 
     }, 
     MyDOMConstruct = function(elems) { 
      this.collection = elems[1] ? Array.prototype.slice.call(elems) : [elems]; 
      return this; // #3 
     }; 
    myDOM.fn = MyDOMConstruct.prototype = { 
     forEach : function(fn) { 
      var elems = this.collection; 
      for (var i = 0, l = elems.length; i < l; i++) { 
       fn(elems[i], i); 
      } 
      return this; 
     }, 
     addStyles : function(styles) { 
      var elems = this.collection; 
      for (var i = 0, l = elems.length; i < l; i++) { 
       for (var prop in styles) { 
        elems[i].style[prop] = styles[prop]; 
       } 
      } 
      return this; 
     } 
    }; 
    return myDOM; // #4 
})(); 

1 ¿Por qué declarar la función utilizando var myDOM = (function() {})(); en lugar de var myDOM = function() {};

2 ¿Por qué declarar otra función dentro de la función myDOM con el mismo nombre? ¿Por qué no poner toda la lógica interna del myDOM dentro de la función myDOM externa?

3 ¿Por qué se devuelve explícitamente "this"? Eso habría sido hecho automáticamente, ¿correcto?

4 ¿Qué está pasando aquí? ¿Devuelve el constructor interno de myDOM? Si es así, ¿por qué?

actualización

Así que la mayoría de esto tiene sentido ahora. Con respecto al # 1, pensé que a myDOM se le estaba asignando la función definida después del =, pero no es así. Se le asigna lo que sea que devuelva esa función. Lo cual resulta ser una función.

Todavía no tengo claro el n. ° 3. Sí, entiendo que al usar la función de esta manera

console.log(MyDomConstruct('foo')) 

Aparecerá 'indefinido'. Pero no es así como se usa. A pocas líneas arriba es este

return new MyDomConstruct(elems); 

me puede entender explícitamente devolver "este" si la declaración fue como esto

return MyDomConstruct(elems); 

Pero ese no es el caso.

+0

En realidad 'new MyDomConstruct (elems)' no devuelve 'this' sino una nueva instancia de' MyDomConstruct'. Tal vez en un contexto diferente esto sea más fácil de entender. – nre

+0

Derecha. Pero "this" y una nueva instancia de MyDomConstruct son instancias de MyDomConstruct, ¿no? Además, ¿por qué utilizar la declaración "nueva" si la función va a devolver una instancia de sí mismo? – mellowsoon

+0

Todas buenas respuestas. Le estoy dando la respuesta a jAndy porque él respondió primero, pero +1 para todos los demás. – mellowsoon

Respuesta

9

¿Por qué declarar la función utilizando var myDOM = (function() {})(); en lugar de var myDOM = function() {};

Esa es una llamada self-invoking anonymous function o . Hace exactamente eso, se llama a sí mismo en tiempo de ejecución. También verá el patrón:

(function($){ 
}(jQuery)); 

bastante alot en el mundo jQuery. Es lo mismo, en el tiempo de ejecución, la función se llama a sí misma y garantiza que el signo $ tenga una referencia al objeto jQuery dentro del cuerpo de la función.

En su fragmento, la función se invoca a sí misma y devuelve myDOM, una referencia de funciones.

¿Por qué declarar otra función dentro de la función myDOM con el mismo nombre? ¿Por qué no poner toda la lógica interna del myDOM dentro de la función myDOM externa?

Eso es solo una convención. Se podría llamar lo que quieras que sea, tal vez el autor pensó que es conveniente hacer esto. El motivo de este patrón es la seguridad &. Al devolver la referencia interna myDOM se crea una referencia closure. Por lo que el después de declarar algo así como

var mytest = myDOM([]); 

que no tendrá acceso a MyDOMConstruct, pero su función interna tiene acceso. De esa forma puedes proteger tus métodos y variables. También se llama method pattern. Siempre es una buena lectura en este contexto Douglas Crockford: Javascript the good parts.

¿Por qué se devuelve explícitamente "this"? Eso habría sido hecho automáticamente, ¿correcto?

No, una función devolverá el valor undefined de forma predeterminada.Por explícitamente volver this puede chain métodos similares (de la llamada de ejemplo anterior):

mytest.forEach([]).addStyles([]); ... 

ya que cada método se vuelve el objeto de la invocación, en este caso myDOM.

¿Qué está pasando aquí? ¿Devuelve el constructor interno de myDOM? Si es así, ¿por qué?

Espero que esto quede claro en este punto.

Editar

Basado en su actualización

new MyDOMConstruct(); 

produce un nuevo objeto que inherits de

MyDOMConstruct.prototype 

Sin la new keyword la this no estaría obligado al nuevo objeto . En cambio, estaría vinculado al objeto global (ventana) y accedería a las variables globales usando this.

+0

Gracias jAndy. Actualicé mi publicación para obtener un poco más de información sobre el # 3. – mellowsoon

+0

@mellowsoon: actualizado – jAndy

6

1. ¿Por qué declarar la función usando var myDOM = (function() {})(); en lugar de var myDOM = function() {};

La forma utilizada es una función de la ejecución de uno mismo. Esto significa que myDOM está configurado para lo que devuelva la función. La segunda forma establece myDOM para la función pero no ejecuta la función de inmediato.

var myDOM = (function() {   // <== This is a function that does something 
       // Something 
      })();     // The function is executed right HERE with(). 


2. ¿Por qué declarar otra función dentro de la función myDOM con exactamente el mismo nombre? ¿Por qué no poner toda la lógica interna del myDOM dentro de la función myDOM externa?

Porque está devolviendo la función myDOM interior al final ... por lo que la denominación en realidad tiene sentido a pesar de que al principio es confusa.Esto se usa a menudo para crear variables privadas en JS. Dado que la función interna tendrá acceso al alcance que está encerrado (la función anónima autoejecutable) pero el usuario no lo hará.

var myDOM = (function() { // <== This is a function that is going to return 
          // a function/object 
       var myDOM = function() { // <== We're going to return this 
        ...     //  The outer myDom will be set to it 
       };      //  So it's actually helpful to name 
             //  it the same for clarity. 
       return myDOM; 
      })(); 

// Now we can access that inner object by using the outer myDOM. 
// We could access the inner object using myDOM even if the inner object 
// was named otherTHING... It's confusing to acces something 
// called otherTHING in the code by 
// writing myDOM().... so better name the inner returned function 
// myDOM as well. 

De modo que el objeto interno podría tener cualquier nombre, y que podrían ser ejecutados con myDOM(), pero si el nombre de la función interna blah sin embargo, todavía se puede ejecutar mediante el uso de myDOM() ... eso no es muy clara .. mucho mejor nombrarlo igual.

3. ¿Por qué devolver explícitamente "esto"? Eso habría sido hecho automáticamente, ¿correcto?

No, si no escribe nada, Javascript devuelve automáticamente undefined. El MDC reference:.

De vuelta this se usa a menudo para preservar el contexto de un método. Solía ​​hacer posible el encadenamiento de métodos ($(here).is().a().chain().of().methods()). Para que un método de la cadena conozca el contexto en el que está operando.

+0

Gracias por la respuesta. Con respecto al n. ° 2, supongo que este es el motivo por el que mostrar un objeto jquery, es decir, console.log ($ (document)), muestra "jQuery()" en lugar de "jQuery.init()", que es el objeto jQuery en realidad (Hasta donde yo sé). Es porque jQuery.init se está asignando a la variable llamada jQuery. Extraño. – mellowsoon

3

Solo una nota más a la función anónima autoejecutable . Envolver algunos fragmentos de JavaScript en un bloque (function() { })(); es una forma de crear un espacio de nombres privado. Todo lo que haga dentro de la función interna será función privada excepto por el valor devuelto (en este caso myDOM).

Es decir que puede hacer cosas como Savely

var counter = (function() { 
    var i = 0; 
    var counter = function() { 
     alert(i++); 
     return i; 
    } 
    return counter; 
})(); 

counter(); // will alert 0 
counter(); // will alert 1 
// ... and so on 

mantener algún secreto de estado interno de fuera de la función. La segunda razón, como ya se indicó en otras publicaciones, es que no contaminará el espacio de nombres global con la variable i. Ese es el caso por el que es una buena práctica usar este tipo de funciones en el desarrollo de plugins jQuery.

+0

Aunque en principio sé lo que era una función anónima autoejecutable, por alguna razón nunca se me pasó por la mente usarla como una forma o proporcionar variables privadas a las funciones. No son exactamente propiedades privadas, pero logra lo mismo. – mellowsoon

1

mismo que éste:


(function() { 
    function b(a) { 
     return new c(a) 
    } 
    function c(a) { 
     this.a = a[1] ? Array.prototype.slice.call(a) : [a]; 
     return this 
    } 
    b.b = c.prototype = {}; 
    return b 
})(); 

esperanza que ayuda ... :)

1

por ejemplo: var fn = (function() { función de retorno() {alert (11) }; })(); cuando se ejecuta el código, ahora fn = function() {alert (11)}; pruébalo!