Pitfalls using DOM-Javascript VS pure Javascript objects? - javascript

Background
First of, I would like to mention, that a SO-search for figuring out differences of
(host objects) DOM-Javascript Objects (var domJSobj = document.createElement("div")) and
(native objects) pure Javascript Objects (var pureJSobj = {})
has been done, but still I cannot claim that I found very much (great is, that there is this question-answers: what-is-the-difference-between-native-objects-and-host-objects). Maybe I overlooked something here, then a comment is very appreciated.
I also read MDN Mozillas Docu on DOM and Javascript to get some idea before asking here.
Question
Being a little "glueless" I started playing in the Javascript Console and I encountered some first pitfall (arising from expectations I have regarding the behaviour of (native objects) which are not true for (host objects)). To be clear many things -at first sight- seem similar:
var nativeObject = {}; //create new object
nativeObject.someAttribute = "something"; //set some attribute
nativeObject.someMethod = function() { return this.someAttribute; } // define some method
console.log(nativeObject.someAttribute); // "something"
console.log(nativeObject.someMethod()); // "something"
var hostObject = document.createElement("div"); //create a "div" one type of host object
hostObject.someAttribute = "something"; //set some attribute
hostObject.someMethod = function() { return this.someAttribute; } // define some method
console.log(hostObject.someAttribute); // "something"
console.log(hostObject.someMethod()); // "something"
For me it seems at first sigth that a (host object) is just as usable as a (native object) and has already more:
console.log(nativeObject.tagName); // undefined
console.log(hostObject.tagName); // "DIV"
as it has the all the nice DOM-attributes already there.
My Question is about a list of pitfalls (possible troubles) that can arrise if I decide to (mis)use a (host object) instead of simple (native object)?
already I am aware of this:
speed considerations (I assume that native objects are created more quickly)
memory usage consideratoins (native objects might be better here too)
Anyways I cannot see much trouble (if those considerations are not very important in a case) yet? This is the reason for the question.
I think answers to this question would be best showing/telling one potential pitfall, that is a case or situation in which it is bad or impossible to use a (host object) over a (native object). In this way this question should adhere to the SO-quality requirement of being passed on real facts and not provoking mere opinion-based-discussion.

For me, the pitfall of using a DOM-based object is that from the moment it's created it already has dozens of properties. Your document.createElement("div") object has an id property and a title property and a style property that is an object of its own, etc. If you want to use a DOM-based object to store arbitrary data, you need to be careful not to name your property something that already exists or you may get unexpected results; for example in my tests in Chrome, the code hostObject.id = null would actually cause hostObject.id to be "" rather than true null; or hostObject.id = false would cause it to be "false" (i.e. the string, not true false) for the hostObject variable defined in your code.
Try adding this to your code:
for (property in document.createElement("div"))
console.log(property);
In Chrome, I see 134 properties listed. That's a lot of landmines to potentially avoid. And beyond that, the properties differ between browsers. The same code in Firefox lists 192 properties.
I would only create a DOM object if you actually intend to use it as a DOM object. Then the properties have some purpose; otherwise they're just potential bugs in your code. Like the comments say, KISS; I mean, sure, I could decide to save the integer value 123456789 within a Date object:
myInt = new Date(123456789);
myInt.getTime(); // returns 123456789
But what's the point of that? Why not just do myInt = 123456789? Just as I wouldn't use a Date object to store integer data, don't use a DOM object to store arbitrary data.

Related

When should I prefer a clone over an reference in javascript?

at the moment I'm writing a small app and came to the point, where I thought it would be clever to clone an object, instead of using a reference.
The reason I'm doing this is, because I'm collecting objects in a list. Later I will only work with this list, because it's part of a model. The reference isn't something I need and I want to avoid having references to outside objects in the list, because I don't want someone to build a construct, where the model can be changed from an inconsiderate place in their code. (The integrity of the information in the model is very important.)
Additional I thought I will get a better performance out of it, when I don't use references.
So my overall question still is: When should I prefer a clone over an reference in javascript?
Thanks!
If stability is important, then clone it. If testing shows that this is a bottleneck, consider changing it to a reference. I'd be very surprised if it is a bottleneck though, unless you have a very complicated object which is passed back and forth very frequently (and if you're doing that it's probably an indication of a bad design).
Also remember that you can only do so much to save other developers from their own stupidity. If they really want to break your API, they could just replace your functions with their own by copying the source or modifying it at runtime. If you document that the object must not be changed, a good developer (yes, there are some) will follow that rule.
For what it's worth, I've used both approaches in my own projects. For small structs which don't get passed around much, I've made copies for stability, and for larger data (e.g. 3D vertex data which may be passed around every frame), I don't copy.
Why not just make the objects stored in the list immutable? Instead of storing simple JSON-like objects you would store closures.
Say you have an object with two properties A and B. It looks like that:
myObj = {
"A" : "someValue",
"B" : "someOtherValue"
}
But then, as you said, anyone could alter the state of this object by simply overriding it's properties A or B. Instead of passing such objects in a list to the client, you could pass read-only data created from your actual objects.
First define a function that takes an ordinary object and returns a set of accessors to it:
var readOnlyObj = function(builder) {
return {
getA : function() { return builder.A; },
getB : function() { return builder.B; }
}
}
Then instead of your object myObj give the user readOnlyObj(myObj) so that they can access the properties by methods getA and getB.
This way you avoid the costs of cloning and provide a clear set of valid actions that a user can perform on your objects.

