I am using a jQuery plugin and running it through the Microsoft Ajax Minifier. My scripts work well for me, but now I am running into an issue with this plugin. The issue is that the plugin calls a function by its name using a string:
var s = (getCachedSortType(table.config.parsers, c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
Note the "sortNumeric" and "sortNumericDesc". This calls these functions:
function sortNumeric(a, b) {
return a - b;
}
function sortNumericDesc(a, b) {
return b - a;
}
This is the only location these functions are called so the IDE VS2010 doesn't think that the functions are being called from anywhere... They are conditionally via the code above.
**Here is the Problem**
When this gets minified, the string name of the function stays, but the function gets removed because it does not thing its getting referenced.
Is there any way to adjust the settings minifier to not do this?
I have also seen it change the names of the functions so
function testFunctionName(a,b)
Would become
function a
This would also cause a problem for situations like mine...
Please note, that I know it is bad code design to hard code function names like this. Like I said it is a plug-in that I am using. I would accept a solution that would call the function out right instead of by string, but I am always hesitant to modify plug-ins.
From documentation:
-evals:(ignore|immediate|safeall) specifies how eval statements are to be treated. This is an important switch to be aware of. By default Ajax Minifier will ignore any eval statements, which can break your minified code if it contains eval statements that reference named local variables or functions. This is because by default Ajax Minifier will also rename local variables and function, but it doesn’t modify the text passed to the eval function, so those references may break. If you minify code and it stops working properly, check the code for eval statements. If there are any, try specifying one of the other two –evals switch options. The “immediate” options will not rename any variables or functions within the same scope as any eval call; the “safeall” option will not rename any variables or functions not only in the same scope as any eval call, but also in any parent scopes. This will seriously impair the minification of your code, but should ensure that any calls to the eval function will work as expected. The default setting is ignoreall.
Then try -evals:immediate and if your code is still broken you have to use -evals:safeall (even if this will make your JavaScript files bigger).
UPDATE
If you're not using eval then you have to skip function renaming at all:
-rename:(all|localization|none) specifies whether or not to automatically rename local variables and functions. Global variables and functions are not automatically renamed, nor are property names. If “localization” is specified, only variables that do not start with “L_” will be renamed. The default value is all.
Just add -rename:none.
Use -unused:keep switch to retain unused functions. This, naturally, will prevent minifier from removing really unused code.
Use -rename switch to assign permanent names to functions that you call by name.
Related
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.
I've been shown how to call variable javascript functions by using window[]().
Is it possible to call variable jQuery functions? If so, how?
Usually, I only need a ternary to flip a visible switch, and it would be very convenient to smush many lines of code into 1. For example, inside an $.aja() success:
if(msg.length > 0){
$("#gridViewContainer").slideDown()
}
else{
$("#gridViewContainer").slideUp()
}
This is probably a bad example since a boolean can probably be passed to slide() or something, but I'd like to use the concept in the linked question above.
This did not work for me:
$("#gridViewContainer")[((msg.length > 0)?'slideDown':'slideUp')]()
jQuery functions are still just JavaScript functions, so the same rules apply to them as any other JS functions.
You can call methods of an object objectVar as follows:
objVar.method();
objVar["method"]();
var methodName = "method";
objVar[methodName]();
Your question mentioned using window[]() - that applies to global functions, since they are essentially properties of window (if running JS in the browser, of course).
In the case of jQuery, you can therefore do this:
var methodName = "hide";
$(someSelector)[methodName]();
$(someSelector)[anyJSExpressionThatReturnsAStringThatIsAjQueryMethod]();
EDIT: I just saw the new version of the question. The line of code shown with the ?: operator selecting the method name should give the same effect as the if/else. I've used similar code myself with no problems, and it works fine in the fiddle that Jason P provided. Note that since your motivation here seems to be about making the code shorter you can omit all of the parentheses from the expression in the [] and just do this:
$("#gridViewContainer")[msg.length > 0?'slideDown':'slideUp']();
...or even omit the > 0 part since msg.length will be truthy when non-zero:
$("#gridViewContainer")[msg.length ?'slideDown':'slideUp']();
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).
I saw many code that began like that
var a=a||{};
Now I know that its check if a exist.
My question is why to check it if its at the first of the code?
I mean the programmer know that a is not exist.
The programmer should know if the variable exists or not.
It's used to mash different pieces of script together without having to keep track of which part of the script is loaded first. Several scripts will have the same piece of code at the start, so they share the same variable.
For the first script, the variable is declared, and there is no previous value for it, so the {} value is used.
For the following scripts that use it, the var is ignored as the variable is already declared, and the previously set value of the variable is used.
Of course, declaring the same variable in several places has a code smell to it. Preferrably you should keep track of what you are doing so that you only declare it once.
Translated into clearer code
var a; // The variable declaration gets brought up because of hoisting
More info on hoisting here
if( a ) {
a = a; // if a is a truthy value then assign it to itself
} else {
a = {}; // if a is a falsy value then set the default to an empty object
}
Hope that helps
That's a shortcut to fall back on a default value - {} in this case.
Basically, javascript can be written in multiple files and within each file you can have multiple declarations and functions defined.
Even if the programmer knows for a given instance if the variable exists or not, there is no way to know if it already exists when this code is called from somewhere else.
This should not happen in well written code (all from one developer / house) but it does happen in projects where the js code is amalgumated from multiple places.
This SO question has a very nice answer about variable scopes in javascript, it should clarify your doubts.
Say I have this function:
function test(){
return a + b + 1;
}
How can I dynamically figure out that it will require globals a and b to be able to run? E.g. something like get_dependencies(test) returns ['a', 'b']
There's no built-in way to do that in standard JavaScript, if you're trying to do it with JavaScript itself.
On nearly all (but not all) JavaScript engines, you can get a form of the source of a function from the function object's toString function, e.g.:
var testSource = test.toString();
...and then of course you could parse that. This is non-standard behavior (the result of calling toString on a function is not defined in the specification), but it's widely-supported. You'd still have to do the parsing to find the symbols.
For the parsing, you have a couple of options. You could try to separate the parser portion of JSLint out of the rest of it, or alternately the terribly-named UglifyJS compressor has a full JavaScript parser which is already separate from the compressor part (see parse-js.js; apparently there's a tiny bit of NodeJS-specific stuff you might want to remove).
You can use a Javascript 'lint' tool that will test your code for common mistakes or oddities.
Some can be found online:
http://www.jslint.com/
http://www.javascriptlint.com/online_lint.php (can also be downloaded)
In your case, you might want to isolate individual functions via a regular expression for example, and submit them to such a tool.