Can I add attributes to 'window' object in javascript? - javascript

Can I add any random attribute to 'window' object in javascript? Some thing like:
window.my_own_attr = "my_value"
Does it have any side effects with any libraries? And is it cross-browser compatible?

Can I add any random attribute to 'window' object in javascript?
Yes, just like you've shown.
Does it have any side effects with any libraries?
No, not unless you use a library which sets a property you then overwrite.
And is it cross-browser compatible?
Yes, completely.
Having said that, this practice is generally frowned upon. You could end up overwriting something you don't want to.

In all browsers, window is the javascript global namespace. Every property or method 'lives' in that namespace. So if you assign a property to window, it is in effect a global variable.
example:
window.myConstant = 5;
// note: a var declaration will be a window property too
// note 2: 'let' or 'const' will not be window properties
// below can also be done without 'var'.
var myConstantGlobal = 4;
console.log(`multiply(10) => ${multiply(10)}`);
console.log(`multiply() => ${multiply()}`);
console.log(`multiplyGlobalVar(10)) => ${multiplyGlobalVar(10)}`);
console.log(`multiplyGlobalVar() => ${multiplyGlobalVar()}`);
function multiply(val){
return myConstant * (val || 1);
}
function multiplyGlobalVar(val){
return window.myConstantGlobal * (val || 1);
}
You have to be cautious with javascript frameworks. For instance, if you declare window.JQuery, and use the JQuery framework, the JQuery namespace will be replaced by your assignment, rendering it useless.

Yes, you can, but in general you shouldn't.
The window object is also the JS default "global" object, so all global variables get added there.
You're unlikely to break anything unless you overwrite a property that's already there, but it's considered bad practise to dump variables on window, or otherwise create lots of global variables.

I won't repeat what others have said re: the hackyness of this practice. But it can be incredibly useful when using a rigid framework like Angular mixed with vanilla HTML / JS (or jQuery) code. Which is also hacky and frowned upon, but sometimes there are good reasons, like if you have lots of pre-existing JS code that will be challenging to integrate into the framework.
The more interesting question to me is HOW to make use of the ability to add properties to the global window object. There is a pattern I use when I want to expose the methods of an Angular provider (service) to code that otherwise would be unable to inject the service, probably because it runs outside of the Angular DI framework. The way I do it is as follows:
Define your service as a provider in your top level module.
In the constructor or onInit of app.component.js (or whatever your top level component is that imports the provider), inject the provider normally, perform any one time initialization that it needs, and then call window['MyServiceName'] = this
Assuming you have designed the provider to follow a Singleton pattern, your provider's methods can now be safely called from anywhere. A non-Angular script need simply call window['MyServiceName'].methodName()

That 'll work fine, no conflict with any library until used same variable name, will work in all browsers, but not recommended as this will create global JS variable.

In IE if an element has an id, then that node is accessible on the window object as a property:
<div id="num"></div>
alert(num); //Element
num = 3; //throws exception
var num = 3; //ok

As pointed out by others yes you can and yes it means adding "global variables".
Having global variables is not best practice but sometimes it is the simplest thing to do. For instance if you use IFrames and want the child-window to access some property of the parent window. Such a property must be "global" for a child to access it. But this also shows that it is not "truly global", it is just a property of a specific window. But it can conflict with other property-names such as names of functions defined in the same window, perhaps by some libraries you use.
So we know global variables are bad. If we decide to use them anyway is there anything we can do to minimize their badness?
Yes there is: Define a SINGLE global variable with a more or less unique name, and store an OBJECT into it. Store all other "variables" you need as fields of that single object.
This way you don't need to ever add more than a single global variable (per window). Not TOO bad.
Name it more or less uniquely so it is unlikely to conflict with anybody else's single global. For instance you could use your name + 's' as the variable name:
window.Panus = {};
:-)

Related

Limiting the scope of a shared variable (Javascript)

