Porque se desaparecen bindings en XAML C#

Basicamente los binding’s desaparecen porque alguien los borra de alguna manera. Y como programadores normalmente no lo hacen, piensan que los binding’s de las propiedades siempre deben funcionar y siempre estan presentes, lo que no es verdad. Y hay un caso bastante facil de ver, pero complicado de entender que esta pasando.

Yo me encontre con la situación que despues de ver un CheckBox marcado gracias al binding, luego se queda marcado siempre y no me cambia el valor aún que se cambia el Context. Si el binding estaria funcionando, todo seria perfecto, pero no funcionaba. Al principio he pensado que problema esta con Mode=TwoWay/OneWay/etc, luego con posible problema de “UpdateTrigger” de la propiedad mostrada y en parte es correcto, pero el Binding en si, dejaba de existir asociado a propiedad “IsChecked”.

Para ver si existe binding podeis utilizar el codigo:

BindingExpression be = cbIsClient.GetBindingExpression(ToggleButton.IsCheckedProperty);

Si “be” es igual a “null”, no existe “binding” en esta propiedad.
Asi que si os deja de funcionar, en diferentes partes de codigo podeis ir detectando en que momento acaba desapareciendo. Gracias a esta investigación bastante manual vi un error mio que yo nunca consideraba que podria ser un error.

Imaginar el caso que tenemos un objeto “Coche” con una propiedad “Cliente”, la cual a su vez es un objeto. En pantalla con XAML dibujamos un CheckBox que tiene que estar marcado cuando “Coche.Cliente != null” y desmarcado cuando propiedad es nula. Se puede utilizar “Converter” personalizado para solventar este problema, pero necesitamos que salta el trigger si se cambia la propiedad “Coche.Cliente”. Si no lo podemos hacer de una forma facil por codigo, al no tener acceso a la propiedad “Cliente” (por ejemplo es de una libreria externa), yo pense que podria hacer simplemente:

cbIsClient.IsChecked = Coche.Cliente != null;

Y cuando pasa por esta parte de codigo se marca o se desmarca correctamente. El problema lo vi luego, al cambiar de un objeto “Coche” a otro de la lista. Vi que por si solo el CheckBox queda con el valor anterior si no fuerzo pasar por la linea de asignación directa y esto teniendo en CheckBox un binding con un converter.

Despues de investigar vi que el problema esta, en que al cargar primer “Coche” si que funcionaba el “binding” pero luego al pasar por “cbIsClient.IsChecked = Coche.Cliente != null;” lo que sucede, es que XAML piensa que apartir de ahora asignación sera manual y borra el binding. Asi luego si comprobamos con “GetBindingExpression” veremos que no hay ningun binding.

Sabiendo esto ya podeis encontrar solución, en mi caso al trabajar en codigo tube que crear algo asi:

coche.Cliente = new Client("123456789");
BindingExpression be = cbIsClient.GetBindingExpression(ToggleButton.IsCheckedProperty);
be?.UpdateTarget();

Mi problema era que no podria acceder a la propiedad y no me saltaba trigger, asi que sin asignar directamente al control, lo que hacia es forzar el disparo del binding del control despues de cambiar el valor por el codigo.

Propiedades generales y de permisos de Usuario en XAML del DataGrid (WPF C#)

Las propiedades mas habituales del DataGrid en XAML y las propiedades para limitar o habilitar acciones de usuario

Margin="10,10,10,10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CanUserSortColumns="True"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserResizeRows="False"

Script para cambiar idioma (cultura) en toda la aplicación en C# WPF

Script que se aplica en arranque de aplicación, para cambio de idioma

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            Options options = Options.Create();
            string alternativeAdminCoreServiceUri = options.AdminCoreServiceUri;
            // Parte particular: inicio
            Admin.Clients.Core.AdminClient adminEntityClient = new Admin.Clients.Core.AdminClient(options.AdminCoreServiceUri, 
                                                                    alternativeAdminCoreServiceUri);
            bool changedFromLocal;
            adminEntityClient.GetGlobalParameterValues("C:", out changedFromLocal);
            string cultureStr = adminEntityClient.AdminSet.GetGlobalParameterStr(Common.SharedEntities.Admin.GlobalParameterValueId.CultureName);
            // Parte particular: final
            System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo(cultureStr);
            System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            System.Threading.Thread.CurrentThread.CurrentUICulture = culture;

            WpfSingleInstance.Make(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, this);
            base.OnStartup(e);
        }
    }

