storing document in a variable - javascript

I just wondered if I stored document into a variable whether there would be a speed enhancement so if I had
var doc= document;
myElement = doc.getElementById('somethingSweet');
I know in this example it wouldn't make that much different but my thinking is that my variable would act as a "pointer" to document and so m scripts would not need to try and refer back to document.

There is value in storing something that will be reused in a variable. Document is a poor choice since it's already available on the window. Typically, you would store things that you look up in the document, that aren't already available via top-level properties. This is especially true in functions or plugins that you may develop where you want to keep a reference to the DOM elements that the plugin is operating on handy to avoid looking it up each time.

Document is a global object. How can it be faster to refer to another variable and then to document instead of directly to document? That's a retorical question :)

Wrap your code in a self-executing anonymous function, and pass document as a variable
(function(doc) {
//code
})(document);
By itself, I don't see any improvements it can make. However, this is a widely used minification technique; minified, doc turns into something like a, so whenever your code uses for example doc.getElementsByTagName, it turns into a.getElementsByTagName.
Edit: A quick example.
//Before minifying
(function(document) {
var anchor = document.createElement('a');
anchor.id = 'world';
document.body.appendChild(anchor);
document.getElementById('world').innerText = 'Hello World';
})(document);
//After minifying
(function(a){var b=a.createElement("a");b.id="world";a.body.appendChild(b);a.getElementById("world").innerText="Hello World"})(document);
Notice how document turned into "a", and so we saved 7 characters each time! Note that writing obfuscated code isn't suggested, and you should only minify right before shipping out the code.
Minified using the excellent Closure Compiler

Related

How to "take variables out of an object" in javascript