I would like to know if it is possible to have a variable with shared scope between two separate javascript files but not within the root document that references those javascript files.
For example, if I wanted to have a variable that held information about the size of an html element on page load, I could do something like this...
Within the root (index.html) document, I could declare the variable and give it a global scope:
<script>
var elemWidth;
</script>
<script src="first.js"></script>
<script src="second.js"></script>
Within the first javascript file (first.js):
var elem = document.getElementById('myElem');
elemWidth = elem.style.width;
Within an additional javascript file (second.js):
var someDynamicValue = n; /* where 'n' is an integer that is given a calculated value */
if(elemWidth > someDynamicValue) { ... }
Using the above convention, the variable elemWidth is accessible in all three documents (index.html, first.js, second.js). But what if, for whatever reason, I did not want that variable to be accessible in the root document (index.html)? I only want it to be accessible and manipulatable in the two .js files. After all, it's really not needed in the root document (index.html) and I wouldn't necessarily need it in additional .js files (e.g. third.js).
Certain possibilities have come to me, but they all seem to break down at a certain point:
Declaring the variable within one of the two .js files would limit
its scope to that document only. This just doesn't work.
Store the variable as a private property of an object that is declared in the root, and allow that property to be set/get only by the approved .js files
This might be possible by extending the prototype of the ancestor object within the external .js files to include getter/setter methods, but not providing those methods in the document root (which is where the ancestor would have to be declared)
I am not an OOP expert, so this approach might be fundamentally flawed. Feel free to correct me on this!
Consolidate the two javascript files into one, and declare the
variable within that script. This would work, but I may not
necessarily want to or be able to consolidate the separate .js files
in certain circumstances.
Other than that, I am stumped by this question. At this time, I don't have a specific reason to need this functionality, but I can imagine it being useful in certain situations (i.e. additional security, quarantining variable values) and, of course, I am curious and would like to learn something new about JS & OOP through this example.
Perhaps it's just not possible in JavaScript - if so, please explain why :)
Update: I would like to expand on the idea of using object prototypal inheritance to possibly achieve this result. If we declare a class constructor, such as:
function ancestorObj() {
var privateVar = 'secret';
}
And then extend this prototype with another constructor:
function inheritedObj() {
this.getSecret = function() {
return privateVar;
}
}
inheritedObj.prototype = new ancestorObj();
We have now created an object class constructor that is an inherited instance of ancestorObj which contains a getter method that returns the private property of the prototype object. The default class constructor does not contain a getter method. The logic that follows is that only instances of the inheritedObj can get the value of this private property. Can we not then declare instances of inheritedObj only where needed (i.e. 'first.js' and 'second.js'), thereby limiting the scope of the privateVar property?
Again, OOP is not my forte, so this may be easily dismissed as not possible or otherwise incorrect. If so, please explain why.
Ultimately there's nothing you can do to make the symbol completely private to two code units imported from separate <script> blocks. The only relationships such code can have are via global symbols, and if code in two scripts can find your "private" property, any other code can too.
Probably the best thing to do is keep it as a property of some global namespace you claim, or under one you're already using (like a framework).
In your case it'd wrap it into a jQuery method like $.fn.methodName = function { var leaveMeAlone = true; };

How do I prevent accidental global name space pollution with javascript eval?