Análisis de rendimiento en consultas MS Sql Server

Pequeño script para analizar rendimiento de consultas

SELECT [Metodo],Max([Tiempo]),SUM([Tiempo]), Count(*)
  FROM [MiDb].[dbo].[optimizacion]
  Group by [Metodo]
  Having Max([Tiempo]) > 0 and SUM([Tiempo]) > Max([Tiempo])
  order by Max([Tiempo]) desc;

SELECT [Metodo],Count(*)
  FROM [MiDb].[dbo].[optimizacion]
  group by [Metodo]
  having Count(*)>1
  order by Count(*) desc;

-- CacheData.IncidenciaGetAll Corregir cache
-- Especifico
SELECT * FROM [MiDb].[dbo].[optimizacion]
where [Metodo] = 'CacheData.IncidenciaGetAll';

Envió de correo electrónico con MailMessage en C#

Uno de los métodos para envió de correos electrónicos en C#. Codigo minimalista.

public static void CreateTestMessage2(string server)
{
	string to = "jane@contoso.com";
	string from = "ben@contoso.com";
	MailMessage message = new MailMessage(from, to);
	message.Subject = "Using the new SMTP client.";
	message.Body = @"Using this new feature, you can send an e-mail message from an application very easily.";
	SmtpClient client = new SmtpClient(server);
	// Credentials are necessary if the server requires the client 
	// to authenticate before it will send e-mail on the client's behalf.
	client.UseDefaultCredentials = true;

    try {
	  client.Send(message);
	}  
	catch (Exception ex) {
	  Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", 
                  ex.ToString() );			  
    }              
}

Mas detalle de excepciones sobre EntitySet en C#

Como podemos mejorar la depuración de aplicaciones? Con mas información en el Log que escribimos en algún sitio (Eventos, Base de datos, fichero planto txt, etc.)

Código para sacar mas información cuando se producen problemas con entidades (longitud incorrecta en base de datos de los nvarchar, tipo diferente, etc.)

            catch (DbEntityValidationException e)
            {
                message = string.Empty;
                foreach (var eve in e.EntityValidationErrors)
                {
                    message += string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    foreach (var ve in eve.ValidationErrors)
                    {
                        message += string.Format("- Property: \"{0}\", Error: \"{1}\"",
                            ve.PropertyName, ve.ErrorMessage);
                    }
                }
                message += ExceptionUtility.GetMessageFromException(e);
            }

Manipulación de elementos en JavaScript

Manipulación dinamica. BOM vs DOM en JavaScript

  • Objeto window representa una o varias ventanas abierta por navegador.
  • Podemos acceder al historico de navegación.
  • Internet Explorer aún soporta document.all, aún que indica en ultimas versiones que no lo hace.
  • opener: devuelve una referencia a la ventana desde la cuál se ha abierto.
  • pageXOffset y pageYOffset. Posiciones de desplazamiento para dejar un objeto siempre visible.
  • Por seguridad codigo JS tiene que coincidir dominio y puerto para funcionar.
  • postMessage para comunicación entre ventanas.
  • find: busca el texto indicado en el documento actual y destaca los fragmentos encontrados.
  • objeto history (length – número de entradas): back, forward, go.
  • objeto navigator (appVersion, userAgent, javaEnabled(), plugins, mimeTypes, platform, cookieEnabled).
  • screen (tamaños de pantalla, dpi’s, etc).
  • document.Open/Close y writeln para mostrar texto nuevo.
  • querySelectorAll devuelve coleccion estatica que es mas lento que colecion dinamica getElementBy*.
  • Mejor no usar += en innerHtml. Sino recargamos la pagina varias veces.
  • Modificación del DOM: createElement, createtextNode, cloneNode, appendChild, insertBefore, removeChild, replaceChild.
  • Añadir nuevo elemento: document.body.appendChild(nuevoDiv);

