Let's have the following html:
<input id="txt" type="text" />
Now, in javascript, I can access its value by these following methods.
var value = txt.value;
var value = document.getElementById('txt').value;
So, is there any difference between them?
First, consider what happens when someone look at the code written like this:
var value = txt.value;
There's exactly ZERO hint here that txt is actually 1) a global variable; 2) a DOM Element. Unless one scans the whole scope of a function (that means the function itself, the parent function it's defined in, its own parent etc. ... right till the outmost - global - scope). That means to understand the code, one has to check its whereabouts. Apparently that doesn't make the code nice to work with.
To illustrate this, consider what happens here:
function someAsyncFunc() {
var txt = 'someText';
// some lines of code
someAsyncAction(function() {
var value = txt.value;
});
}
Here we have a function used as a callback in some asynchronous action. Technically, it doesn't have txt as a local variable to this specific function - but reference to a global variable is still shadowed by txt defined in its parent. The point is, it's way too easy to introduce subtle - yet very nasty - bugs by this potential clash of names.
That's for theory and reasoning, now about cross-platform practice. The whole idea of injecting the DOM Elements into the global scope (by making namespace resolver scan both window and document) for many years was considered, well, a bad idea - a shortcut that'll save you a couple of keystrokes when you write the code, but will more than compensate when someone (or you 6 months after) will debug the code. That's why, I suppose, Gecko engine didn't make such an injection in the standards mode - only in quirks.
Still, this idea has made its way in HTML5 Standard:
*Named objects [...] are those that are either:
a, applet, area, embed, form, frameset, img, or object elements that have a name content attribute whose value is name, or
HTML elements that have an id content attribute whose value is name.
There was a lengthy discussion about the correctness of such approach - which ultimately resulted in the approach staying as is. And the key reason was given by MS reps:
Our data suggests that making this quirks only would break a large
number of web sites.
Yes, yet another victory for the bad practice used so often that it became a common practice. That's why Firefox 14+ supports this 'feature' as well. Still, the mere support of it doesn't make it right.
Related
I recently came across a JavaScript script, in which the author seemed to try to avoid strings inside his code and assigned everything to a variable.
So instead of
document.addEventListener('click', (e) => { /*whatever*/ });
he would write
var doc = document;
var click = 'click';
var EventListener = 'EventListener';
var addEventListener = `add${EventListener}`;
doc[addEventListener](click, (e) => { /*whatever*/ });
While caching document into a variable can be regarded a micro optimization, I am really wondering if there is any other benefit of this practice in general - testability, speed, maintenance, anything?
Legacy IE attachEvent should be pretty much dead, so being able to quickly make the script only run in these environments can hardly be regarded an advantage I suppose.
The example you give looks pretty strange, and I can't imagine any "good practice" reason for most of those moves. My first guess was that it's the work of someone who wasn't sure what they were doing, although it's odd that they'd also be using ECMAScript 6 syntax.
Another possibility is that this is generated code (e.g. the output of some kind of visual programming tool, or a de-minifier). In that situation it's common to see this sort of excessive factoring because the code is generated from templates that are conservatively written to guard against errors; I'm thinking of the way preprocessor macros in C make liberal use of parentheses.
Sometimes variable declarations are written in a way that makes clear (to the compiler and/or the reader) what type of data the variable holds. For instance, asm.js code uses unnecessary-looking variable declarations as a trick to implement strongly-typed variables on top of regular JS. And sometimes declarations are written as a form of documentation (if you see var foo = Math.PI * 0, that's probably there to tell you that foo is an angle in radians, since otherwise the author would have just written var foo = 0.0). But that still wouldn't explain something like var click='click'.
First of all i know that:
Use of the with statement is not recommended, as it may be the source
of confusing bugs and compatibility issues. See the "Ambiguity Con"
paragraph in the "Description" section below for details.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
BUT
If we take a simple function like this (THIS FUNCTION WORKS GREAT)
function loadImage(url,cb){
with(new Image)
onload=cb,
src=url
}
we notice there is nothing CONFUSING that could break the code inside the function closures. the only 2 variables we use are onload & src. Until i don't create variables, objects,arrays or functions that i name onload or src nothing bad should happen.
Said that, my question is:
The javascript garbage collector should add the new Image to the collection directly after been executed ?
And so have less impact to the memory vs a standard function:
function loadImage(url,cb){
var image=new Image;
image.onload=cb;
image.src=url;
}
In the above case the var image remains inside the function until i execute a new one.
btw. also the code would be much shorter.
// preload a image
function loadImage(a,b){with(new Image)onload=b,src=a}
// convert a file to base64
function readFile(a,b){with(new FileReader)onload=b,readAsDataURL(a)}
A demo to play with
http://jsfiddle.net/5wqm3/4/
First of all i know that: Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues
No, the main issue with the with statement is that it prevents certain static optimisations as it introduces new variable names at runtime. That's also the reason why it was forbidden in ES 5 strict mode code.
Using the with statement should have less impact to the memory vs a standard function
No. They perform exactly the same. When the function ends, the new Image/image is no more in scope of anything. The image variable will be gone in the same way as the with statement ends with a closing brace.
The javascript garbage collector should add the new Image to the collection directly after been executed?
Actually, I don't think the object is garbage-collected. It's a DOM element with an alive load handler waiting for it, I would assume it is still referenced from the event loop queue. However, that doesn't really matter for your question I think.
What's the point of document.defaultView?
MDN says:
In browsers returns the window object associated with the document or null if none available.
Code like the following (from PPK's site) makes use of document.defaultView:
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
return y;
}
Code like this can be found in other places, like David Mark's My Library. I'm not sure if people are just copying from PPK or some other source or coming up with this independently, but I don't understand it.
My question is, what is the point of using document.defaultView in cases like this? Wouldn't it be easier to write this as follows:
function getStyle(element, styleProp) {
if (element === ''+element) element = document.getElementById(element);
return element.currentStyle ? element.currentStyle[styleProp] :
getComputedStyle(x,null).getPropertyValue(styleProp);
}
What does document.defaultView.getComputedStyle do that window.getComputedStyle or simply getComputedStyle does not?
cwolves' answer got me thinking in the right direction. The original function is silly, missing the point of defaultView. My proposal above is less silly, but also missing the point of defaultView. Here's my new proposal:
function getStyle(element, styleProp) {
var view = element.ownerDocument && element.ownerDocument.defaultView ?
element.ownerDocument.defaultView : window;
return view.getComputedStyle ?
view.getComputedStyle(element,null).getPropertyValue(styleProp) :
element.currentStyle ?
element.currentStyle[styleProp] : null;
}
The element itself must be passed in, not the id. I think this is probably to be preferred anyway. This gets the document containing the node, and the window associated with it. It has a fallback to the current window's getComputedStyle if ownerDocument or defaultView are broken (I vaguely remember getComputedStyle being around before defaultView). This is probably closer to the intended use of defaultView.
The OP asks the question, "What's the point of document.defaultView", and the answer really doesn't have anything to do with getComputedStyle. The document.defaultView property is simply a way of obtaining the window object if one has a reference to the document object contained in that window. There are cases where the window object you are seeking to reference (or defaultView) is not in the same window scope as the code you are running.
One example of this is if you have a reference to the document object in an iframe, and wish to conveniently get a reference to the window object of that iframe.
Another case might be where you are running in privileged context in the browser scope (eg, chrome code in Firefox), and you happen to have a reference to the document object of a tabbrowser, or another window.
Or, as Dagg Nabbit points out, if in any of these cases you have a reference to an element within the window, you could access the parent window of that element through element.ownerDocument.defaultView
I'm not positive on this, but I imagine that it's the result of fixing a bug from either trying to run code on a detached document (i.e. something that exists in memory but is not in the page) or trying to run on a document in a different window (e.g. an iframe or a popup).
According to your quote, when document.defaultView is run on a document that is NOT the current document, you will get the associated window object, thus document.documentView.getComputedStyle !== getComputedStyle since they are in different contexts.
In short, I believe it's akin to document.window which doesn't exist.
It is simply an abstraction as far as I can tell, just in case any user agents pop up with a DOM implementation, but don't provide a view in the form of a window. See Views in DOM level 2.
According to MDN getComputedStyle article,
In many code samples online, getComputedStyle is used from the
document.defaultView object.
In nearly all cases, this is needless, as
getComputedStyle exists on the window object as well.
It's likely the
defaultView pattern was some combination of
folks not wanting to write a spec for window and
making an API that was also usable in Java.
However, there is a single case where the defaultView's method
must be used: when using Firefox 3.6 to access framed styles.
I'm using John Resig's recipe for JavaScript 'classes' and inheritance. I've stripped my code back to something like this for this question:
MyClass = Class.extend({
// create an <h3>Hello world!</h3> in the HTML document
init : function (divId) {
this._divId = divId;
this._textDiv = document.createElement("h3");
this._textDiv.innerHTML = "Hello world!";
document.getElementById(divId).appendChild(this._textDiv);
},
// remove the <h3> and delete this object
remove : function () {
var container = document.getElementById(this._divId);
container.parentNode.removeChild(container);
// can I put some code here to release this object?
}
});
All works well:
var widget = new MyClass("theDivId");
...
widget.remove();
I'm going to have hundreds of these things on a page (obviously with some sensible functionality) and I'd like a simple way to release the memory for each object. I understand I can use widget = null; and trust the GC releases the object when required (?), but can I do something explicit in the remove() method? I know that placing this = null; at the end of remove() doesn't work ;)
there is no ways to destroy objects manually, only way is to free all links to your object and trust removal to GC
actually in your code you should clear this._textDiv = null and container = null in remove method too, because it can be a problem for GC in some browsers
No. You don't have any way of accessing the garbage collector directly. As you say, the best you can do is make sure the object is no longer referenced.
IMO, it's better that way. The garbage collector is much smarter than you (and me) because years of research has gone into writing the thing, and even when you try and make optimisations, you're likely still not doing a better job than it would.
Of course if you're interfacing with a JS engine you will be able to control the execution and force garbage collection (among much more), although I very much doubt you're in that position. If you're interested, download and compile spider monkey (or v8, or whatever engine tickles your fancy), and in the repl I think its gc() for both.
That brings me to another point, since the standard doesn't define the internals of garbage collection, even if you manage to determine that invoking the gc at some point in your code is helpful, it's likely that that will not reap the same benefits across all platforms.
this is a keyword, to which you cannot assign any value. The only way to remove objects from a scope is to manually assign nullto every variable.
This method doesn't always work, however: In some implementations of the XMLHttpRequest, one has to reset the onreadystate and open functions, before the XMLHttpRequest object is freed from the memory.
I prefer to declare one Javascript file for my all website. I am trying to decrease the usage of global variables. My examples at the below, in both case each object has a myName field.
I would like to know when they are initialized?
And In terms of memory and efficiency which one is more effective?
For variable a, is declaring a.myName the same as global "var myName = Rebecca" ?
var a = {
myName : 'Rebecca' ,
sayHello : function() {
console.log(this.myName);
}
};
var b = {
myName : function() {
return 'Rebecca';
},
sayHello : function() {
console.log(this.myName());
}
};
Thanks
I believe these will be initialized identically (i.e. when the code is reached). What's different is what's happening when they are initialized and where the load is placed when their data is actually required.
To me, it would depend a lot on what you were expecting to have in myName. If it were just a string, I'd avoid the function and go with choice a. On the other hand, if there were a great deal of logic involved and that logic might not need to be invoked (for example, if it only gets executed when a user clicks on a button or the application reaches a certain state), I'd go with choice b. As I understand it, the function does consume memory and won't get garbage collected (which is a minus), but it also won't consume CPU resources until it's actually needed (which can be a huge plus).
I'm not sure I understand the question, but I'd say it's not the same. If the only member of a is myName then the two are equivalent (both are occupying the global namespace. But if you have multiple properties, the savings become obvious. From your examples, I think it's clear you understand this, so again I may not understand the question.
They will be initialized when the statements are first encountered. In a, 'Rebecca' is initialized as the value for the myName key. In b, it's just data internal to the myName (anonymous) function. a will be slightly more efficient because it avoids a function call. I also find it more readable in this simple example.
I find the choice to put everything in a single file questionable. In some cases, you want a modular design. And since you're worried about efficiency (albeit perhaps prematurely), note that having one big file can actually hurt performance if pages include code they don't need.
1) They are initialized when the script is processed in the browser, unless you declare the objects in an event handler. In that case the object is created when the event script is executed.
2) In terms of efficiency, a will probably be more efficient. Note though that in the first case you use a.myName and in the second b.myName() to get the value of the property.
3) No. If you assign a value to a property of an object, you always have to get that value through the object. In this case either a.myName or a['myName'].
a doesn't make any sense, because you're logging a function reference. B is the way to go, since you're actually invoking the method, using ().