JavaScript Cómo incrustar miembros privados en un objeto

Recientemente desarrollé Angular Cloud Data Connector, que permite a los desarrolladores de Angular usar datos de la nube, específicamente los servicios móviles de Azure, utilizando estándares web como la base de datos indexada. Estaba intentando crear una forma para que los desarrolladores de JavaScript incrusten miembros privados en un objeto. 

Mi técnica para este caso específico es usar lo que yo llamo "espacio de cierre". En este tutorial, quiero compartir con ustedes cómo usar esto para sus propios proyectos y cómo afecta el rendimiento y la memoria para los principales navegadores.

Pero antes de sumergirme en él, permítame compartir por qué puede necesitar miembros privados, así como una forma alternativa de "simular" miembros privados..

Siéntase libre de hacerme ping en Twitter si desea discutir este artículo: @deltakosh.

1. ¿Por qué usar miembros privados?

Cuando creas un objeto usando JavaScript, puedes definir miembros de valor. Si desea controlar el acceso de lectura / escritura en ellos, necesita accesores que puedan definirse así:

entidad var = ; entity._property = "hola mundo"; Object.defineProperty (entidad, "propiedad", get: function () return this._property;, set: function (value) this._property = value;, enumerable: true, configurable: true);

Al hacer esto, tienes control total sobre las operaciones de lectura y escritura. El problema es que la _propiedad miembro sigue siendo accesible y puede ser modificado directamente.

Esta es exactamente la razón por la que necesita una forma más robusta de definir miembros privados a los que solo pueden acceder las funciones de los objetos..

2. Usando el espacio de cierre

La solución es utilizar el espacio de cierre. Este espacio de memoria lo crea el navegador cada vez que una función interna tiene acceso a las variables desde el alcance de una función externa. Esto puede ser complicado a veces, pero para nuestro tema, esta es una solución perfecta.

Así que vamos a modificar el código anterior para utilizar esta función:

var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, enumerable: true, configurable : cierto );  var entidad = ; var myVar = "hola mundo"; createProperty (entidad, "propiedad", myVar);

En este ejemplo, el crear propiedad la función tiene un valor actual Variable que obtiene y establece funciones que puede ver. Esta variable se guardará en el espacio de cierre de las funciones de obtención y configuración. Sólo estas dos funciones ahora pueden ver y actualizar el valor actual ¡variable! Misión cumplida!

La única advertencia que tenemos aquí es que el valor de origen (mivar) sigue siendo accesible. Así que aquí viene otra versión para una protección aún más robusta:

var createProperty = function (obj, prop) var currentValue = obj [prop]; Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, enumerable: true, configurable: true);  var entity = propiedad: "hola mundo"; createProperty (entidad, "propiedad");

Usando este método, incluso el valor de la fuente se destruye. Así que misión cumplida!

3. Consideraciones de rendimiento

Veamos ahora el rendimiento..

Obviamente, los espacios de cierre o incluso las propiedades son más lentos y costosos que una simple variable. Es por eso que este artículo se centra más en la diferencia entre la forma regular y la técnica de espacio de cierre..

Para confirmar que el enfoque del espacio de cierre no es demasiado costoso en comparación con el método estándar, escribí este pequeño punto de referencia:

       
Informática…

Creo 1 millón de objetos, todos con un miembro de propiedad. Luego hago tres pruebas:

  • Hacer 1 millón de accesos aleatorios a la propiedad..
  • Hacer 1 millón de accesos aleatorios a la versión "espacio de cierre"..
  • Haga 1 millón de accesos aleatorios a la versión regular de get / set.

Aquí hay una tabla y una tabla de los resultados:

Podemos ver que la versión del espacio de cierre es siempre más rápida que la versión regular y dependiendo del navegador, Puede ser una optimización realmente impresionante..

El rendimiento de Chrome es menos de lo que esperaba. Puede haber un error, así que para estar seguro, me puse en contacto con el equipo de Google para averiguar qué está pasando aquí. Además, si desea probar cómo funciona esto en el nuevo navegador Microsoft Edge-Microsoft que se enviará por defecto con Windows 10, puede descargarlo aquí.

