Javascript scope, security, and extension - javascript

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!

Related

Need advise/help on getting rid of global variables

Yes, this is another topic about global variables. I've searched quite a bit about them. But most of the topics is just about WHY not to use global variables and I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
I am working on a project, and it works wonders, but I am using about 50 global variables at the moment and that number keeps rising. Right now I've split things up in multiple .js files. Like load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js, to spread the functions based on what they are for. And I've put all global variables inside settings.js.
Currently I use these global variables for these reasons:
1. Calculation based on some other global variables that doesn't change much or at all after loading. By doing this once, and store it in a global variable, I no longer have to repeat the calculation ever again. If I didn't store it in a (global) variable, Javascript would have to do the calculation many times each second, in some cases even up to few thousand times per second.
2. When the global variable is needed in many functions. Like there's this World-variable, that I use to hold data for the appearance of the world. This variable is a multidimensional array. World[y][x] for example. Load_chunks.js adds more data to this variable, or remove data if you move too far. This variable is also needed in render_map.js, to create the map, and it's also needed in player_action.js, to see if you can step on that particular location.
3. Settings; So a number in a variable that remains the same unless I change them in my script. Instead of going through my scripts, and change the numbers manually after a long search and thinking what the number was, I've put that number in 1 variable and call that variable numerous times in my scripts. These variables are in some cases also needed elsewhere.
Also I like to mention that I don't use classes, and perhaps for that reason I never got around using global variables...?
So how do I get rid of my global variables, or shouldn't I?
I hope you can show me or write for me a script example (or a link to it) of how I should do it. That's the fastest way I learn.
Put Variables Inside a Function Closure
One common way to eliminate a global is to put is inside a function closure:
(function() {
var declareYourFormerGlobalHere = 0;
// put all code that uses the variable inside this closure
// the variable persists for this code to use, but is not actually global
})();
Here's are some usage examples:
// example keeping track of a running count and a cached DOM element
(function() {
var cntr = 0, obj = document.getElementById("test");
setInterval(function() {
++cntr;
if (obj.value < cntr) {
// do something
} else {
// do something else
}
}, 1000);
})();
// example keeping track of a time of last click
(function() {
var timeOfLastClick = 0;
document.getElementById("run").addEventListener("click", function(e) {
var now = new Date().getTime();
// only process click if more than 2 seconds have passed since last click
if (now - timeOfLastClick > 2000) {
// OK to process the click
}
timeOfLastClick = now;
});
})();
Sometimes, you can actually enclose all your code or nearly all your code in a single closure like this and all your current globals become local variables inside the closure rather than actual globals. jQuery uses this technique to declare lots of persistent variables it uses, none of which are actual globally scoped.
Use a Single Namespace Object
Another common method of reducing the number of globals is to use the namespace concept. In this concept, you declare a single global object and put other persistent variables as properties of this single global object. This still leaves you with a single global variable, you can have as many properties as you want off this single global.
var myNamepaceObject = {};
myNamespaceObject.var1 = "foo";
myNamespaceObject.var2 = "whatever";
This technique is also used by jQuery as all globally accessible functions that jQuery offers are available off the jQuery object such as jQuery.extend() or jQuery.contains(). jQuery exposes a single global variable and many other globally accessible functions are then available as properties of that single global object.
Module Pattern
What is commonly known as the "module pattern" uses a combination of these above two techniques, where you have a single module variable that both uses properties and closure variables.
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
You can see a discussion of this design pattern in these references:
JavaScript Module Pattern: In-Depth
Learning Javascript - The Module Pattern
Mastering the Module Pattern
JavaScript module pattern with example
I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js, strongly hint to a procedural implementation, that is your architecture probably has several functional pieces and you pass data around between these functions. That's where your global variables are coming from.
So how do I get rid of my global variables (...)
To change that, you need to structure your system in an object or component based approach, that is:
encapsulate data + respective functions by objects in your problem domain, e.g. have a World object that contains Avatar, Buildings, Airborne objects etc. (or whatever your project is about).
separate the problem domain's logic from view logic (e.g. use a MVC architecture)
then your project organises the interactions between view and model objects by essentially exchanging messages between them.
To facilitate this, I suggest these fine frameworks, or some equivalents suitable for your run-time environment:
requirejs - to encapsulate modules into globally managed components
backbonejs - to have an efficient, proven model/view, class/object model (actually built for use with a REST-style backend, but that's not a strict requirement)
Code structure
Typically, I structure my applications such that there is one .js file per each object component/module. A module in this sense contains both the class definition and the corresponding collection. The modules are managed by requirejs and the class definitions are done using backbonejs.
I hope you can show me or write for me a script example
/* define a class e.g. in someclass.js */
define(['backbone'], function($B) {
var SomeClass = $B.Model.extend({
// all instance variables, methods etc. follow
someVar : value,
someMethod : function() { ... },
});
return SomeClass;
});
/* use the class, e.g. in app.js */
require(['someclass'], function(SomeClass) {
var instance = new SomeClass({ initial model attributes });
var value = instance.get('attribute');
instance.someMethod();
...
});
i had the same problem before but it was a big problem as we had a third party javascript code and our code live in clients websites so we should find a way to omit the appearance of global variable so to be short:
Use 1 global variable namespace and make all other to be properities for it:
GlobalVariable = {}
GlobalVariable.var1 = "var1"
GlobalVariable.var2 = "var2"
You can also make it more useful and divide it into groups:
GlobalVariable.helper = {}
GlobalVariable.helper.var1 = "var1"
GlobalVariable.helper.var2 = "var2"
so you can use same names under different groups.
and if you want to Omit it totally you can use:
(function(document, window) {
// all variables here is global only inside the scope
}(document, window));

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.

Can I add attributes to 'window' object in 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 = {};
:-)