Programación Orientada a Objetos (POO) en JavaScript

Descripción de POO: como crear clases, herencias, polimorfismo, etc. en JavaScript

  • Clase es definicion como tiene que ser.
  • Objeto es una instancia de la clase con valores aplicados y particulares.
  • En JS no existen interfaces.

Los tres pilares básicos de la Programación Orientada a Objetos son:
A. Encapsulación.
B. Herencia.
C. Polimorfismo.

2.1. Redefiniendo objetos genericos:
Crear objeto:

var marcianito = new Object(); // Creamos objeto
marcianito1.name = “invasor del espacio #1”; // Se crea nueva propiedad y se asigna valor a ella
marcianito1.color = “Azul”;
marcianito1.x = 100;
marcianito1.y = 20;
marcianito1.disparos = 30;
marcianito1.disparos++; // Incrementamos valor de propiedad

Crear metodos:
marcianito1.disparar = function () {
this.disparos–;
alert(this.name + ” ha disparado.”);
}

Uso de metodos:
marcianito1.disparar();

2.2. Sintaxis JSON para objetos (JavaScript Object Notation). No es muy util para hacer POO.

var marcianito1 = {
name : “invasor del espacio #1”, // Uso de “:” para asignacion de valor
color : “Azul”, // Uso de “,” despues de cada propiedad si despues hay otra
x : 100,
y : 20,
disparos : 30,
disparar : function () {
this.disparos–;
alert(this.name + ” ha disparado.”);
}
}

marcianito1.disparar(); // Funciona exactamente igual.

2.3. Patrón factoría

Creando objetos usando una funcion.

function crearMarcianito(elNombre, elColor, posX, posY, disparosIniciales) {
return {
name : elNombre,
color : elColor,
x : posX,
y : posY,
disparos : disparosIniciales,
disparar : function () {
this.disparos–;
alert(this.name + ” ha disparado.”);
}
};
}