I'm looking for something that will import the contents of an object to the global scope:
var y = {}
y.x = 5
//do some magic here
console.log(x); //5
I want to do this is so I can make an easy to use module with memorable function names without having to worry about things accidentally getting overridden by other modules.
Consider this example:
funModule = {};
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
Here I've created a module that has some useful functions and constants (implementations and values were replaced with "...").
I don't want my users to have to type out the module name every time they call function or use a constant. That would result with really messy code:
funModule.walkDog(funModule.UNITED_STATES_DEFICIT);
I could try it again by defining everything globally:
washClothes = function(clothes){...}
walkDog = function(dogName){...}
//etc
UNITED_STATES_DEFICIT = ...;
but if a different module has also defined the commonly named function washClothes we've got trouble. (in my actual case the commonly named function is run)
Removed from technical context, here is the problem I'm faced with:
Firstly I want to use simple and memorable names to make the module easy to learn and fun to use.
Secondly I don't want the easy names to make the module impossible to use with others. Especially as it grows, a lot of common names will be used. It would be great if the users could decide whether or not import the names directly.
Thirdly I realized as I'm typing this that what I'm describing is something that definitely already exists, in python. See http://effbot.org/zone/import-confusion.htm for more detail.
tl;dr How can python-like imports be done with javascript?
EDIT:
It seems there is not a universal way to do this.
Using Window won't work in all environments (but will work in any common browser).
Apparently ES6 Modules are not available to web browsers directly.
This question is different from this one because its not about Node.js. I was looking for a universal way to do it, but that doesn't seem possible, so I'll limit it to web browsers, (namely chrome, firefox, safari, opera, and maybe ie)
EDIT:
This general article about Scope could be useful for anyone with a similar question as mine: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/
Object.prototype.makeglobal=function(){
for(key in this){
if(window[key]){//replace window if youre not in a browser
//already exist, error handling
console.error(key+' already exist in window');
}else{
window[key]=this[key];
}}};
Use like this:
funModule.makeglobal();
//now you can
washClothes();
But this is bad as it pollutes the global object.
2.Your user should create his own namespace:
function(){
this.washClothes();
//more of his content
}.call(funModule);
3.You could also add a loader:
funModule.load=function(func){
console.log(func);
console.log(this);
func.call(this,this);
};
Now you can do:
funModule.load(function(fun){
this.washClothes();
fun.washClothes();
});
4.If youre concerned about readability you may use function chaining (?):
funModule.washClothes=function(){
//your code
return this;
}
now you can do:
funModule.washClothes("tshirts").washClothes("trousers").washClothes();
ES6 Modules are what you want.
If you will define your object as es6 module you could do this (using the names in your example):
import { washClothes } from "fun-module";
and then washClothes will be globally available on the file that imported it, just like you want.
Read about it here.
If you really want a magic solution like in the comment in your post and don't want to use ES6 and you run in the browser you can put it on the window object:
window.x = 5
In JavaScript, at least in a browser, global variables are properties of the window object: that is, window.x and x (where x is global) reference the same value. So, in theory, you could use Object.assign() to copy your object's properties to the window object making them global variables. This is roughly equivalent to globals().update(myobj.__dict__) in Python.
But just as import * is usually a bad idea in Python, so too this sounds like a bad idea, except even worse because window has a lot of other properties that you probably don't want to clobber.
After some additional research I found a way, without polluting the global namespace, to allow users to directly access module contents.
This solution allows the user to:
Write code that directly references the module's functions/properties
Define precedence if there are multiple modules written in this same style
Still access the module's functions/properties by module name*
*This feature comes with a catch
Here's the code
Module
funModule = {};
//This stuff is the arbitrary contents of the module:
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
//etc
//This part is necessary:
funModule.run(userApp)
{
for(key in this){
eval(key + " = " + this[key] + ";");
}
userApp();
}
The only way (that I could find) to dynamically define functions both in funModule.run's scope and in funModule is to use Eval. Using call, apply, or bind to manipulate scope would still require use of the this keyword and the whole point of this unusual style is to make client code as simple and non-repetitive as possible.
Client Code 1
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run(myApp);
Here in the client code it is possible to directly access everything except for funModule.run. So the global namespace is kept clean but the user's code does not need unnecessary repetition.
Client Code 2
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run( otherModule.run.bind({},myApp) ); //otherModule has precedence here
Assume otherModule is a different module that features the same run function. funModule will load its contents then call its first argument. The first argument will load otherModule's contents, overriding anything from funModule with the same name.
Client Code 3
function myApp()
{
//directly access stuff from funModule
walkDog()
var big = UNITED_STATES_DEFICIT * 3.14;
//explicitly access stuff from specific modules
clothes = new otherModule.Clothes();
funModule.washClothes(otherModule.washClothes(clothes));
}
funModule.run(myApp)
This is the feature that makes use of eval necessary. The user can opt out of ambiguity of direct access. They can still access properties/methods by naming the module they come from.
But Why?
Some StackOverflow users were understandably concerned about the unusual set of constraints in the question, so I figured I would answer the following question:
Why don't you use a short alias for your module.
I tried to answer that question in this article, which pulls from this question and answer.

Is it safe to rename document variable in javascript

I noticed that Google Closure Compiler did not rename document to something like d to reduce space.
I cannot think of a case where this would break the code (ie where document points to something else down the road). Actually the same goes for window.
Is there a reason for protecting document this way?
== EDIT ==
By renaming it I was thinking reassigning it. Example below.
var d=document;
var obj1=d.getElementById("obj1");
var obj2=d.getElementById("obj2");
... // with enough uses of document so it makes to reassign it size-wise.
Closure-compiler does not perform this "optimization" by default for the simple reason that it produces LARGER source when used with gzip. You can enable this optimization by turning on the AliasExternals pass using either the Java API or a custom build.
See https://code.google.com/p/closure-compiler/source/browse/src/com/google/javascript/jscomp/AliasExternals.java#38
What happens?
ProblemFactory's guess is correct.
This is a //TODO in the closure compiler source code. If we didn't preserve document and window and instead ran them over with d for example, at the moment the closure compiler does not know if it's overriding a global from another file. Like the comments say this will be resolved in the future at which point.
Enough words, show me the source!
If we check the closure compiler source code inside VariableReferenceCheck.java we can find the following:
private class ReferenceCheckingBehavior implements Behavior {
#Override
public void afterExitScope(NodeTraversal t, ReferenceMap referenceMap) {
// TODO(bashir) In hot-swap version this means that for global scope we
// only go through all global variables accessed in the modified file not
// all global variables. This should be fixed.
// Check all vars after finishing a scope
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
checkVar(v, referenceMap.getReferences(v).references);
}
}
If we check the hot-swap algorithm itself we can see that:
// Note we use the global scope to prevent wrong "undefined-var errors" on
// variables that are defined in other JS files.
So, we can see that this is just the closure compiler not understanding the code of globals across multiple files well enough to make that replacement. You can always do the replacement yourself :)
I think document is standardized, always-global variable. To use the same way d it has to be global also, thus global namespace will have another "junk" variable.
It could be dangerous for not aware developers (which wont be aware of that thus it is not standard variable).