Sin embargo, si observamos de cerca, podemos encontrar que usar el espacio de cierre o incluso una propiedad puede ser diez veces más lento que el acceso directo a un miembro. Así que ten cuidado y úsalo sabiamente..

4. Huella de memoria

También tenemos que comprobar que esta técnica no consume demasiada memoria. Para comparar la memoria escribí estas tres piezas de código:

Código de referencia

var sampleSize = 1000000; entidades var = []; // Creando entidades para (var index = 0; index < sampleSize; index++)  entities.push( property: "hello world (" + index + ")" ); 

Manera regular

var sampleSize = 1000000; entidades var = []; // Agregar propiedad y usar un miembro local para guardar un valor privado para (var index = 0; index < sampleSize; index++)  var entity = ; entity._property = "hello world (" + index + ")"; Object.defineProperty(entity, "property",  get: function ()  return this._property; , set: function (value)  this._property = value; , enumerable: true, configurable: true ); entities.push(entity); 

Versión de espacio de cierre

var sampleSize = 1000000; entidades var = []; var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, enumerable: true, configurable : cierto );  // Agregar propiedad y usar el espacio de cierre para guardar el valor privado para (var index = 0; index < sampleSize; index++)  var entity = ; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); 

Luego ejecuté estos tres códigos y lancé el generador de perfiles de memoria integrado (por ejemplo, aquí con las herramientas F12):

Aquí están los resultados que obtuve en mi computadora:

Entre el espacio de cierre y el modo regular, solo Chrome tiene resultados ligeramente mejores para la versión de espacio de cierre. IE11 y Firefox usan un poco más de memoria, pero los navegadores son relativamente comparables, los usuarios probablemente no notarán una diferencia entre los navegadores modernos.

Más práctica con JavaScript

Puede que te sorprenda un poco, pero Microsoft tiene un montón de aprendizaje gratuito sobre muchos temas de código abierto de JavaScript, y estamos en la misión de crear mucho más con la llegada de Microsoft Edge. Echa un vistazo a mi propia:

  • Introducción a WebGL 3D con HTML5 y Babylon.JS
  • Creación de una aplicación de una sola página con ASP.NET y AngularJS
  • Gráficos de vanguardia en HTML

O la serie de aprendizaje de nuestro equipo:

  • Consejos prácticos de rendimiento para hacer que su HTML / JavaScript sea más rápido (una serie de siete partes que abarca desde el diseño responsivo hasta los juegos casuales y la optimización del rendimiento)
  • The Modern Web Platform Jump Start (los fundamentos de HTML, CSS y JS)
  • Desarrollar aplicaciones universales de Windows con HTML y JavaScript Jump Start (use el JS que ya creó para crear una aplicación)

Y algunas herramientas gratuitas: Visual Studio Community, Azure Trial y herramientas de prueba en varios navegadores para Mac, Linux o Windows.

Conclusión

Como puede ver, las propiedades de espacio de cierre pueden ser una gran manera de crear datos realmente privados. Puede que tenga que lidiar con un pequeño aumento en el consumo de memoria, pero desde mi punto de vista esto es bastante razonable (y a ese precio puede tener una gran mejora de rendimiento en comparación con el uso regular).

Y, por cierto, si quieres probarlo por ti mismo, encuentra todo el código utilizado aquí. Hay un buen "manual" sobre los servicios móviles de Azure aquí.

Este artículo es parte de la serie web dev tech de Microsoft. Estamos muy contentos de compartir Microsoft Edge y lo nuevo Motor de renderizado EdgeHTML con usted. Obtenga máquinas virtuales gratuitas o realice pruebas a distancia en su dispositivo Mac, iOS, Android o Windows @ http://dev.modern.ie/.

Aprender JavaScript: la guía completa

Hemos creado una guía completa para ayudarlo a aprender JavaScript, ya sea que esté comenzando a trabajar como desarrollador web o si desea explorar temas más avanzados..