Prototype Methods, Objects Without __proto__
Let’s first explore the modern methods for setting up a prototype.
Amongst them are:
- Object.create(proto[, descriptors]). This method is used for creating an empty object with given proto as [[Prototype]], as well as, optional property descriptors.
- Object.getPrototypeOf(obj). This one helps to return the [Prototype]] of the obj.
- Object.setPrototypeOf(obj, proto). The method is aimed at setting the [[Prototype]] of the obj to proto.
So, you can use the mentioned methods instead of the __proto__.
Take a look at the following example:
let animal = {
speaks: true
};
let dog = Object.create(animal);// create a new object with animal as a prototype
console.log(dog.speaks); // true
console.log(Object.getPrototypeOf(dog) === animal); // true
Object.setPrototypeOf(dog, {}); // change the prototype of dog to {}
There is an alternative argument for Object.create: property descriptors. You have the option of providing additional properties to the object there.
For example:
let animal = {
speaks: true
};
let dog = Object.create(animal, {
runs: {
value: true
}
});
console.log(dog.runs); // true
For performing an object cloning, it’s more convenient to use Object.create than copying properties in for..in.
The example looks like this:
// fully identical shallow clone of obj
let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
The call mentioned above creates the exact copy of obj, which includes all the properties: non-enumerable and enumerable, data properties, setters/getters, and with the suitable [[Prototype]].
Short History¶
There are many ways of managing the [[Prototype]].
One of the reasons is that the “prototype” property has worked since ancient times. In 2012, Object.create was added to the standard. It started to allow creating objects with __proto__ accessor.
Later, in 2015, Object.setPrototypeOf and Object.getPrototypeOf appeared in the standard for performing the same functionality as __proto__.
Nowadays, all these methods are at the developers’ disposal.
Technically, it is possible to get/set [[Prototype]] at any time. But, commonly, it is set once while creating the object and is not modified anymore. Changing a prototype with Object.setPrototypeOf or obj.__proto__= can be considered a slow operation. The reason is that it breaks internal optimizations for object property access operations.
"Very Plain" Objects¶
You can use objects as associative arrays for storing key/value pairs. But in the event of trying to store user-provided keys inside it, a unique error may occur: all the keys will work well except "__proto__".
Look at this example:
let obj = {};
let key = prompt("What is the key value?", "__proto__");
obj[key] = "some value";
console.log(obj[key]); // [object Object], not "some value"!
Here when the user types __proto__, the assignment is ignored. Thus, the __proto__ property is unique. It can be either null or an object. A string can’t transform into a prototype.
So, the main problem is that "__proto__" is not saved accurately. It’s a bug. Some unexpected things can happen while assigning toString that is a function by default.
To avoid such kinds of problems, first, you can switch to using Map .
The Object may also be helpful. The __proto__ is not an object property, but an accessor property of Object.prototype.
Check out this case:
In obj.__proto__ is set or read, the appropriate setter/getter is called from its prototype, as well as, sets/gets [[Prototype]].
If you intend to use an object as an associative array, you can implement it with a trick.
Here is how to do it:
let obj = Object.create(null);
let key = prompt("What's the key value?", "__proto__");
obj[key] = "some value";
console.log(obj[key]); // "some value"
Object.create(null) generates an empty object without a prototype:
It can be assumed that there isn’t any inherited getter/setter for __proto__. It is handled as an ordinary data property.
Such objects can be named “very plain” because they are more straightforward than the ordinary plain object {...}.
The disadvantage is that such objects lack built-in object methods (toString).
For instance:
let obj = Object.create(null);
console.log(obj); // Error (no toString)
Usually, it’s fine for associative arrays.
0 Comments
CAN FEEDBACK
Emoji