Why would I need to freeze an object in JavaScript?

It is not clear to me when anyone would need to use Object.freeze in JavaScript. MDN and MSDN don't give real life examples when it is useful.
I get it that an attempt to change such an object at runtime means a crash. The question is rather, when would I appreciate this crash?
To me the immutability is a design time constraint which is supposed to be guaranteed by the type checker.
So is there any point in having a runtime crash in a dynamically typed language, besides detecting a violation better later than never?
The Object.freeze function does the following:
Makes the object non-extensible, so that new properties cannot be added to it.
Sets the configurable attribute to false for all properties of the object. When - configurable is false, the property attributes cannot be changed and the property cannot be deleted.
Sets the writable attribute to false for all data properties of the object. When writable is false, the data property value cannot be changed.
That's the what part, but why would anyone do this?
Well, in the object-oriented paradigm, the notion exists that an existing API contains certain elements that are not intended to be extended, modified, or re-used outside of their current context. The final keyword in various languages is the most suitable analogy of this. Even in languages that are not compiled and therefore easily modified, it still exists, i.e. PHP, and in this case, JavaScript.
You can use this when you have an object representing a logically immutable data structure, especially if:
Changing the properties of the object or altering its "duck type" could lead to bad behavior elsewhere in your application
The object is similar to a mutable type or otherwise looks mutable, and you want programmers to be warned on attempting to change it rather than obtain undefined behavior.
As an API author, this may be exactly the behavior you want. For example, you may have an internally cached structure that represents a canonical server response that you provide to the user of your API by reference but still use internally for a variety of purposes. Your users can reference this structure, but altering it may result in your API having undefined behavior. In this case, you want an exception to be thrown if your users attempt to modify it.
In my nodejs server environment, I use freeze for the same reason I use 'use strict'. If I have an object that I do not want being extended or modified, I will freeze it. If something attempts to extend or modify my frozen object, I WANT my app to throw an error.
To me this relates to consistent, quality, more secure code.
Also,
Chrome is showing significant performance increases working with frozen objects.
Edit:
In my most recent project, I'm sending/receiving encrypted data between a government entity. There are a lot of configuration values. I'm using frozen object(s) for these values. Modification of these values could have serious, adverse side effects. Additionally, as I linked previously, Chrome is showing performance advantages with frozen objects, I assume nodejs does as well.
For simplicity, an example would be:
var US_COIN_VALUE = {
QUARTER: 25,
DIME: 10,
NICKEL: 5,
PENNY: 1
};
return Object.freeze( US_COIN_VALUE );
There is no reason to modify the values in this example. And enjoy the benefits of speed optimizations.
Object.freeze() mainly using in Functional Programming (Immutability)
Immutability is a central concept of functional programming because without it, the data flow in your program is lossy. State history is abandoned, and strange bugs can creep into your software.
In JavaScript, it’s important not to confuse const, with immutability. const creates a variable name binding which can’t be reassigned after creation. const does not create immutable objects. You can’t change the object that the binding refers to, but you can still change the properties of the object, which means that bindings created with const are mutable, not immutable.
Immutable objects can’t be changed at all. You can make a value truly immutable by deep freezing the object. JavaScript has a method that freezes an object one-level deep.
const a = Object.freeze({
foo: 'Hello',
bar: 'world',
baz: '!'
});
When you're writing a library/framework in JS and you don't want some developer to break your dynamic language creation by re-assigning "internal" or public properties.
This is the most obvious use case for immutability.
With the V8 release v7.6 the performance of frozen/sealed arrays is greatly improved. Therefore, one reason you would like to freeze an object is when your code is performance-critical.
What is a practical situation when you might want to freeze an object?
One example, on application startup you create an object containing app settings. You may pass that configuration object around to various modules of the application. But once that settings object is created you want to know that it won't be changed.
This is an old question, but I think I have a good case where freeze might help. I had this problem today.
The problem
class Node {
constructor() {
this._children = [];
this._parent = undefined;
}
get children() { return this._children; }
get parent() { return this._parent; }
set parent(newParent) {
// 1. if _parent is not undefined, remove this node from _parent's children
// 2. set _parent to newParent
// 3. if newParent is not undefined, add this node to newParent's children
}
addChild(node) { node.parent = this; }
removeChild(node) { node.parent === this && (node.parent = undefined); }
...
}
As you can see, when you change the parent, it automatically handles the connection between these nodes, keeping children and parent in sync. However, there is one problem here:
let newNode = new Node();
myNode.children.push(newNode);
Now, myNode has newNode in its children, but newNode does not have myNode as its parent. So you've just broken it.
(OFF-TOPIC) Why are you exposing the children anyway?
Yes, I could just create lots of methods: countChildren(), getChild(index), getChildrenIterator() (which returns a generator), findChildIndex(node), and so on... but is it really a better approach than just returning an array, which provides an interface all javascript programmers already know?
You can access its length to see how many children it has;
You can access the children by their index (i.e. children[i]);
You can iterate over it using for .. of;
And you can use some other nice methods provided by an Array.
Note: returning a copy of the array is out of question! It costs linear time, and any updates to the original array do not propagate to the copy!
The solution
get children() { return Object.freeze(Object.create(this._children)); }
// OR, if you deeply care about performance:
get children() {
return this._PUBLIC_children === undefined
? (this._PUBLIC_children = Object.freeze(Object.create(this._children)))
: this._PUBLIC_children;
}
Done!
Object.create: we create an object that inherits from this._children (i.e. has this._children as its __proto__). This alone solves almost the entire problem:
It's simple and fast (constant time)
You can use anything provided by the Array interface
If you modify the returned object, it does not change the original!
Object.freeze: however, the fact that you can modify the returned object BUT the changes do not affect the original array is extremely confusing for the user of the class! So, we just freeze it. If he tries to modify it, an exception is thrown (assuming strict mode) and he knows he can't (and why). It's sad no exception is thrown for myFrozenObject[x] = y if you are not in strict mode, but myFrozenObject is not modified anyway, so it's still not-so-weird.
Of course the programmer could bypass it by accessing __proto__, e.g:
someNode.children.__proto__.push(new Node());
But I like to think that in this case they actually know what they are doing and have a good reason to do so.
IMPORTANT: notice that this doesn't work so well for objects: using hasOwnProperty in the for .. in will always return false.
UPDATE: using Proxy to solve the same problem for objects
Just for completion: if you have an object instead of an Array you can still solve this problem by using Proxy. Actually, this is a generic solution that should work with any kind of element, but I recommend against (if you can avoid it) due to performance issues:
get myObject() { return Object.freeze(new Proxy(this._myObject, {})); }
This still returns an object that can't be changed, but keeps all the read-only functionality of it. If you really need, you can drop the Object.freeze and implement the required traps (set, deleteProperty, ...) in the Proxy, but that takes extra effort, and that's why the Object.freeze comes in handy with proxies.
I can think of several places that Object.freeze would come in very handy.
The first real world implementation that could use freeze is when developing an application that requires 'state' on the server to match what's in the browser. For instance, imagine you need to add in a level of permissions to your function calls. If you are working in an application there may be places where a Developer could easily change or overwrite the permission settings without even realizing it (especially if the object were being passed through by reference!). But permissions by and large can never change and error'ing when they are changed is preferred. So in this case, the permissions object could be frozen, thereby limiting developer from mistakenly 'setting' permissions erroneously. The same could be said for user-like data like a login name or email address. These things can be mistakenly or maliciously broken with bad code.
Another typical solution would be in a game loop code. There are many settings of game state that you would want to freeze to retain that the state of the game is kept in sync with the server.
Think of Object.freeze as a way to make an object as a Constant. Anytime you would want to have variable constant, you could have an object constant with freeze for similar reasons.
There are also times where you want to pass immutable objects through functions and data passing, and only allow updating the original object with setters. This can be done by cloning and freezing the object for 'getters' and only updating the original with 'setters'.
Are any of these not valid things? It can also be said that frozen objects could be more performant due to the lack of dynamic variables, but I haven't seen any proof of that yet.
The only practical use for Object.freeze is during development. For production code, there is absolutely no benefit for freezing/sealing objects.
Silly Typos
It could help you catch this very common problem during development:
if (myObject.someProp = 5) {
doSomething();
}
In strict mode, this would throw an error if myObject was frozen.
Enforce Coding Protocol / Restriction
It would also help in enforcing a certain protocol in a team, especially with new members who may not have the same coding style as everyone else.
A lot of Java guys like to add a lot of methods to objects to make JS feel more familiar. Freezing objects would prevent them from doing that.
I could see this being useful when you're working with an interactive tool. Rather than:
if ( ! obj.isFrozen() ) {
obj.x = mouse[0];
obj.y = mouse[1];
}
You could simply do:
obj.x = mouse[0];
obj.y = mouse[1];
Properties will only update if the object isn't frozen.
Don't know if this helps, but I use it to create simple enumerations. It allows me to hopefully not get duff data in a database, by knowing the source of the data has been attempted to be unchangeable without purposefully trying to break the code. From a statically typed perspective, it allows for reasoning over code construction.
All the other answers pretty much answer the question.
I just wanted to summarise everything here along with an example.
Use Object.freeze when you need utmost surety regarding its state in the future. You need to make sure that other developers or users of your code do not change internal/public properties. Alexander Mills's answer
Object.freeze has better performance since 19th June, 2019, ever since V8 v7.6 released. Philippe's answer. Also take a look at the V8 docs.
Here is what Object.freeze does, and it should clear out doubts for people who only have surface level understanding of Object.freeze.
const obj = {
name: "Fanoflix"
};
const mutateObject = (testObj) => {
testObj.name = 'Arthas' // NOT Allowed if parameter is frozen
}
obj.name = "Lich King" // Allowed
obj.age = 29; // Allowed
mutateObject(obj) // Allowed
Object.freeze(obj) // ========== Freezing obj ==========
mutateObject(obj) // passed by reference NOT Allowed
obj.name = "Illidan" // mutation NOT Allowed
obj.age = 25; // addition NOT Allowed
delete obj.name // deletion NOT Allowed

Is there a difference between localStorage.getItem('foo') and localStorage['foo'] [duplicate]

I recently asked a question about LocalStorage. Using JSON.parse(localStorage.item) and JSON.parse(localStorage['item']) weren't working to return NULL when the item hadn't been set yet.
However, JSON.parse(localStorage.getItem('item') did work. And it turns out, JSON.parse(localStorage.testObject || null) also works.
One of the comments basically said that localStorage.getItem() and localStorage.setItem() should always be preferred:
The getter and setter provide a consistent, standardised and
crossbrowser compatible way to work with the LS api and should always
be preferred over the other ways. -Christoph
I've come to like using the shorthand dot and bracket notations for localStorage, but I'm curious to know others' take on this. Is localStorage.getItem('item') better than localStorage.item or localStorage['item'] OR as long as they work are the shorthand notations okay?
Both direct property access (localStorage.foo or localStorage['foo']) and using the functional interface (localStorage.getItem('foo')) work fine. Both are standard and cross-browser compatible.* According to the spec:
The supported property names on a Storage object are the keys of each key/value pair currently present in the list associated with the object, in the order that the keys were last added to the storage area.
They just behave differently when no key/value pair is found with the requested name. For example, if key 'foo' does not exist, var a = localStorage.foo; will result in a being undefined, while var a = localStorage.getItem('foo'); will result in a having the value null. As you have discovered, undefined and null are not interchangeable in JavaScript. :)
EDIT: As Christoph points out in his answer, the functional interface is the only way to reliably store and retrieve values under keys equal to the predefined properties of localStorage. (There are six of these: length, key, setItem, getItem, removeItem, and clear.) So, for instance, the following will always work:
localStorage.setItem('length', 2);
console.log(localStorage.getItem('length'));
Note in particular that the first statement will not affect the property localStorage.length (except perhaps incrementing it if there was no key 'length' already in localStorage). In this respect, the spec seems to be internally inconsistent.
However, the following will probably not do what you want:
localStorage.length = 2;
console.log(localStorage.length);
Interestingly, the first is a no-op in Chrome, but is synonymous with the functional call in Firefox. The second will always log the number of keys present in localStorage.
* This is true for browsers that support web storage in the first place. (This includes pretty much all modern desktop and mobile browsers.) For environments that simulate local storage using cookies or other techniques, the behavior depends on the shim that is used. Several polyfills for localStorage can be found here.
The question is already quite old, but since I have been quoted in the question, I think I should say two words about my statement.
The Storage Object is rather special, it's an object, which provides access to a list of key/value pairs. Thus it's not an ordinary object or array.
For example it has the length attribute, which unlike the array length attribute is readonly and returns the number of keys in the storage.
With an array you can do:
var a = [1,2,3,4];
a.length // => 4
a.length = 2;
a // => [1,2]
Here we have the first reason to use the getters/setters. What if you want to set an item called length?
localStorage.length = "foo";
localStorage.length // => 0
localStorage.setItem("length","foo");
// the "length" key is now only accessable via the getter method:
localStorage.length // => 1
localStorage.getItem("length") // => "foo"
With other members of the Storage object it's even more critical, since they are writable and you can accidently overwrite methods like getItem. Using the API methods prevents any of these possible problems and provides a consistent Interface.
Also interesting point is the following paragraph in the spec (emphasized by me):
The setItem() and removeItem() methods must be atomic with respect to failure. In the case of failure, the method does nothing. That is, changes to the data storage area must either be successful, or the data storage area must not be changed at all.
Theoretically there should be no difference between the getters/setters and the [] access, but you never know...
I know it's an old post but since nobody actually mentioned performance I set up some JsPerf tests to benchmark it and as well as being a coherent interface getItem and setItem are also consistently faster than using dot notation or brackets as well as being much easier to read.
Here are my tests on JsPerf
As it was mentioned, there is almost no difference except of nonexisting key. The difference in performance varies depending on what browser/OS are you using. But it is not really that different.
I suggest you to use standard interface, just because it is a recommended way of using it.

Where does the variable holding an element with an id get stored?

This question ( Element accessible with ID ) points out that if an element has an id then you can access it by variable name based on that id. It intrigued me, as I had seen this variable available when developing using Visual Studio 2010. I did some testing out of curiosity and it turns out that document.getElementById() was still faster than using the variable name. So, I began trying to look through the window, figuring it must be in window["idName"], in debug, and with console.log(window) and could not find where the variable was actually stored.
When an element is defined in html with <div id="foo"> it is available in javascript with the variable foo (I am not suggesting to use this, it is bad practice). Where is that variable stored?
This is non-standard behavior. Where (and if) it is stored is up to the implementation.
Using Firefox 15 on Linux, I had to go 2 prototype objects deep to find the actual object. I ran this code on this StackOverflow page, and got a true result.
Object.getPrototypeOf(Object.getPrototypeOf(window)).hasOwnProperty("hlogo");
In Chrome on Linux, it was one level deep.
Object.getPrototypeOf(window).hasOwnProperty("hlogo");
I was actually surprised to see it in Firefox, but since Chrome followed the Microsoft pattern, I guess Firefox must have felt the need to follow suit.
If you don't know how deep a prototype chain is, you can run a loop, and add the different objects to an Array, or just work with the objects in the loop.
var protos = [],
obj = window;
while (Object.getPrototypeOf(obj) !== null) {
obj = Object.getPrototypeOf(obj);
protos.push(obj);
}
alert("The object had " + protos.length + " prototype objects");

