📜 ⬆️ ⬇️

Creating objects inherited from null on Node.js

From the translator: the translator's field is new to me, so I ask you not to judge strictly.

Once, reading the Principles of Object-Oriented JavaScript by Nicholas Zakas , I came across a tip on using Object.create () to create objects inherited from null. Such an object does not inherit the Object.prototype and, accordingly, will not have it, the Object.prototype , methods. Zakaz suggested that this could be used to create a secure “ cache ” object. I really liked this idea, but according to the MDN ( Mozilla Developer Network ), Object.create () is not supported until IE9 , which makes this method more demanding when used in a browser. But in Node.js , on the server, this method is fully supported.

When you create an object in JavaScript , this object automatically inherits the Object.prototype methods. Because of this, the object becomes “dangerous” for checking the existence of keys using the “ in ” operator, since in this case there will be such object methods as “ valueOf ” and “ toString ” (as a result of elevating the prototype hierarchy). Therefore, people prefer to use Object.prototype.hasOwnProperty () instead of the “ in ” operator .

But if you create an object inherited from null using Object.create () , then there will be no inheritance hierarchy. As such, this object becomes very close to an object that does not contain system-predefined methods.
')
To see how this works, take a look at the following Node.js script:
//    .        //   .  ,          //  ,          . var safeCache = Object.create(null); //  ,   -     . ["hasOwnProperty", "toString", "valueOf", "constructor", "__proto__"] .forEach( function iterator(key, index) { console.log("[ %s ] exists: %s", key, ( key in safeCache )); } ); 

When you run this script, we get the following result:
 [ hasOwnProperty ] exists: false [ toString ] exists: false [ valueOf ] exists: false [ constructor ] exists: false [ __proto__ ] exists: true 

As you can see, all the “standard” properties of Object.prototype are missing. The only, magical property that exists is " __proto__ ". This gives us the closest possible opportunity, blindly, to add, delete and check the presence of keys for this object. I assume that this is an acceptable level of risk for the possibility of the simplest possible code.

Of course, when I say “simple code”, the difference is not so significant. To see something specific, I tried to create a maximally simple cache class that encapsulates storing key-value pairs. The first class is the storage implemented on an object inherited from null ; the second class is a repository implemented on a regular JavaScript object:
 //         //    null,  , ,   //         . function SafeCache() { var cache = Object.create(null); // Reveal the public API. return ({ get: get, has: has, remove: remove, set: set }); // --- // PUBLIC METHODS. // --- function get(key) { return ( cache[key] ); } function has(key) { return ( key in cache ); } function remove(key) { return ( delete( cache[key] ), this ); } function set(key, value) { return ( cache[key] = value, this ); } } var safeCache = new SafeCache() .set("foo", "Bar") .set("hello", "world") .set("beep", "boop"); console.log("## Safe Cache ##"); console.log(safeCache.has("foo")); console.log(safeCache.has("meep")); console.log(safeCache.has("valueOf")); console.log(safeCache.has("__proto__")); //         , //        //    ,  , . function SaferCache() { var cache = {}; // Reveal the public API. return ({ get: get, has: has, remove: remove, set: set }); // --- // PUBLIC METHODS. // --- function get(key) { if (has(key)) { return ( cache[key] ); } } function has(key) { return ( cache.hasOwnProperty(key) ); } function remove(key) { return ( delete( cache[key] ), this ); } function set(key, value) { return ( cache[key] = value, this ); } } var saferCache = new SaferCache() .set("foo", "Bar") .set("hello", "world") .set("beep", "boop"); console.log("## Safer Cache ##"); console.log(saferCache.has("foo")); console.log(saferCache.has("meep")); console.log(saferCache.has("valueOf")); console.log(saferCache.has("__proto__")); 

If you only glanced briefly at this code, you might not even notice the difference. But it is there, in the get () and has () methods.

To be honest, if you intend to encapsulate the cache implementation, you could use the most reliably - .hasOwnProperty () or, for example, a mixed key. But if you do not work with an incomplete cache, using an object inherited from null can be a reasonable method of balancing between code simplicity and risk. And if none of the above, then it is simply useful to know that you can create an object inherited from null in JavaScript / Node.js.

Source: https://habr.com/ru/post/253051/


All Articles