I am writing a simple REPL (Read, Evaluate, Print, Loop) implementation in JavaScript. I am able to isolate code and calling context like so:
var sandbox = {
// Allow the input code to use predefined helper functions
// without the preceding use of the this keyword.
helper_fn: function() { alert("foo"); }
};
var func = new Function("with (this) { " + user_inputed_code + " }");
func.call(sandbox);
Now it closes the user_inputed_code so that this referers to sandbox and if the inputted code accesses or mutates this it is affecting sandbox.
However, I noticed that if the imputed code were to accidentally forget to preface a variable assignment with the keyword var that the global namespace get polluted.
Is there anyway to prevent this? If so how (maybe a regexp?)? Is there a better way to approach this?
I'm going to provide two completely different approaches from what others discussed here. They are both drastic, and are useful when you want to relatively isolate your environment.
The easiest technique that works in all browsers is to probably create an iframe, and append script tags to it. (Note, a really overzealous iframe can still get past that if they're in the same domain, at least in older browsers). I discuss that in this question.
Use web Workers, which have an isolated environment by default and have no access to the global object of the main execution thread. I discuss that in this question.
More specifically, if you're building a REPL take a look at this answer where we discuss and I explain how to eval code in the same scope but outside the global scope, using the first approach of iframes.
(I assumed a browser, in node you can simple use the vm module and select the context in runInContext)
Turns out there is a way with "use strict" and without Object.freeze. You have to manually replace the global namespace with your own sandbox object:
var sandbox, module, func, output;
// Empty object or with defined methods / properties
// you want to expose as globals.
sandbox = {};
// A reference to an object you WANT to provide safe
// access to. In this example it's just an empty object.
module = {};
// A better version of eval:
func = new Function("module", "with(this){return(function(module,global,window){\"use strict\";return eval(\"" + code + "\");})(module,this,this)}");
output = func.call(sandbox, module);
This code allows global and window to refer to a sandboxed object instead of the global name space. It masquerades the variables global and window as the sandbox object and the use of "use strict" will cause it to throw an exception if the input missed the use of var. It also wraps the function in a with statement to make the methods and properties defined in the sandbox object to work as if they were preceded by this.. To see an implementation example (with test specs) check out this gist.
Thank you all for your ideas. Hope this answer helps others.

Javascript scope, security, and extension

I have read an awful lot about Javascript scope and have produced the functionality that I wanted - I thought i'd post this question to clarify on the hows/whys in one place.
In my case I was using Leaflet - a javascript library for mapping.
My first question is as to what the 'L' is.
So for example I can use the following code:
current_map = L.map(map_id);
What does L represent and why can I access functions 'through' it?
Secondly on my website I have mutliple different maps sharing some common code e.g setting up the map.
As such I wanted to develop some 'common code' which would set up the map and add markers for example.
So I wrote the following code in map_global.js:
var current_map;
window.setup_map = function(map_id)
{
if ($("#"+map_id)[0])
{
$("#"+map_id).show();
current_map = L.map(map_id);
}
}
Then in my map_individual.js file I simply write:
map_setup('map_div');
and my map is setup.
I can do this because by using window in the defining function name I am setting the function in a global scope. Likewise by setting the variable current_map outside any function it too is global?
Is this an efficient/safe/reasonable way to achieve this functionality?
Finally why can i NOT access current_map in map_individual.js?
Many Thanks.
Tom
This is an issue of variable scoping.
Think of "L" conceptually as a namespace. L exposes methods to you, such as map, L.map().
Looks like you want to expose your "current_map" variable. In your map_global.js file, current_map is currently a local variable - because you declared it with var. So anything outside of the map_global.js scope, can NOT access current_map.
If you want a quick and dirty way to access current_map in map_individual.js, you can expose it by setting the global window.current_map to L.map(map_id), so change the scope of your current_map variable.
This of course leads to polluting the global scope, so one thing you can explore is how to achieve "modular" client side javascript. A simple way of doing this, is by implementing your own namespacing. E.g. in map_global.js, you can expose just one 'object' - your own namespace - and attach that to window. You can use your namespace to access current_map and setup_map(), if you attach those methods and vars to that 'object', instead of attaching all your methods and variables directly to the window - global namespace - which could get out of hand quickly.
function setup_map(){ ...}
var current_map;
window.my_lib = {
setup_map = setup_map,
current_map = current_map
}
so my_lib.setup_map(), and my_lib.current_map could be accessed later in this way then, since you only make my_lib a global. Imagine if my_lib exposed a dozen functions, the idea is that this would be more organized, as opposed to attaching all dozen functions to the window - global namespace. This comes in handy later when you have different files/"modules" which have functions that are named the same. This way, you can have my_lib.render() and say, client_lib.render(), without overwriting one another, and maintain that separation, as a way of reducing the risk that you overwrite what is already in the global namespace.
Note that the order in which you import scripts matters as well! There are also libraries such as RequireJS, CommonJS, just to name a few that try to deal with the dependency side of this whole modularity thing which can be worth exploring. So tread carefully and hope this helps!

Isolate execution of JavaScript

One of the limitation of JS that bugs me the most is the poor ability to isolate code's execution.
I want to be able to control the context in which the code is executed, Something that achieve a similar effect to what Script.createContext & Script.runInContext in node.js does (node is using binding to the V8 engine, so i can't emulate their implementation).
Here is the some reason why I want to isolate code execution:
Isolate the code from the global namespace (the window object and the also the DOM) , but I however need to be able reference function call on objects exposed in the context which must be executed synchronous which makes it almost impossible using a WebWorker for isolation.
By isolate the execution of code it would possible also be able to deallocate its definitions when no longer needed (memory management).
I know one may achieve partly isolated execution by loading script into a iframe, this approach is however very heavy and uses a lot memory for a second instance of the DOM which isn't needed for what I'm trying to do.
I need to share constructor definition and also definitions of object which are shared between the isolated containers/contexts which both must run on the main UI thread. Mainly i want to use these isolated containers to host plugins/modules (mini-applications) which each presents and dynamically updates a viewport by calling drawing commands on their own Context2D object.
If these containers are not running on the main UI thread it wold be painfully hard to proxy calls such as ctx.measureText() and ctx.drawImage() would be all useless as image objects can't be created in a Worker.
Does someone know of future specification that would make this possible?
Are there any current (hidden) browser-side APIs that could be used to achieve this?
Would it be better utilize a virtual machine like Goggle's Dart VM and also re-implement my current codebase?
My current codebase is slightly above 20 000 lines of code.
Would it be better to re-implement the framework in *
The closest library I've seen for this is Caja.
Basically, in non-strict javascript code, there are many ways to get access to the global object (window in browsers), making true isolation a very hard problem. Caja does some iframing trickery to patch this, but to be honest I'm not exactly sure how it works.
You can isolate your code from the global namespace with a simple self executing function object:
(function() {
// all your code goes here
// nobody outside of your code can reach your top level variables here
// your top level variables are not on the window object
// this is a protected, but top level variable
var x = 3;
// if you want anything to be global, you can assign it to the window object.
window.myGlobal = {};
function myTopLevelFunction(x,y,z) {
// code here
}
})();
If you want to have multiple ones of these execution contexts and be able to share between them, then you will have to rendezvous via one publicly known location, either a truly global variable or a property on a known DOM object or something like that. It is relatively common to declare one global namespace object and use properties off that for any access to things you're sharing among modules. I know it isn't completely perfect, but it works. Here's an example of the rendevous using a single global namespace object:
// module AAA
(function() {
// module AAA code goes here
// set up global namespace object and whatever references we want to be global
window.myModuleTop = window.myModuleTop || {};
myModuleTop.AAA = {};
myModuleTop.AAA.myFuncA = function() {};
})();
// module BBB
(function() {
// module BBB code goes here
// set up global namespace object and whatever references we want to be global
window.myModuleTop = window.myModuleTop || {};
myModuleTop.BBB = {};
myModuleTop.BBB.myFuncB = function() {};
})();
Couldn't you use a closure like other answers mentioned and then use a shadow dom to ensure that the user can't get to the rest of the dom? Something like this:
var containerNode = someDomNode
var root = containerNode.createShadowRoot()
;(function(root){
var window = null, document = null, history = null,
screen = null, navigator = null, location = null
// isolated code goes here
})(root)
Caveats:
If you create other global objects outside the context of the isolated code, you need to explicitly shadow the variable like I did with window, document, etc, otherwise the isolated code will be to access it.
This won't work in browsers that don't have shadow dom obviously, unless your isolated code doesn't need to interact with the dom at all.
You have to be very careful that objects you do give the isolated code access to doesn't contain references to things you don't want it to have access to. Sometimes this is super error prone to do.
I'm making this suggestion because its plausible that it works, but I have no idea if there are additional ways to get to things like the window and document objects.
Is "standard" namespacing an option? Like:
var myNamespace = {};
myNamespace.myFunc = function() { return true; }
This approach is the simplest I can think of and may be the solution to many problems. Although not a real sandbox, it can let the code less error prone.
There is a proposal for Realms API, which seems to solve similar problems. It is still under discussion, but there is already a polyfill for it - realms-shim.

How to avoid global variables?

I've been told not to use global variables.
I use one to turn off/on client side validation.
I use two more to conrol me drop-down menu.
If these should not be gloval variables where should I put them?
/*
Global
*/
var client_validation=1, // used to turn off/on client-side validation
menu_timer=0,
menu_elment=0;
window.onload=i0;
/*menu*/
function top_mouse_over(id)
{
bottom_mouse_over();
if(menu_element)menu_element.style.visibility='hidden';
menu_element=document.getElementById(id);
menu_element.style.visibility='visible';
}
function internal_time()
{
if(menu_element)menu_element.style.visibility='hidden';
}
function mouse_out()
{
menu_timer=window.setTimeout(internal_time, 500);
}
function bottom_mouse_over()
{
if(menu_timer)
{
window.clearTimeout(menu_timer);
menu_timer=0;
}
}
Header 1 // This makes more sense
Content
Header 1 // Than this
Content
It sounds to me like you those might be good candidates for globals. Globals are supposed to, well, be reserved for operations with broad implications for the app like controlling fundamental behavior across multiple pieces.
Now, if you want to create a "namespace" for them, it's this simple:
var globalControls = {
client_validation:1,
menu_timer:0,
menu_elment:0,
window_onload:i0
};
Javascript doesn't have real namespaces yet. Objects are used as a substitute for them until the next version of ECMAScript might get around to adding that feature.
Here is an article about javascript namespacing.
http://javascriptweblog.wordpress.com/2010/12/07/namespacing-in-javascript/
The title should be "How do I avoid global variables"? But that's ok.
You can create an object and assign properties to it. Then you'll have variables inside an object and these variables will only be accessible through this one, not through the global scope.
Example:
var config = {
clientValidation: true,
menuTimer: 0,
menuElement: 0,
someFunction: function () {
// alert (this.clientValidation) "this" is the object scope
}
};
// then you access the object properties:
alert( config.clientValidation ); // true
namespacing separates class definitions from colliding, however, it will not solve the global variable problem. It is a temporary fix.
A solution to global variables is to use a class instance which encapsulates properties that would otherwise be global. Encapsulation is one of the 3 pillars of object oriented programming.
See for an example of a class with a namespace that has encapsulated properties.
Additionally, I show how to create a custom jquery plugin that uses the class.
http://www.robusthaven.com/blog/javascript-development/Automatically-generate-the-table-of-contents-with-jQuery
When i have data that i need persisted that would normally require creating a global variable I instead use http://api.jquery.com/jQuery.data/ to attach the data in an object form to the dom element making use of this data.

Categories

Resources