Skip to content

Instantly share code, notes, and snippets.

@a0viedo
Last active May 18, 2022 21:01
Show Gist options
  • Save a0viedo/57e0ffcc00cb5e5abc23 to your computer and use it in GitHub Desktop.
Save a0viedo/57e0ffcc00cb5e5abc23 to your computer and use it in GitHub Desktop.

Objetos y sus keys

Sabemos que un objeto es una "bolsa" de keys (propiedades) y values (valores). Por ejemplo si ejecutamos el siguiente código:

var obj = { a: 1 };
console.log(Object.keys(obj)); // [ "a" ]

podemos entender que Object.keys nos retorna un array con los keys que contiene el objeto que recibe por parámetro. A su vez, un objeto puede poseer propiedades pero éstas estar definidas para que no sean enumerables. Una propiedad no-enumerable no es recorrida con loops for...in y no es considerada por Object.keys. La forma de definir propiedades no-enumerables es con Object.defineProperty. Se puede saber también si una propiedad es enumerable usando Object.prototype.propertyIsEnumerable, por ejemplo:

console.log(Object.keys(Math)); // []
console.log(Math.propertyIsEnumerable('random')); // false
console.log(Object.getOwnPropertyNames(Math)); // ["E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", "SQRT1_2", "SQRT2", "random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor", "log", "round", "sin", "sqrt", "tan", "atan2", "pow", "max", "min", "imul", "sign", "trunc", "sinh", "cosh", "tanh", "asinh", "acosh", "atanh", "log10", "log2", "hypot", "fround", "clz32", "cbrt", "log1p", "expm1"]

Por lo tanto, si queremos obtener todas las propiedades de un objeto, ya sean enumerables o no, debemos utilizar Object.getOwnPropertyNames. Si lo aplicamos a un array vacío:

console.log(Object.getOwnPropertyNames([])); // ["length"]
console.log([].forEach); // function forEach() { [native code] }

Entonces, ¿dónde reside la función forEach? ¿Cuando se setea en el array vacío?¿Pertenece realmente al array vacío?

Prototype Chain

JavaScript es conocido por ser uno de los únicos lenguajes de programación popular en utilizar herencia prototipada. Otros conocidos son Perl, Lua y Lisp. Esto significa básicamente que el reuso de componentes será dado por un link ascendente y uno descendente dentro de algo llamado prototype chain. Por ejemplo, cualquier objeto hereda de un único objeto que tiene predefinidas las propiedades que utilizamos comunmente. Para "subir" por la prototype chain se puede utilizar la propiedad (no estandar) __proto__. Por ejemplo:

var obj = {};
Object.getOwnPropertyNames(obj); // []
Object.getOwnPropertyNames(obj.__proto__); // ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__", "__proto__"]

Dónde obj.__proto__ referencia a el objeto del cual heredan todos los objetos. Lo mismo ocurre con arrays y funciones, que a su vez cómo ya sabemos son objetos también. Dada una función constructora, por ejemplo Array, si queremos referenciar al objeto que van a referenciar todos los arrays que se creen debemos utilizar la propiedad prototype. Por ejemplo:

console.log([].__proto__ === Array.prototype) // true

Podemos visualizar que todo array creado linkea a través de la prototype chain (ascendente) a Array.prototype. Douglas Crockford comenta mucho acerca de este tema y hace incapié especialmente porque muchos desarrolladores mantienen la forma de pensar de "herencia clásica" y no aceptan la forma prototipada. Según Douglas, la mejor forma de verlo es objetos que heredan comportamiento de objetos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment