Getting value from object vs getting value from global value - javascript

I know this is premature optimization but I am just curious to know
how long does it take to get the value of this
var objects =
{
number:10
}
console.log(""+objects.number);
VS
var number = 10;
console.log("" + number);
I just do not know how to benchmark so if I knew I would do it myself but if this is a really bad question please do not -rep me, just tell me and I'll remove the question

The results are intensely varying.
See this test: http://jsperf.com/property-vs-plain-variable
Run it many times, you can see the results orbit around, without a definitive result (at least on Firefox). Sometimes accessing a variable is slower than accessing the object's property directly, I think you can assume there is no real difference.

Using local values is faster than getting objects value
http://jsperf.com/comparing-speed-of-getting-var-in-javascript

Related

Detecting when any variable in a large JS program is set to NaN

I have a large, messy JS codebase. Sometimes, when the app is being used, a variable is set to NaN. Because x = 2 + NaN results in x being set to NaN, the NaN it spreads virally. At some point, after it has spread pretty far, the user notices that there are NaNs all over the place and shit generally doesn't work anymore. From this state, it is very difficult for me to backtrack and identify the source of the NaN (and there could very well be multiple sources).
The NaN bug is also not easily reproducible. Despite hundreds of people observing it and reporting it to me, nobody can tell me a set of steps that lead to the appearance of NaNs. Maybe it is a rare race condition or something. But it's definitely rare and of uncertain origins.
How can I fix this bug? Any ideas?
Two stupid ideas I've thought of, which may not be feasible:
Write some kind of pre-processor that inserts isNaN checks before every time any variable is used and logs the first occurrence of NaN. I don't think this has been done before and I don't know how hard it would be. Any advice would be appreciated.
Run my code in a JS engine that has the ability to set a breakpoint any time any variable is set to NaN. I don't think anything does this out of the box, but how hard would it be to add it to Firefox or Chrome?
I feel like I must not be the first person to have this type of problem, but I can't find anyone else talking about it.
There is probably no solution for your problem aka: break, whenever any variable is set to NaN. Instead, you could try to observe your variables like this:
It was earlier stated, that the Chrome debugger offers conditional breakpoints. But, it also supports to watch expressions. In the Watch-Expressions menu you can set a condition to break, whenever the variable is set to a specific value.
Object.observe is a method that observes changes on a object. You are able to listen to all changes on the object, and call debug when any variable is set to NaN. For example, you could observe all change on the window object. Whenever any variable on the window object is set to NaN, you call debug. Please note, that Object.observe is quite cutting edge and not supported by all browsers (check out the polyfill in this case).
Take this opportunity to write a test case for every function in your code. Perform random testing and find the line of code that can create NaN values.
Another problem of yours is probably how to reproduce this error. Reloading your webpage over and over doesn't make too much sense. You could check out a so called headless browser: It starts an instance of a browser without displaying it. It can be leveraged to perform automatic tests on the website, click some buttons, do some stuff. Maybe you can script it in such a way that it finally reproduces your error. This has the advantage that you don't have to reload your webpage hundreds of times. There are several implementations for headless browsers. PhantomJS is really nice, in my opinion. You can also start a Chrome Debug Console with it (you need some plugin: remote debugger).
Furthermore, please notice that NaN is never equal to NaN. It would be a pity if you finally are able to reproduce the error, but your breakpoints don't work.
If you're doing a good job keeping things off of the global namespace and nesting things in objects, this might be of help. And I will preface this by saying this is by no means a fully complete solution, but at the very least, this should help you on your search.
function deepNaNWatch(objectToWatch) {
'use strict';
// Setting this to true will check object literals for NaN
// For example: obj.example = { myVar : NaN };
// This will, however, cost even more performance
var configCheckObjectLiterals = true;
var observeAllChildren = function observeAllChildren(parentObject) {
for (var key in parentObject) {
if (parentObject.hasOwnProperty(key)) {
var childObject = parentObject[key];
examineObject(childObject);
}
}
};
var examineObject = function examineObject(obj) {
var objectType = typeof obj;
if (objectType === 'object' || objectType === 'function') {
Object.observe(obj, recursiveWatcher);
if (configCheckObjectLiterals) {
observeAllChildren(obj);
}
} if (objectType === 'number' && isNaN(obj)) {
console.log('A wild NaN appears!');
}
};
var recursiveWatcher = function recursiveWatcher(changes) {
var changeInfo = changes[0];
var changedObject = changeInfo.object[changeInfo.name];
examineObject(changedObject);
};
Object.observe(objectToWatch, recursiveWatcher);
}
Call deepNaNWatch(parentObject) for every top level object/function you're using to nest things under as soon as they are created. Any time an object or function is created within a watched object/function, it itself will become watched as well. Any time a number is created or changed under a watched object--remember that typeof NaN == 'number'--it will check if it's NaN, and if so will run the code at console.log('A wild NaN appears!');. Be sure to change that to whatever sort of debugging output you feel will help.
This function would be more helpful if someone could find a way to force it onto the global object, but every attempt I made to do so simply told me I should sit in time out and think about what I've done.
Oh, and if it's not obvious from the above, on a large scale project, this function is bound to make pesky features like "speed" and "efficiency" a thing of the past.
Are your code communicate with your server side, or it is only client side?
You mention that it is rare problem, therfore it may happend only in some browsers (or browsers version) or on any situation which may be hard to reproduce. If we assume that any appearance of nan is problem, and that when it happend user notice bug ("there are NaNs all over the place"), then instead display popup with error, error should contain first occurence of nan (then users may raport it "Despite hundreds of people observing it and reporting it to me"). Or not show it, but send it to server. To do that write simple function which take as agument only one variable and check if variable is NaN,. Put it in your code in sensitive places (sensitive variables). And this raports maybe solate problematic code. I know that this is very dirty, but it can help.
One of your math functions is failing. I have used Number(variable) to correct this problem before. Here is an example:
test3 = Number(test2+test1) even if test1 and test2 appear to be numbers
Yeah man race conditions can be a pain, sounds like what it may be.
Debugging to the source is definitely going to be the way to go with this.
My suggestion would be to setup some functional testing with a focus on where these have been reproduced, set some test conditions with varied timeouts or such and just rerun it until it catches it. Set up some logging process to see that backtrace if possible.
What does your stack look like? I can't give too much analysis without looking at your code but since its javascript you should be able to make use of the browser's dev tools I assume?
If you know locations where the NaNs propagate to, you could try to use program slicing to narrow down the other program statements that influence that value (through control and data dependences). These tools are usually non-trivial to set up, however, so I would try the Object.observe-style answers others are giving first.
You might try WALA from IBM. It's written in Java, but has a Javascript frontend. You can find information on slicer on the wiki.
Basically, if the tool is working you will give it a program point (statement) and it will give you a set of statements that the starting point is (transitively) control- and/or data-dependent on. If you know multiple "infected" points and suspect a single source, you could use the intersection of their slices to narrow down the list (the slice of a program point can often be a very large set of statements).
(was too long for a comment)
While testing you could overwrite ALL Math functions to check if an NaN is being produced.
This will not catch
a = 'string' + 1;
but will catch things like
a = Math.cos('string');
a = Math.cos(Infinity);
a = Math.sqrt(-1);
a = Math.max(NaN, 1);
...
Example:
for(var n Object.getOwnPropertyNames(Math)){
if (typeof Math[n] === 'function') Math[n] = wrap(Math[n]);
}
function wrap(fn){
return function(){
var res = fn.apply(this, arguments);
if (isNaN(res)) throw new Error('NaN found!')/*or debugger*/;
return res;
};
}
I didn't tested, maybe an explicit list of the "wrap"ed methods is better.
BTW, you should not put this into production code.

Pitfalls using DOM-Javascript VS pure Javascript objects?

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.

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");

Wrong value in console.log [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Chrome's JavaScript console lazy about evaluating arrays?
I have the following snippets in javascript whose output makes me feel that something is going wrong.
1.
a=2;
console.log(a);
a+=2;
console.log(a);
Output:2 4 ; as expected
2.
t=[0,2];
console.log(t);
t[0]+=2;
console.log(t);
Output: [2,2] [2,2]
Shouldn't the output be [0,2] [2,2] ? And whats the difference between the above two cases that results in the different answers in both the cases?
It's because the log is delayed until Chrome has time to do it (i.e. your scripts releases the CPU).
Try this to understand what happens :
var t=[0,2];
console.log(t);
setTimeout(function() {
t[0]+=2;
console.log(t);
}, 1000);
It outputs what you expect.
Is that a bug of Chrome ? Maybe a side effect of an optimization. At least it's a dangerous design...
Why is there a difference ? I suppose Chrome stores temporarily what it must log, as a primary (immutable) value in the first case, as a pointer to the array in the last case.
console.log in chrome/ff is asynchronous and objects that are logged are interpreted at the time when they're expanded. . Instead make a copy of the object if you want to see its value at that time (for an array):
t=[0,2];
console.log(t.slice(0));
t[0]+=2;
console.log(t);
With an array, calling .slice will duplicate the array and not create a reference.
I wouldn't suggest using a time out: this really doesn't solve the problem, just circumvents it temporarily.
Everything you're doing is right, but chrome's logging is screwy/delayed. Try making a copy of the variable and adding to that and you'll see that your code is correct.
Chrome's logging is delayed in the newer versions, no problem from your end. Make a copy of the variable or use setTimeout.

Categories