var marcianito1 = crearMarcianito(“Invasor #1”, “Azul”, 0, 0, 30);
var marcianito2 = crearMarcianito(“Invasor #2”, “Verde”, 100, 300, 50);
alert(marcianito1.name);
alert(marcianito2.name);

  1. “new” para crear objetos. Llama al constructor que contiene todas las clases.
    “instanceof” para identificar la clase de objeto.
    3.1. Constructores reales de objetos:
    “this.” para crear propiedades de propio objeto. Ej: function Marcianito(elNombre,…){ this.name = elNombre; }
    “new”. Ej.: var item = Marcianito(“Invasor #1”,…);
    3.2. Fundamentos de la variable especial this.
  • Depende desde donde se llama al “this.” le da un valor u otro.
  • “this.” en constructor (en llamada “new”) – acceso a propio objeto para crear propiedades. JS al llamar a funcion con “new”, pasa al constructor nuevo objeto vacio.
  • Si no ponemos “new”, “this.” no sera nuevo objeto y no se asignaran propiedades. No devolvera objeto esta funcion. Dentro de funcion “this.” representa que es la ventana del navegador. Es objeto global del ejecutor del codigo, en navegadores es ventana.
  • Si no ponemos “this.”, ni “var”, se definen propiedades globales como si se llaman con “this.”.
  • Objetos se escriben con PascaleCase (Primera letra mayuscula).
    3.3. Determinando el tipo del objeto:
    “typeof(item)” nos devuelve el tipo, en caso de objetos devuelve “object”, porque no son objetos nativos de JS.
    Cuando llamamos “new” nos crea una propiedad “item.constructor”. En esta propiedad esta todo el codigo del constructor.
    Si comparamos item.constructor == Marcianito. Y nos indica si constructor es igual que función.
    Si hacemos (marcianito1 instanceof Marcianito) nos indicara “true” porque nos indica que marcianito1 es una instancia del constructor Marcianito.
    Si hacemos (marcianito1 instanceof Object) tambien es “true” porque todos objetos heredan de Object.
  1. Prototipos
    4.1. Funciones compartidas en prototipos.
  • Es ineficiente crear cada vez funciones dentro asi:
    marcianito1.disparar = function () {
    this.disparos–;
    alert(this.name + ” ha disparado.”);
    }
  • Podemos asignar al metodo de la clase una funcion no anonima. Pero no es mejor forma de hacer lo.
    Ej.: marcianito1.disparar = marcianoDisparar;
  • En cambio podemos usar prototipo “Marcianito.prototype” (en este caso no se utiliza “this.”). Si le asignamos una función, sera disponible para todas las instancias de la clase. Ej.: Marcianito.prototype.disparar = function () {…}
  • Para no redefenir la misma funcion en cada llamada al constructor, comprobamos si ya existe: if(!Marcianito.prototype.disparar) { Marcianito.prototype.disparar = function() {} };
  • Con prototype podemos definir funciones a clases que ya existen. Por ejemplo queremos tener un check si es numerico en cadenas. Extendemos clase “String” y anyadimos con propotipo nueva funcionalidad. Ej.: String.prototype.isNumeric = function () {…}
    4.2. Búsqueda de miembros y cadena de prototipos:
  • No se definen metodos con prototipos en todas las clases instanciadas de un tipo en concreto. Se sigue una cadena de busqueda:
    A) Primero se busca en el objeto.
    B) Si no está se busca en su prototipo
    C) Si no está se busca en el prototipo del prototipo (de haberlo) y así sucesivamente.
    D) Si no se encuentra en el último prototipo entonces se produce un error porque no existe el miembro buscado.
  • Es muy importante que “this.” sigue apuntando al objeto original, aún que se llama desde “prototype”.
  • Prototipo es un objeto, asi que puede tener su propio prototipo.
  • “Shadow”: Podemos con prototipo ocultar en nivel inferior una funcionalidad superior. Ej: Marcianito.prototype.toString = function() { return this.name + ” – ” + this.color; };
  • Para crear variables estaticas compartidas entre todos objetos de la misma clase: Marcianito.prototype.Propiedad1 = 1; No es muy recomendable su uso.
  • Propiedad “proto” apunta a la clase prototipo. Normalmente no tenemos que tocarla.
  1. Controlando el valor de contexto con call y apply:
  • Valor de “this.” depende del contexto desde cual lo llamamos. Pero lo podemos modificar.
  • Usar metodos “call” y “apply” para pasar contexto como primer argumento y parametros (call) o matriz (apply). Ej.:
    function asignarNombreYEdad(nombre, edad) {
    this.Nombre = nombre;
    this.Edad = edad;
    }
    var miObjeto = new Object();
    asignarNombreYEdad.call(miObjeto, “Pepe”, “40”); // Llamada a la función usando call toma primer parametro como contexto (this)
    asignarNombreYEdad.apply(miObjeto, [“Pepe”, “40”]); // Lo mismo que “call”, pero se le pasan parametros en una matriz
    alert(miObjeto.Nombre + ” – ” + miObjeto.Edad);
  • Metodo “bind” igual que “call” pero no ejecuta directamente, sino crea una referencia a funcion para una llamada mas tarde con su contexto y parametros.
  1. Herencia
    6.1. Herencia: Encadenamiento de prototipos
  • No se soporta de manera nativa en JS.
  • Formas de herencia: simple encadenado de prototipos, robo de constructores, herencia por combinación, herencia prototípica (inventado por Douglas Crockford, conocido programador JavaScript), herencia parasitaria.
  • Si hacemos que el prototipo de nuestra clase sea una instancia de otra, entonces la nueva clase dispondrá de los mismos miembros que la original. Ej.:
    function ClaseBase()
    {
    this.Nombre = “”;
    ClaseBase.prototype.mostrarNombre = function () {
    alert(this.Nombre);
    }
    }
    function ClaseDerivada()
    {
    this.Apellidos = “”;
    }
    ClaseDerivada.prototype = new ClaseBase();
    ClaseDerivada.prototype.constructor = ClaseDerivada; // Importante asignar el constructor de esta manera

