I'm working on an application framework written as an object literal and for the sake of simplicity I'd like to do two things:
Have the object available globally
Use the object name (as globally defined) for all references (vs. using this)
So, I've run some tests, done research, and am not finding any good reason NOT to take this approach. My question is - am I missing something? Perf tests actually seem to favor my method and from a logistical level I don't see any issues. Looking at other frameworks I've seen a mix, but I know that the this reference is revered by many programmers.
For reference...
A very minimal example of my approach:
var myobj = {
someVal: 'foo',
init: function(){
// Make myobj available globally
window.myobj = myobj;
// Fire off a method
myobj.doStuff();
},
doStuff: function(){
// Just print out the contents...
console.log(myobj.someVal);
}
}
myobj.init();
Note the references are all to the global, not this.
Like I said, I've seen a mix of this, I guess I just would like to know if this could cause issues in the long-run or if this a much ado about nothing.
As far as limitations go, the first thing that comes to mind is that you could only have one instance of this object. Trying to initialize a new one would wipe out the object.
Another reason for using this rather than a global variable name is that this will point to the correct object even if the name of the variable changes.
If you really want this to be a "create once" global object whose name never changes then this technique isn't technically wrong. But it won't be able to be used in any other situation. It is probably wiser to consider writing code that will be more adaptable if the requirements change (for instance if you use a library that causes a naming conflict with the chosen variable name)
Using this lets you be flexible in renaming the variable and passing it in different contexts without worrying about tracking variable names. It also will make it easy to change if naming conflicts arise.
Related
I've read a number of questions that state it is unwise to add properties to DOM element objects; and they seem to make a great deal of sense. The best suggestion I came across to accomplish the same end was to use a Weak Map with the DOM node reference as the key.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
That brings up a related matter I've been trying to understand which is that some claim that the window object is so cluttered up that it ought not to be added to and scripts should be modules now. Modules appears to be more isolated than my limited experience with simple namespaces. Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object? That object would still be added to the window object.
Thank you.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
It's not safe in that, if you do it, others could do it too. For example:
// Your code
RegExp.description = 'some description for the constructor!';
setTimeout(() => {
console.log(RegExp.description);
});
// Someone else's code
RegExp.description = "someone else's description";
The only consolation is that it's pretty unlikely for such a thing to happen.
Similarly, it's pretty unlikely for some random English word that one library creates for itself on the window collides with another word that another library creates for itself on the window - but it's not impossible. For that reason
That object would still be added to the window object.
can be seen as slightly less than optimal on huge pages, where collisions are a real possibility.
Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object?
Yes, see above. If all of your code is in module scripts, there should be no need to put any object onto the window, in most cases. In addition to the above, module scripts often make projects easier to manage because they make all dependencies explicit through the use of import statements. They're also very easily integrated into a build process like Webpack - and build processes allow for all sorts of neat things that aren't easily done otherwise.
This is along the same lines as the question titled "Capturing Nashorn's Global Variables". I'm finding it very limiting not being able to intercept the assignment of variables to the global object.
For instance, say I eval the script "a = 10". Perhaps I want to call a listener to notify something that 'a' was added to the scope. The only way I could do this is to investigate the global object after the script is eval'd.
Or say i want to intercept an object being assigned to the global scope and substitute it for another; if it was using Bindings I could implement put, and delegate off to some other bindings:
public Object put(String name, Object value) {
//put a toStringed version of the object in scope
return delegate.put(name, value+"");
}
This way, when the code 'a=10' is evalled, it would put "10" in scope instead of 10.
It's handy having a Bindings interface to implement, but frustrating that I can't provide something like this implementation for the global object. ScriptObjectMirror is final, so I can't even overload this and hijack the subsequent call to the internal ScriptObject. Am I missing something?
So basically what you want to do is to intercept/trap assignments to arbitrary properties on some object. In your case, the global object.
Afaik, this was never really possible without some pretty hacky code indeed. A search for 'observables javascript' might help you with that, but be warned that you'll get into some muddy territory.
If this is meant for testing (as opposed to production code), a setTimeout / setInterval with some listener that periodically enumerates all properties of the global object and logs a warning if one was added might be good enough for you.
In the future, we'll have the Javascript Proxy standard to help us with this but I seriously doubt it is there yet in Nashorn. It's been a while since I worked with Nashorn but after the initial burst on the scene it has been quiet on the Nashorn front afaict...
are there any specific disadvantages of defining a global function, as there are for defining global variables?
We are trying to downsize our custom JS file, and quite a bit of code is being used across functionalities.
Namespace collisions are one big issue. If you create a global function, and accidentally use the same name as another global function, you will overwrite that function, which may cause your application to break.
Bear in mind that all global variables are actually properties of the window object. If you accidentally overwrite a built-in property of window, you might produce some really odd glitches that can be hard to track down.
Another reason is just general cleanliness/organization. If you write a dozen functions to do operations on strings, you might want to put them all on an object stringOps, so that you've got them in one place.
The main danger with global references are that you will step on someone elses reference or vice versa. This can make testing extremely difficult as you may have introduced a large dose of non-determinism.
For instance say you define Global.PI as 3.14159 and your functions which ref that work fine, until a user loads a page with a library that defines Global.PI as 'Lemon', now your functions work not quite as expected.
The project I work on has global references due to the strucutre of our application.
To alleviate some of these issues we will attach a single object to window (window.yourObjHere) and place our global references within that object.
The only advantage to Globals are that some things simply can't be done without them. We have an eventBus that must message over seperate AngularJS applications. As the AngularJS native eventBus is per application, we have to register each application on our GLobal object in order to keep track of where messages should go etc. Whenver possible avoid using Globals but there are simply some things which can't be done without them. Just be careful and limit your Global footprint.
The disadvantages are as poeple ahve outlined (basically no namespacing meaning functions/variables can be overwritten) but you could get around this by declaring a global object which has all you need in it - and you can add things to it 'on the fly' :
GLOBAL_myObject = {
variableOne: 1,
variableTwo: "A atring",
getThisAndThat: function(p1,p2) {
//do some stuff
return p1 * p2; /or somthing
}
};
So refer to all your own variables as a property of that object:
alert(GLOBAL_myObject.variableOne);
GLOBAL_myObject.getThisAndThat(1,2);
Effectively you're just namespacing the variables.
to add more to the global GLOBAL_myObject you can just declare it ..
GLOBAL_myObject.anotherThing=1965; // what a year!
I am learning about object/method chaining in JavaScript and I would like make sure I understand it correctly.
If the following code is an example of JavaScript without object chaining:
var people = helper.getPeople();
var bob = people.find("bob");
var email = bob.getEmail();
and the code below is after applying object chaining:
var email = helper.getPeople().find("bob").getEmail();
Am I to consider object chaining as simply a way to "drill down" into an object, reaching "sub-objects" or properties/methods etc...?
If these two examples of code are supposed to do the same thing, why is a var declaration not required in the object-chained example? I do not understand how the chained statement is the same if no new variables are declared in the process.
I can see the value of saving space and writing the code on one line, and all my research online has shown that this is considered an intuitive, simplified way to write. However, I feel that I am able to read the first example (without object chaining) better. That may just be because I am new to JavaScript, but which example would be considered good coding practice?
Additionally, is the purpose of object chaining merely to reach objects that are not defined in the global scope? A way of reaching local objects?
Thank you for your help!
Am I to consider object chaining as simply a way to "drill down" into an object, reaching "sub-objects" or properties/methods etc...? Is the purpose of object chaining merely to reach objects that are not defined in the global scope? A way of reaching local objects?
It could be. Every of these methods does return another object with methods, that's the secret of chaining. "Drilling down" might be an appropriate wording for some uses, like the one you've shown, where different objects are returned.
However, whether these returned objects are hidden, local "sub-objects", accessible through other means or just created on the fly by that method, or even the original object that returns itself, is dependent on the methods and API design. All options make valid chaining, though.
If these two examples of code are supposed to do the same thing, why is a var declaration not required in the object-chained example? I do not understand how the chained statement is the same if no new variables are declared in the process.
Returning objects that are immediately accessed does not require them to be assigned to any variable. They of course are held in memory somewhere, but don't have an explicit identifier attached to them.
That may just be because I am new to JavaScript, but which example would be considered good coding practice?
Depends. Usually, a good practise is not to create variables if you don't need them. If you are only interested in the email and won't access all the people and bob again, there's no reason to create variables for them.
The readability can be increased by putting each method call on a new line, which is common in JS for chaining:
var email = helper.getPeople()
.find("bob")
.getEmail();
(with various styles of indentation for the subsequent lines)
I was looking over the code for qunit.
My question is why would you want to attach the qunit object via property to window object.
Here is the link to the file. Look at line 11.
If I look at a unit test run using firebug you can see it is a property of window.
[edit]
Additional: Is there a specific reference for best practice for declaring things in specific namespaces?
All global objects (functions, variables, etc) are just children of window, it's the default context.
For example: window.jQuery or window.$
It may be easier to think of it this way...where else would you put them? When you're doing something this general, best (or at least easiest) to stick them in the default place. If you're doing something complex with lots of functions, objects, etc...best to put them in a namespace or within an object. For example all of jQuery's code is under jQuery, not littered in the root of the DOM like window.ajax, instead it's jQuery.ajax.
This is much neater, but perhaps overkill when you're dealing with a few items, but it's a good idea to make sure they are unique if this is the case...which qunit does, by prefixing their objects with qunit-
Attaching globals as properties of window is bad practice. All globals should be declared using var. Here's my reasons:
It makes static analysis of source code much harder. It is impossible to tell from looking at a script which globals will be declared and when. Undeclared globals will create ReferenceErrors if they're used. Using var means JavaScript's hoisting takes effect, and mitigates this problem.
Globals made this way are fundamentally different, and there is no easy way for your code to detect this. The biggest difference is the absence of [[DontDelete]] on globals made this way, which means you can delete your global variables. This is silly.
It will tempt you to declare your globals from outside the global scope. This is magic, and bad magic at that. Don't do it.
As far as I'm concerned, the fact that window.x = 1 creates a global variable named x is an interesting curiosity of JavaScript, but should not be used nor replied upon. There are, however, good reasons to use properties of window, since it's an object like any other (more or less). In these cases, you should use the full name, e.g. window.onload instead of just onload.