Best practice: Javascript/Jquery saving variable for later use

I'm sure, this question has been answered somewhere before but I just couldn't find it.
If within a function a variable has been defined, what is the best practice to save it for later use? 1. Saving it "globally"?
foo = 'bar';...function bar(){
...
foo = 'bat';
return foo;
}...
Here, the variable will be altered later on.
2. Or saving it within a hidden form field within the HTML-DOM?
`Thanxs!
Saving it as a global JavaScript variable is by far the most efficient.
EDIT: If the data you want to save is associated with an element on the page (for example, each row in a table has a bit of data associated with it), and you are using jQuery, there is a data() method which is more efficient than setting an attribute on the element or something similar.
It depends on the context, but probably: In a variable defined at the top level of a closure that wraps the set of functions to which it applies.
i.e.
var exports = function () {
var stored_data;
function set_data(foo) {
stored_data = foo;
}
function get_data() {
return stored_data;
}
return { get: get_data, set: set_data };
}();
This avoids the risk of other scripts (or other parts of your own, potentially very large, script) overwriting it by accident.
The HTML5 spec has defined a solution to this question: If you are using HTML5, you can specify data attributes in your DOM.
See this page for more info: http://ejohn.org/blog/html-5-data-attributes/
This is now the standardised way of doing it, so I guess that it's considered best practice. Also John Resig, who wrote the blog I linked to above, is the author of JQuery, so if it's good enough for him, who am I to argue.
The really good news is that you don't even have to be using an HTML5-compatible browser for this technique to work - it already works in older browsers; it's just that now it's been encoded into the standard, and there's a defined way to do it.
That said, there's nothing wrong with a global variable in your Javascript as long as you avoid polluting the namespace too much, and it would be more efficient from a performance perspective, so there's plenty of merit in that approach as well.

Is there a way to jail in Javascript, so that the DOM isn't visible

I would really like to provide the user some scripting capabilities, while not giving it access to the more powerful features, like altering the DOM. That is, all input/output is tunneled thru a given interface. Like a kind of restricted javacsript.
Example:
If the interface is checkanswer(func)
this are allowed:
checkanswer( function (x,y)={
return x+y;
}
but these are not allowed:
alert(1)
document.write("hello world")
eval("alert()")
EDIT: what I had in mind was a simple language that was implemented using javascript, something like http://stevehanov.ca/blog/index.php?id=92
(Edit This answer relates to your pre-edit question. Don't know of any script languages implemented using Javascript, although I expect there are some. For instance, at one point someone wrote BASIC for Javascript (used to have a link, but it rotted). The remainder of this answer is therefore pretty academic, but I've left it just for discussion, illustration, and even cautionary purposes. Also, I definitely agree with bobince's points — don't do this yourself, use the work of others, such as Caja.)
If you allow any scripting in user-generated content, be ready for the fact you'll be entering an arms race of people finding holes in your protection mechanisms and exploiting them, and you responding to those exploits. I think I'd probably shy away from it, but you know your community and your options for dealing with abuse. So if you're prepared for that:
Because of the way that Javascript does symbol resolution, it seems like it should be possible to evaluate a script in a context where window, document, ActiveXObject, XMLHttpRequest, and similar don't have their usual meanings:
// Define the scoper
var Scoper = (function() {
var rv = {};
rv.scope = function(codeString) {
var window,
document,
ActiveXObject,
XMLHttpRequest,
alert,
setTimeout,
setInterval,
clearTimeout,
clearInterval,
Function,
arguments;
// etc., etc., etc.
// Just declaring `arguments` doesn't work (which makes
// sense, actually), but overwriting it does
arguments = undefined;
// Execute the code; still probably pretty unsafe!
eval(codeString);
};
return rv;;
})();
// Usage:
Scoper.scope(codeString);
(Now that uses the evil eval, but I can't immediately think of a way to shadow the default objects cross-browser without using eval, and if you're receiving the code as text anyway...)
But it doesn't work, it's only a partial solution (more below). The logic there is that any attempt within the code in codeString to access window (for instance) will access the local variable window, not the global; and the same for the others. Unfortunately, because of the way symbols are resolved, any property of window can be accessed with or without the window. prefix (alert, for instance), so you have to list those too. This could be a long list, not least because as bobince points out, IE dumps any DOM element with a name or an ID onto window. So you'd probably have to put all of this in its own iframe so you can do an end-run around that problem and "only" have to deal with the standard stuff. Also note how I made the scope function a property of an object, and then you only call it through the property. That's so that this is set to the Scoper instance (otherwise, on a raw function call, this defaults to window!).
But, as bobince points out, there are just so many different ways to get at things. For instance, this code in codeString successfully breaks the jail above:
(new ('hello'.constructor.constructor)('alert("hello from global");'))()
Now, maybe you could update the jail to make that specific exploit not work (mucking about with the constructor properties on all — all — of the built-in objects), but I tend to doubt it. And if you could, someone (like Bob) would just come up with a new exploit, like this one:
(function(){return this;})().alert("hello again from global!");
Hence the "arms race."
The only really thorough way to do this would be to have a proper Javascript parser built into your site, parse their code and check for illegal accesses, and only then let the code run. It's a lot of work, but if your use-case justifies it...
T.J. Crowder makes an excellent point about the "arms race." It's going to be very tough to build a watertight sandbox.
it's possible to override certain functions, though, quite easily.
Simple functions:
JavaScript: Overriding alert()
And according to this question, even overriding things like document.write is as simple as
document.write = function(str) {}
if that works in the browsers you need to support (I assume it works in all of them), that may be the best solution.
Alternative options:
Sandboxing the script into an IFrame on a different subdomain. It would be possible to manipulate its own DOM and emit alert()s and such, but the surrounding site would remain untouched. You may have to do this anyway, no matter which method(s) you choose
Parsing the user's code using a white list of allowed functions. Awfully complex to do as well, because there are so many notations and variations to take care of.
There are several methods to monitor the DOM for changes, and I'm pretty sure it's possible to build a mechanism that reverts any changes immediately, quite similar to Windows's DLL management. But it's going to be awfully complex to build and very resource-intensive.
Not really. JavaScript is an extremely dynamic language with many hidden or browser-specific features that can be used to break out of any kind of jail you can devise.
Don't try to take this on yourself. Consider using an existing ‘mini-JS-like-language’ project such as Caja.
Sounds like you need to process the user entered data and replace invalid mark-up based on a white list or black-list of allowed content.
You can do it the same way as Facebook did. They're preprocessing all the javascript sources, adding a prefix to all the names other than their own wrapper APIs'.
I got another way: use google gears WorkerPool api
See this
http://code.google.com/apis/gears/api_workerpool.html
A created worker does not have access
to the DOM; objects like document and
window exist only on the main page.
This is a consequence of workers not
sharing any execution state. However,
workers do have access to all
JavaScript built-in functions. Most
Gears methods can also be used,
through a global variable that is
automatically defined:
google.gears.factory. (One exception
is the LocalServer file submitter,
which requires the DOM.) For other
functionality, created workers can ask
the main page to carry out requests.
What about this pattern in order to implement a sandbox?
function safe(code,args)
{
if (!args)
args=[];
return (function(){
for (i in window)
eval("var "+i+";");
return function(){return eval(code);}.apply(0,args);
})();
}
ff=function()
{
return 3.14;
}
console.log(safe("this;"));//Number
console.log(safe("window;"));//undefined
console.log(safe("console;"));//undefined
console.log(safe("Math;"));//MathConstructor
console.log(safe("JSON;"));//JSON
console.log(safe("Element;"));//undefined
console.log(safe("document;"));//undefined
console.log(safe("Math.cos(arguments[0]);",[3.14]));//-0.9999987317275395
console.log(safe("arguments[0]();",[ff]));//3.14
That returns:
Number
undefined
undefined
MathConstructor
JSON
undefined
undefined
-0.9999987317275395
3.14
Can you please provide an exploit suitable to attack this solution ? Just to understand and improve my knowledge, of course :)
THANKS!
This is now easily possible with sandboxed IFrames:
var codeFunction = function(x, y) {
alert("Malicious code!");
return x + y;
}
var iframe = document.createElement("iframe");
iframe.sandbox = "allow-scripts";
iframe.style.display = "none";
iframe.src = `data:text/html,
<script>
var customFunction = ${codeFunction.toString()};
window.onmessage = function(e) {
parent.postMessage(customFunction(e.data.x, e.data.y), '*'); // Get arguments from input object
}
</script>`;
document.body.appendChild(iframe);
iframe.onload = function() {
iframe.contentWindow.postMessage({ // Input object
x: 5,
y: 6
}, "*");
}
window.onmessage = function(e) {
console.log(e.data); // 11
document.body.removeChild(iframe);
}

How much overhead is there when traversing the DOM?

(I'm using prototype.js here, but I imagine the same holds true across other libraries as well)
I often find myself writing code like this:
var search_box;
Event.observe(window, 'load', function() {
search_box = $('search_box');
});
function doSomething(msg) {
search_box.innerHTML = msg;
}
Rather then writing it simply like this:
function doSomething(msg) {
$('search_box').innerHTML = msg;
}
My intention is to avoid having to traverse the entire DOM searching for the "search_box" element everything I need access to it. So I search for it once on page load and then stick the reference in a global variable. However, I don't recall ever seeing anyone else do this? Am I needlessly making my code more complex?
This is called premature optimization.
You are introducing a global variable to optimize something you have not profiled.
Your assumption that the $ "traverses the DOM" is incorrect. This function is implemented using document.getElementById which is the fastest way to access an element in the DOM.
I suggest coding your javascript using basic programming best practices such as avoiding global variables, and not optimizing without profiling. Once your application is working as expected, then you should profile it (using firebug) and address the area(s) where it is slow.
I usually do the same thing, the reason you don't see it often is probably because you don't see well written code often that's optimized ( nevermind the whole preoptimization is evil thing ) - I say if you can optimize it without headaches then why not?
Realistically speaking though that's a very very trivial DOM lookup, you should only begin to worry if you're iterating through dozens of elements and being vague in the selectors.. so I wouldn't worry too much about it unless you can really notice certain parts of your web page loading rather slowly, in which case you should store the multiple elements you access in the outer scope's variable.
Good:
(function() {
var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.
function foo() {
els.something();
}
els.somethingElse();
})();
Bad:
(function() {
var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.
function foo() {
$$('.foo span').something();
}
$$('.foo span').somethingElse();
})();
I decided to spend a bit of time doing some testing to get some hard data. The answer is that preloading the elements into global variables is twice as efficient as accessing them using the DOM getElementById method. (At least under FF 3.6).
Subsequent accesses to the objects is also more efficient using the global variable method, but only marginally so.

Categories