var cd = new ClaseDerivada();
cd.Nombre = “Perico”;
cd.Apellidos = “de los Palotes”;
cd.mostrarNombre();
alert(cd instanceof ClaseDerivada);
alert(cd instanceof ClaseBase);

No es muy recomendable esta tecnica antigua, porque es propensa de errores y no es muy comoda.

6.2. Robo de constructores y sustitución de prototipos:

  • Bibliotecas utiles: jQuery, Dojo, Prototype, ExtJS.
  • Herencia aconsejable en JS: robo de constructores con sustitución de prototipos. Consiste en llamar al constructor de la clase base desde el constructor de la derivada, pasándole como contexto el objeto que se está creando. Ej.:
    function ClaseBase(nom)
    {
    this.Nombre = nom;
    ClaseBase.prototype.mostrarNombre = function () {
    alert(this.Nombre);
    };
    }
    function ClaseDerivada(nom, apell)
    {
    ClaseBase.call(this, nom);
    this.Apellidos = apell;
    }
    ClaseDerivada.prototype = new ClaseBase();
    ClaseDerivada.prototype.constructor = ClaseDerivada;

6.4. Detalles internos sobre creación de objetos
Ej.:
function NEW(fConstructora){
var nObjeto = {
proto‘: fConstructora.prototype
};
return function(){
fConstructora.apply(nObjeto, arguments);
return nObjeto;
};
};

  • Se asigna prototipo.
  • Se devuelve funcion como objeto.
    Constructor normal:
    function Animal(sNombre, nPatas) {
    this.nombre = sNombre;
    this.patas = nPatas;
    }
    var bicho = new Animal(“Perro”, 4);
    console.log(bicho);
    Con nuestro constructor:
    var bicho2 = NEW(Animal)(“Canario”, 2);
    console.log(bicho2);
    Herencia habitual:
    function Gato(sNombre) {
    Animal.call(this, sNombre, 4);
    }
    Gato.prototype = new Animal();
    Gato.prototype.constructor = Gato;
    var gato1 = new Gato(“Patucas”);
    console.log(gato1);
    Herencia con nuestro constructor:
    var gato2 = NEW(Gato)(“Calcetines”);
    console.log(gato2); //Idéntico!

6.5. Herencia: Detalles importantes a recalcar

  • Clase puede derivarse de otra clase.
  • Los prototipos no se utilizan para instanciar objetos, sino en si son objetos.
  • Si objeto no tiene propiedad, JS busca en sus prototipos padres. Uso de cadena de prototipos.
  • Clase B que herada de clase A no tiene su constructor por defecto. Hay que asignar lo (robar), pero no siempre es obligatorio.
  • Propiedades prototype y proto no son iguales. Uno es para definicr cosas, otro es para ver el objeto. Normalmente objetos no disponen de propiedad prototype cuando depuramos, prototype apunta a objeto patron, en cambio proto al objeto concreto. “prototype” es propiedad solo de tipos nativos de JS.
  • Clase en JS en realidad en una funcion constructora.
  • Cuando una función se usa con la palabra clave new delante, JS crea un objeto vacío, asigna como prototipo (en proto) lo que haya en la propiedad prototype de la función y la llama estableciendo this a este nuevo objeto.
  • ClaseDerivada.prototype.constructor = ClaseDerivada es para asociar y saber en futuro el tipo de objeto/funcion constructora. Sino tambien funciona, pero no sabremos el tipo. O tambien para instanciar otra clase sin igual sin saber cual es la clase exacta con .constructor. Esta propiedad no existe si creamos objeto con JSON, no es obligatoria para objetos, ya que JS no la utiliza.