Prevent 'global' references in javascript

I've got a problem of having code variable names conflicting each other, ie;
<script type="text/javascript">var a = "hello"; </script>
<script type="text/javascript">alert(a);//this works, when I want 'a' not to exist </script>
Are closures the only option?
Coming from a c# background, its like constructing an unreferenced instance of a delegate, then calling it inline, which seems a bit messy
(function(){var a = "hello";})();
(function(){alert(a);})();//yes! working as expected
Using a (immediately self-executing) function to create a new scope is indeed the way to go.
This also has the advantage that you can ensure that certain variables have certain values. When using jQuery, the following is common for example:
(function($, window, undefined) {
// ...
})(jQuery, this);
Unless you have tons of functions with only a single statement in each (like in your example) it is also perfectly readable.
Yes, closures are your only option. In browsers all JavaScript files get put into the same global scope.
IIFE's are very common place in JavaScript; I wouldnt' call them messy.
Javascript only has function scope, unlike C# which has block scope. The following code is valid javascript and C#:
var x = 2;
while(true) {
var y = 3;
break;
}
//y is not accessible here in C#, but is in javascript
The only way to create a new scope is to create and execute an anonymous function.
For short, inline stuff then you're best to use the module pattern to create a closure and therefore emulate private variables.
(function(){
var a....
})();
A better long-term approach is to use objects as namespaces.
var NS = {};
NS.a = 1;
Just to provide a different perspective. It is possible to write code without using closures, and maintain (arguably) safe global variable scope.
Define a single object, to use as a namespace, with a suitably unique name (e.g. MyAppContext) that will have global scope, and if you need to define global-like variables only for use in your application only, attach them to this object.
MyAppContext.appTitle = 'Application Title';
At the start of your script where you create MyAppContect make sure it doesn't aleady exist.
Make sure that all of your function-scoped variables use the var keyword so you know you're not referencing a global value.
Obviously this approach opens up a risk that you forget to define some of your function variables with var. JSLint can help you in respoect of this this.
I am happy to retract this answer if I start getting flamed, but I believe it is a workable alternative approach to using closures. And hey! it's old skool
I also agree that the use of closures is safer, but thought this might interest you.

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.

Categories

Resources