tag - Javascript: ¿Necesito poner this.var para cada variable en un objeto?
title of page html (6)
En javascript, this
siempre se refiere al objeto propietario de la función. Por ejemplo, si defines tu función foo()
en una página, entonces owner es la windows
objeto javascript; o si define foo()
en el elemento html <body>
, entonces el propietario es el cuerpo del elemento html; y del mismo modo si defines la función onclick del elemento <a>
, entonces el propietario es el ancla.
En su caso, está asignando una bar
propiedades al objeto ''propietario'' al principio y tratando de devolver la bar
variables local.
Como nunca definió ninguna bar
varialbe local, le está dando como la barra no está definida.
Idealmente, su código debería haber definido la variable como var bar;
si quieres devolver el valor cero.
En C ++, el lenguaje con el que me siento más cómodo, generalmente uno declara un objeto como este:
class foo
{
public:
int bar;
int getBar() { return bar; }
}
Llamar a getBar()
funciona bien (ignorando el hecho de que la bar
puede estar desinicializada). La bar
variables dentro de getBar()
está dentro del alcance de la clase foo
, así que no necesito decir this->bar
menos que realmente necesite dejar en claro que me estoy refiriendo a la bar
la clase en lugar de, por ejemplo, un parámetro.
Ahora, estoy tratando de comenzar con OOP en Javascript. Entonces, busco cómo definir clases y probar el mismo tipo de cosas:
function foo()
{
this.bar = 0;
this.getBar = function() { return bar; }
}
Y me da bar is undefined
. Cambiar la bar
a this.bar
corrige el problema, pero hacer eso para cada variable complica mi código bastante. ¿Es esto necesario para cada variable? Como no puedo encontrar ninguna pregunta relacionada con esto, me hace sentir que estoy haciendo algo fundamentalmente incorrecto.
EDITAR: Correcto, entonces, de los comentarios lo que this.bar
es que this.bar
, una propiedad de un objeto, hace referencia a algo diferente a bar
, una variable local. ¿Puede alguien decir por qué exactamente es esto, en términos de alcance y objetos, y si hay otra forma de definir un objeto donde esto no sea necesario?
JavaScript no tiene clases de modelo de objetos basado en clases . Utiliza la herencia prototípica más poderosa, que puede imitar a las clases, pero no es adecuada para eso. Todo es un objeto y los objetos [pueden] heredar de otros objetos.
Un constructor es solo una función que asigna propiedades a los objetos recién creados. El objeto (creado por una llamada con la new
palabra clave ) se puede referenciar a través de la palabra clave this
(que es local para la función).
Un método también es simplemente una función que se llama a un objeto, de nuevo con this
apuntando al objeto. Al menos cuando esa función se invoca como una propiedad del objeto, utilizando un operador miembro (punto, corchetes). Esto causa mucha confusión a los novatos, porque si pasas por esa función (por ejemplo, a un oyente de eventos) se "separa" del objeto al que se accedió.
Ahora, ¿dónde está la herencia? Las instancias de una "clase" heredan del mismo objeto prototipo. Los métodos se definen como propiedades de función en ese objeto (en lugar de una función para cada instancia), la instancia en la que los llama simplemente hereda esa propiedad.
Ejemplo:
function Foo() {
this.bar = "foo"; // creating a property on the instance
}
Foo.prototype.foo = 0; // of course you also can define other values to inherit
Foo.prototype.getBar = function() {
// quite useless
return this.bar;
}
var foo = new Foo; // creates an object which inherits from Foo.prototype,
// applies the Foo constructor on it and assigns it to the var
foo.getBar(); // "foo" - the inherited function is applied on the object and
// returns its "bar" property
foo.bar; // "foo" - we could have done this easier.
foo[foo.bar]; // 0 - access the "foo" property, which is inherited
foo.foo = 1; // and now overwrite it by creating an own property of foo
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that
(new Foo).foo; // is still 0
Entonces, solo usamos propiedades de ese objeto y estamos contentos con eso. ¡Pero todos ellos son "públicos", y pueden sobrescribirse / cambiarse / eliminarse! Si eso no te importa, tienes suerte. Puede indicar "privacidad" de las propiedades al ponerle un prefijo a sus nombres con guiones bajos, pero eso es solo una pista para otros desarrolladores y puede que no se obedezca (especialmente por error).
Por lo tanto, las mentes inteligentes han encontrado una solución que utiliza la función de constructor como cierre, lo que permite la creación de "atributos" privados. Cada ejecución de una función de javascript crea un nuevo entorno variable para las variables locales, que puede obtener basura recolectada una vez que la ejecución ha finalizado. Cada función que se declara dentro de ese ámbito también tiene acceso a estas variables, y mientras esas funciones puedan ser llamadas (por ejemplo, por un detector de eventos), el entorno debe persistir. Por lo tanto, al exportar funciones definidas localmente desde su constructor, conserva ese entorno variable con variables locales a las que solo pueden acceder estas funciones.
Veámoslo en acción:
function Foo() {
var bar = "foo"; // a local variable
this.getBar = function getter() {
return bar; // accesses the local variable
}; // the assignment to a property makes it available to outside
}
var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor
Esta función getter, que se define dentro del constructor, ahora se llama un "método privilegiado " ya que tiene acceso a los "atributos" (variables) "privados" (locales). El valor de la bar
nunca cambiará. También podría declarar una función de establecimiento, por supuesto, y con eso podría agregar alguna validación, etc.
Tenga en cuenta que los métodos del objeto prototipo no tienen acceso a las variables locales del constructor, aunque pueden usar los métodos privilegiados. Agreguemos uno:
Foo.prototype.getFooBar = function() {
return this.getBar() + "bar"; // access the "getBar" function on "this" instance
}
// the inheritance is dynamic, so we can use it on our existing foo object
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix
Entonces, puedes combinar ambos enfoques. Tenga en cuenta que los métodos privilegiados necesitan más memoria, ya que crea distintos objetos de función con diferentes cadenas de alcance (pero el mismo código). Si vas a crear cantidades increíblemente grandes de instancias, debes definir los métodos solo en el prototipo.
Se vuelve incluso un poco más complicado cuando configura la herencia de una "clase" a otra. Básicamente, debe hacer que el objeto prototipo hijo herede del padre y aplicar el constructor padre a las instancias hijo para crear los "atributos privados". ". Eche un vistazo a Corregir herencia de JavaScript , Variables privadas en prototipos heredados , Definir miembros de campo privado y Herencia en el patrón de módulo JAVASCRIPT y Cómo implementar herencia en JS Revelar patrón de prototipo?
Para acercarse a OOP en JavaScript, es posible que desee echar un vistazo a un patrón de diseño del Módulo (por ejemplo, se describe here ).
Basado en el efecto de cierre, este patrón permite emular propiedades privadas en sus objetos.
Con las propiedades ''privadas'' puede hacer referencia a ellas directamente por su identificador (es decir, no this
palabra clave como en constructores).
Pero de todos modos, cierres y patrones de diseño en JS: un tema avanzado. Entonces, familiarícese con lo básico (también explicado en el libro mencionado anteriormente).
this.foo
explícitamente significa (como has entendido bien) que estás interesado en la propiedad foo
del objeto actual al que hace referencia. Entonces, si usa: this.foo = ''bar'';
va a establecer la propiedad foo
del objeto actual al que hace referencia this
igual a bar
.
La palabra clave this
en JavaScript no siempre significa lo mismo que en C ++. Aquí puedo darte un ejemplo:
function Person(name) {
this.name = name;
console.log(this); //Developer {language: "js", name: "foo"} if called by Developer
}
function Developer(name, language) {
this.language = language;
Person.call(this, name);
}
var dev = new Developer(''foo'', ''js'');
En el ejemplo anterior llamamos a la función Person
con el contexto de la función Developer
por this
hace referencia al objeto que creará el Developer
. Como puede ver en el resultado de console.log
this
viene del Developer
. Con el primer argumento de la call
al método especificamos el contexto con el que se llamará a la función.
Si no usa this
simplemente la propiedad que ha creado será una variable local. Como es posible que sepa, JavaScript tiene un ámbito funcional, por lo que la variable será local, visible solo para la función en la que está declarada (y, por supuesto, todas las funciones secundarias que se declaran dentro del elemento principal). Aquí hay un ejemplo:
function foo() {
var bar = ''foobar'';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(f.getBar()); //''foobar''
Esto es cierto cuando usa la palabra clave var
. Esto significa que estás definiendo bar
como variable local si olvidas var
bar
desafortunadamente se volverá global.
function foo() {
bar = ''foobar'';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(window.bar); //''foobar''
Exactamente el alcance local puede ayudarlo a lograr la privacidad y la encapsulación, que son uno de los mayores beneficios de OOP.
Ejemplo del mundo real:
function ShoppingCart() {
var items = [];
this.getPrice = function () {
var total = 0;
for (var i = 0; i < items.length; i += 1) {
total += items[i].price;
}
return total;
}
this.addItem = function (item) {
items.push(item);
}
this.checkOut = function () {
var serializedItems = JSON.strigify(items);
//send request to the server...
}
}
var cart = new ShoppingCart();
cart.addItem({ price: 10, type: ''T-shirt'' });
cart.addItem({ price: 20, type: ''Pants'' });
console.log(cart.getPrice()); //30
Un ejemplo más de los beneficios del alcance de JavaScript es el Patrón del Módulo . En Module Pattern puede simular privacidad utilizando el alcance funcional local de JavaScript. Con este enfoque, puede tener propiedades y métodos privados. Aquí hay un ejemplo:
var module = (function {
var privateProperty = 42;
function privateMethod() {
console.log(''I/'m private'');
}
return {
publicMethod: function () {
console.log(''I/'m public!'');
console.log(''I/'ll call a private method!'');
privateMethod();
},
publicProperty: 1.68,
getPrivateProperty: function () {
return privateProperty;
},
usePublicProperty: function () {
console.log(''I/'ll get a public property...'' + this.publicProperty);
}
}
}());
module.privateMethod(); //TypeError
module.publicProperty(); //1.68
module.usePublicProperty(); //I''ll get a public property...1.68
module.getPrivateProperty(); //42
module.publicMethod();
/*
* I''m public!
* I''ll call a private method!
* I''m private
*/
Hay una pequeña sintaxis extraña en la que los padres envuelven las funciones anónimas, pero olvídenla por el momento (solo está ejecutando la función después de que se haya inicializado). La funcionalidad se puede ver desde el ejemplo de uso, pero los beneficios se conectan principalmente para proporcionar una interfaz pública simple que no lo involucra con todos los detalles de implementación. Para una explicación más detallada del patrón, puede ver el enlace que puse arriba.
Espero que con this
información :-) te haya ayudado a comprender algunos temas básicos de JavaScript.
esto es como un modificador de acceso público de objetos (variables o funciones), mientras que var es el modificador de acceso privado
Ejemplo
var x = {};
x.hello = function(){
var k = ''Hello World'';
this.m = ''Hello JavaScript'';
}
var t = new x.hello();
console.log(t.k); //undefined
console.log(t.m); //Hello JavaScript
function Foo() {
this.bar = 0;
this.getBar = function () { return this.bar };
}
Cuando llama a la función anterior con la new
palabra clave, como esta ...
var foo = new Foo();
... - suceden algunas cosas:
1) se crea un objeto
2) la función se ejecuta con la palabra clave this
haciendo referencia a ese objeto.
3) ese objeto es devuelto
foo
, entonces, se convierte en este objeto:
{
bar: 0,
getBar: function () { return this.bar; }
};
Por qué no, entonces, solo haz esto:
var foo = {
bar: 0,
getBar: function () { return this.bar; }
};
Lo harías, si es solo un objeto simple.
Pero crear un objeto con un constructor (así se llama) nos da una gran ventaja al crear varios de los "mismos" objetos.
Ver, en javascript, todas las funciones se crean con una propiedad prototipo [un objeto], y todos los objetos creados con esa función (llamándola con la nueva palabra clave) están vinculados a ese objeto prototipo. Es por eso que es genial: puede almacenar todos los métodos comunes (y propiedades, si así lo desea) en el objeto prototipo, y guardar mucha memoria. Así es como funciona:
function Foo( bar, bob ) {
this.bar = bar;
this.bob = bob;
}
Foo.prototype.calculate = function () {
// ''this'' points not to the ''prototype'' object
// as you could''ve expect, but to the objects
// created by calling Foo with the new keyword.
// This is what makes it work.
return this.bar - this.bob;
};
var foo1 = new Foo(9, 5);
var foo2 = new Foo(13, 3);
var result1 = foo1.calculate();
var result2 = foo2.calculate();
console.log(result1); //logs 4
console.log(result2); //logs 10
¡Eso es!