6.6. Herencia: Uso práctico de prototype

  • Propiedad prototype contiene funcion que se utilizara para crear objetos que se asignaran a la propiedad “proto“.
  • El prototipo es el mismo para todos los objetos de la misma clase.
  • Podemos aprovechar prototipo para crear metodos y propiedades “estaticas”.
  • Formas de crear “prototype”:
    A. Gato.prototype = new Animal(); // Podemos tener problemas con propiedades que no inicializamos
    B. Gato.prototype = new Animal(“Patron”, 0); // evitamos problemas de que haya propiedades sin inicializar
    C. Gato.prototype = object.Create(Animal.proptotype); // variante moderno, utilizando Object.create, crea objeto sin inicializar con prototipo asignado, no se llama al constructor de la clase base. Mas optimizado por no tener objetos no inicializados. Es el mas recomendado si IE>8
  • Asignamos construcor “Gato.prototype.constructor = Gato;” para coherencia y para crear hijos:
    Animal.prototype.procrear = function(){
    // Creacion normal
    return new Animal(this.nombre + ” – Hijo”, this.patas);
    // Creacion usando constructor original y le asigna el tipo de objeto identico al del padre
    return new this.proto.constructor(this.nombre + ” – Hijo”, this.patas);
    };
    gatito1 = gato1.procrear();
    console.log(gatito1);
  • Nuevas versiones de firefox muestran “proto” como “”, pero realmente es “proto“.

7.0. Encapsulación en JavaScript

  • La encapsulación o encapsulamiento es una característica de los lenguajes orientados a objetos que consiste en que las clases pueden definir miembros privados, ocultos al exterior, y que solamente pueden ser cambiados a través de los métodos establecidos a tal efecto.
  • En JS es dificil. Ya que propiedades son publicas.
  • clausuras o closures. Es una función que es evaluada en un determinado ámbito pero que tiene acceso también a variables que están ubicadas en un ámbito diferente. Son como un puente entre dos mundos.
    Ej.:
    function pruebaClosure() {
    var loc = “¡Hola closure!”;
    this.muestraMensaje = function () {
    alert(loc);
    };
    }
    var obj = new pruebaClosure();
    obj.muestraMensaje(); //Muestra el mensaje de saludo
  • La verdadera regla de acceso a variables es que una línea de nuestro código sólo puede acceder a variables que tengan un ámbito mayor o igual que el suyo propio. En este caso “loc” pertenece a un ambito mayor.
  • una jerarquía donde los niveles inferiores siempre tienen acceso a los superiores.
  • lo que representan son funciones que tienen acceso a una serie de variables liberadas ya en su propio ámbito original, pero que quedan confinadas (clausuradas) en el ámbito de la función que las utilizará más tarde, fuera de ámbito.

Ejecución diferida de funciones gracias a las clausuras
function concatenar(s1) {
return function(s2) {
return s1 + ‘ ‘ + s2;
};
}
var diHola = concatenar(“Hola”);
alert( diHola(“visitante”) );

  • hemos definido una función que permite asignar valores para ejecución retardada.
  • lo que tenemos en la variable diHola es una función pre-parametrizada y lista para ser utilizada.

Ejemplo de uso en setInterval y setTimeOut cuando queremos pasar parametros a la funcion, en lugar de llamar a una funcion desde otra funcion (solución fea pero comun).
function moverElemento(elto, x, y)
{
return function(){
elto.style = “position:absolute; left:”+ x + “;top:” + “y;”;
};
}
var mover = moverElemento(getElementById(“miDiv”), 0, 0);
setTimeout(mover, 500);

  • Para mantener ambito al principio de funciones escribimos como primera linea, es importante para si hay subfunciones:
    var that = this; // O tambien se utiliza “var self = this;”