Why doesn't my object inherit the keys functions?

If I have an object:
A = {a:true}
Why do I have to use:
Object.keys(A)
and not:
A.keys()
If keys is a method of Object, and everything inherits from Object, shouldn't A be able to call keys?
Object.keys is a so-to-say "static" method attached strictly to the Object function, not to its instances.
For it to be inherited, it would need to be defined as Object.prototype.keys.
You can certainly add it yourself if you so desire:
Object.prototype.keys = function () {
return Object.keys(this);
};
Just note, as Rocket mentioned in the comments, "own" properties take precedence over prototype properties:
var foo = {};
foo.keys(); // Array of enumerable key names, if any
var bar = { keys: true };
bar.keys(); // TypeError: not a function
The real answer is "because that's how the ES committee members designed it." But specifically, the second comment on your original question (by #RobW) is exactly what they wanted to avoid.
Moreover, I would ask that you remove the "accepted answer" designation from #JonathonLonowski's answer, because he is clearly giving (and avidly but unwisely defending) advice (modifying built-in prototype's) which most of the web community knows to be of poor form. The ONLY time when it's OK to modify a built-in's prototype is when you are absolutely certain that no other code will trip over it... the only time that is true is you write 100% of all code that runs (or ever will run) on a page. The number of times that is true is so low that this advice is considered not-good-practice.

Categories