Herencia prototípica
Al igual que otros tipos de datos, un objeto hereda propiedades y métodos de un prototipo integrado Object
, lo que significa que el objeto resultante contiene las propiedades que definiste y una propiedad del prototipo que contiene los métodos heredados del prototipo:
let myObject = {
'booleanValue' : true
};
myObject;
> Object { booleanValue: true }
booleanValue: true
[[prototype]]: Object { … }
__defineGetter__: function __defineGetter__()
__defineSetter__: function __defineSetter__()
__lookupGetter__: function __lookupGetter__()
__lookupSetter__: function __lookupSetter__()
__proto__: …
constructor: function Object()
hasOwnProperty: function hasOwnProperty()
isPrototypeOf: function isPrototypeOf()
propertyIsEnumerable: function propertyIsEnumerable()
toLocaleString: function toLocaleString()
toString: function toString()
valueOf: function valueOf()
<get __proto__()>: function __proto__()
<set __proto__()>: function __proto__()
Las propiedades de prototipos no están diseñadas para que la clave de propiedad no pueda acceder a ellas de forma directa. Como puedes observar en el ejemplo anterior, esto está implícito por la notación [[prototype]]
o <prototype>
que se usa en las consolas para desarrolladores de los navegadores y en las fuentes de documentación de la clave de propiedad del prototipo:
// Chrome:
let emptyObject = {};
emptyObject;
> {}
[[prototype]]: Object
// Firefox:
let emptyObject = {};
emptyObject;
> Object { }
<prototype>: Object { … }
Aunque todos los navegadores comunes usan __proto__
como un estándar de facto, esto no está
estandarizado formalmente y debe evitarse en el código de producción.
let emptyObject = {};
emptyObject.__proto__;
> Object { … }
__defineGetter__: function __defineGetter__()
__defineSetter__: function __defineSetter__()
__lookupGetter__: function __lookupGetter__()
__lookupSetter__: function __lookupSetter__()
__proto__:
constructor: function Object()
hasOwnProperty: function hasOwnProperty()
isPrototypeOf: function isPrototypeOf()
propertyIsEnumerable: function propertyIsEnumerable()
toLocaleString: function toLocaleString()
toString: function toString()
valueOf: function valueOf()
<get __proto__()>: function __proto__()
<set __proto__()>: function __proto__()
En su lugar, puedes acceder directamente al [[Prototype]]
de un objeto y modificarlo con los métodos integrados Object.getPrototypeOf()
y Object.setPrototypeOf()
:
let myObj = { "value" : 5 };
let protoParent = { "protoValue" : true };
myObj;
Object { value: 5 }
value: 5
<prototype>: Object { … }
Object.getPrototypeOf( myObj );
> Object { … }
__defineGetter__: function __defineGetter__()
__defineSetter__: function __defineSetter__()
__lookupGetter__: function __lookupGetter__()
__lookupSetter__: function __lookupSetter__()
__proto__:
constructor: function Object()
hasOwnProperty: function hasOwnProperty()
isPrototypeOf: function isPrototypeOf()
propertyIsEnumerable: function propertyIsEnumerable()
toLocaleString: function toLocaleString()
toString: function toString()
valueOf: function valueOf()
<get __proto__()>: function __proto__()
<set __proto__()>: function __proto__()
Object.setPrototypeOf( myObj, protoParent );
> Object { value: 5 }
value: 5
<prototype>: Object { protoValue: true }
Para diferenciar entre las propiedades heredadas y las propiedades definidas por el autor, esta última suele denominarse “propiedades propias” del objeto.
El método integrado Object.hasOwn()
muestra true
si la propiedad especificada
es una propiedad directa del objeto y false
si la propiedad es heredada o
no existe. Siempre que sea posible, usa Object.hasOwn()
, en lugar del método hasOwnProperty()
heredado, que no admite Object.create()
.
let myObject = {
'myValue' : 100
};
Object.hasOwn( myObject, 'myValue' );
> true
myObject.__proto__; // The Object prototype inherited by `myObject` is present:
> Object { … }
Object.hasOwn( myObject, '__proto__' ); // The Object prototype inherited by `myObject` is not an "own property:"
> false
Verifica tus conocimientos
¿Por qué deberías evitar usar __proto__
?