2012-06-06 24 views
21

¿Cuál es el mejor patrón de diseño para el logro de los siguientes (que no funciona)?Javascript: Llamar a métodos de objeto dentro de ese objeto

var obj = (function() { 

    // code defining private variables and methods 

    var _obj = { 
    property: value, 
    method1: function() { 
     // do stuff 
    }, 
    method2: function() { 
     // use property 
     var prop = _obj.property; // obviously doesn't work 
     // call method1 
     obj.method1(); // "obj" not finished being defined yet! 
    } 
    }; 

    // obviously now I could do... 
    var prop = _obj.property; 

    return _obj; 

})(); 

// and I could now do... 
obj.method1(); 

Una variación que creo que debería funcionar es

var obj = (function() { 

    var property = value, 
     method1 = function() { 
     // do stuff 
     }, 
     method2 = function() { 
     // use property 
     var prop = property; 
     // call method1 
     method1(); 
     }, 
     _obj = { 
     property: property, 
     method1: method1, 
     method2: method2 
     }; 

    return _obj; 

})(); 

Del mismo modo, ¿cómo funciona para objetos destinados a ser creado con el operador new? Dentro de la propia función de constructor puedes escribir . Pero, ¿y si quieres mantener pequeño al constructor, solo definir aquellas cosas que probablemente se personalizarán en la creación, y luego definir el resto en el prototipo? (Este parece ser el patrón común.) ¿Pueden las propiedades/métodos dentro del prototipo interactuar de alguna manera?

var MyObj = function(name) { 
    this.name = name; 
}; 

var obj = new MyObj('Bob'); 

MyObj.prototype = { 
    called_often: function() { 
    // lots more code than just the following 
    return document.getElementById('someID').value; 
    }, 

    global_default: 'value', // can be changed, so need to pull value when run 

    does_stuff: function(value) { 
    var str = global_default + value, // can't access global_default on its own 
     input = MyObj.called_often(), // doesn't work; MyObj.prototype.called_often() DOES 
     name = this.name; // 'this' used in the prototype doesn't work 
          // even within a created object 
    return name + input + str; 
    } 
}; 

Estoy seguro de que hay mejores formas de lograr mi resultado siempre que me encuentre con este problema. Este código no es específico de la situación y simplemente ilustra el problema general. Entonces no podrás darme una alternativa para esas situaciones específicas con las que me encuentro. Pero tal vez puedas ayudar mi pensamiento general.

Respuesta

26

Pues bien, desde el primer ejemplo:

var _obj = { 
    property: value, 
    method1: function() { 
     // do stuff 
    }, 
    method2: function() { 
     // use property 
     var prop = this.property; 
     // call method1 
     this.method1(); 
    } 
    }; 

Eso es lo que el valor es para this.

Ahora, lo que no puede hacer es referirse a una propiedad de un objeto "en construcción" de la sintaxis literal de objeto en otro lugar. (Es difícil dar un ejemplo porque simplemente no es sintácticamente posible.) En los casos en los que desea hacer eso, necesita una o más declaraciones de asignación por separado.

+0

había pensado que 'esto' sólo apunta al objeto si se ha creado con la nueva + constructor, o si se utiliza la llamada/aplican. Pero tienes razón, ¡funciona! Aparentemente he estado confundido todo este tiempo. Además, pensé que había intentado eso. Pero aparentemente no. –

+0

JavaScript es increíblemente simple y sorprendentemente complicado al mismo tiempo :-) Resulta que 'this' está vinculado en el momento en que se llama a una función, y eso es todo; sin embargo, esa regla simple conduce a todo tipo de detalles interesantes. – Pointy

+0

Hola, puntiagudo. Tengo el mismo tipo de problema. Estoy usando 'roundslider.js' y estoy llamando a una función donde has escrito hacer cosas. Pero es un error para mí. '$ (" # slider "). RoundSlider ({ cambio: función (evento) { traceEvent() },' }); – locateganesh

9

¿Adivina qué? Estás haciendo que las cosas simples sean complejas. La respuesta de Pointy es buena, pero el prototipo es mejor por varias razones. Es por eso que estoy describiendo (más bien, haciendo correcciones) el último método. Check this fiddle.

var MyObj = function(name) { 
    this.name = name; 
}; 

MyObj.prototype = { 
    called_often: function() { 
    // lots more code than just the following 
    return 'VALUE'; //document.getElementById('someID').value; 
    }, 

    global_default: 'value', // can be changed, so need to pull value when run 

    does_stuff: function(value) { 
    var str = this.global_default + value, // can't access global_default on its own 
     input = this.called_often(), // doesn't work; MyObj.prototype.called_often() DOES 
     name = this.name; // 'this' used in the prototype doesn't work 
          // even within a created object 
    return name + input + str; 
    } 
}; 

var obj = new MyObj('Bob'); 
+0

¡Gracias por tomarse el tiempo de poner eso en jsfiddle! Como comenté en la publicación anterior, al parecer estaba confundido acerca de la capacidad de usar 'esto' en estas situaciones. (Obviamente, como comenté en la versión del prototipo que "esto no funcionará".) Sé con certeza que traté de usar esto en un prototipo antes y obtuve un error. Ahora voy a tener que volver a visitar ese código y ver lo que estaba haciendo realmente mal, ¡porque obviamente no era el uso de 'esto'! –

+0

Esta es una gran respuesta. – Pointy

+1

@Pointy, gracias! ;) –

Cuestiones relacionadas