7.2.1. Prototipos accediendo a variables de ámbito: un error grave

  • Cuidado que objetos no tengas atributos compartidos:
    function Marcianito(elNombre, elColor, posX, posY, disparosIniciales) {
    var that = this;
    var _name = elNombre;
    Marcianito.prototype.getName = function(){
    return _name.toUpperCase() + ” (” + that.color + “)”;
    };
    }
  • Aqui el problema esta en que se redefine funcion de prototipo “getName”. Esta funcion del prototipo queda atada a propiedades del ultimo ambito que la llama. De esta manera podemos crear “variables privadas estáticas”.
  • Para metodos de clausura no hay que utilizar prototype, sino crear metodos con this. Ej: this.getName = function(){…_name…that.color…;
  • Las funciones del prototipo no pueden acceder a variables de instancia (como _name o that en el ejemplo).
  • Funcion completa de ejemplo:
    function Marcianito(elNombre, elColor, posX, posY, disparosIniciales) {
    var that = this;
    var _name = elNombre;
    this.getName = function(){
    return _name.toUpperCase() + ” (” + that.color + “)”;
    };
    this.setName = function (nombre) {
    _name = nombre;
    };
    this.color = elColor;
    if (posX < 0) posX = 0; if (posX > 100) posX = 100;
    this.x = posX;
    if (posY < 0) posY = 0; if (posY > 100) posY = 100;
    this.y = posY;
    if (disparosIniciales < 0) disparosIniciales = 0; if (disparosIniciales > 100) disparosIniciales = 100;
    this.disparos = disparosIniciales;
    if (!Marcianito.prototype.disparar) {
    Marcianito.prototype.disparar = function () {
    this.disparos–;
    //codigo para pintar el disparo
    alert(this.getName() + ” ha disparado.”);
    };
    }
    Marcianito.prototype.toString = function () {
    return this.getName() + ” – ” + this.color;
    };
    }

7.3. Verdaderas propiedades encapsuladas

  • En POO por regla general se entiende por propiedad a un miembro que utiliza el mismo nombre tanto para leer como para escribir.
  • defineGetter y defineSetter de Object para definir con que funcion escribir y leer propiedades. Integradas en Mozilla Firefox, Chrome, Safari y Opera, pero no en Internet Explorer. Mozilla ha decidido hacerlas obsoletas, no forman parte de estandar.
  • ECMAScript 5 introduce “método defineProperty”.
  • defineProperty(objeto, nombre, descriptor):
    A. El objeto sobre el que se va a definir la propiedad
    B. El nombre de la propiedad
    C. Un objeto descriptor que definirá mediante sus propiedades las características concretas que regirán el acceso a la propiedad.
    C1. value: el valor inicial.
    C2. get: leer valor.
    C3. set: almacenar valor.
    C4. writable: posible cambiar valor.
    C5. configurable: si podemos o no cambiar el tipo de descriptor.
    C6. enumerable: indica se es enum.
  • “delete” permite eliminar miembros de objetos.
  • Ejemplo de uso de defineProperty
    var objeto = new Object();
    Object.defineProperty(objeto, “nombre”,
    {
    value: “Mi nombre”,
    writable: true,
    enumerable: true,
    configurable: true
    }
    );
  • Otra forma de definir con JSON
    if (Object.defineProperty) {
    Object.defineProperty(this, “name”,
    {
    get: getName,
    set: setName
    });
    }
  • Si usamos value no podemos utilizar las funciones get y set, y viceversa.
  • variante denominada defineProperties (en plural) para definicion multiple:
    Object.defineProperties(objeto,
    {
    “Apellido1”: { value: “López”, writable:true, enumerable:true},
    “Apellido2”: { value: “Fernández”, writable: true, enumerable: true }
    }
    );
  • Podemos bloquear la modificación de un objeto con Object (preventExtensions, seal y freeze).
  • “preventExtensions” no deja añadir propiedades o metodos.
  • “sel” impide añadir, quitar, redefinir propiedades/metodos.
  • “freeze” sella objeto y conjela propiedades (si en descriptor usan “value”).
  • Para verificar estado de estos metodos isExtensible, isSealed y isFrozen.
  1. Reflexión: Inspeccionando los objetos
  • Técnicas de reflexión (miembros que tiene un objeto)
  • Nombres (for-in): for (var prop in marcianito1)
  • Acceso a valor: marcianito1[“disparos”] = 50;
  • Llamada a funcion: marcianito1[“disparar”]();
  • For-in no devuelve en mismo orden en diferentes navegadores. Propiedades sin definir pueden no aparecer. Ej.:
    function ResumeObjeto(obj) {
    var prop;
    var informe = “”;
    for (prop in obj) {
    informe += prop + “: ” + obj[prop] + “\n”;
    }
    return informe;
    }