I am writing a Google Chrome extension with the help of Google closure compiler.
I make heavy use of the message API to communicate between code that runs on different processes. Thats why my files need to be compiled separately. If I use advanced optimizations I also have to access properties with quoted strings in data I send with this message API. That works without a problem but it makes my code look ugly. But I like the dead code removal that comes with advanced optimizations.
I would like to be able to do dead code removal without the renaming that comes with advanced optimizations. Is this possible with the closure compiler?
It is not possible out of the box, You can however download the source and make the customization yourself in Java.
Yes, I agree. It is ugly to have to use obj["prop"] instead of obj.prop in all your code that deals with data being passed around just to use the Closure Compiler in Advanced mode.
One trick I have developed is to build a mapping object:
var mapping = {
field1: "field1",
field2: "field2"
:
};
This object, after compiling by the Closure Compiler, will have field names mangled (renamed) mapping to the original, unmangled names, e.g:
var a = {
b: "field1",
c: "field2"
:
};
Then before I send the data, I pass it through a function that clones the entire data structure, converting each mangled field name into the unmangled version in the new object before passing the new object out:
function cloneData(obj) {
var newobj = {};
foreach (var name in obj) {
if (!obj.hasOwnProperty(name)) continue;
var fullname = mapping[name] || name;
newobj[fullname] = obj[name];
}
return newobj;
}
For data received, do the reverse.
Without knowing how many you want to hold onto, you might look into the "Export Symbols You Want To Keep" section of the docs.
Related
I want to reduce the I/O overhead of fetching information from the server using XMLHttpRequest() or ActiveXObject(), as appropriate, by making a general-purpose function for doing the fetch which then stores the fetched data using sessionStorage.<variable>. The trouble is, I don't know in advance what the variable names all are, and I intentionally don't want to know.
I was thinking that if there is some way to "dereference" a variable, like we can easily do in BASH, for example, this would be trivial. For example, if the fetched data was in newData, and the name of the file it was fetched from is in dataFile, and if the dereference syntax was, say $(<variableName>), then one could write code like this to store and fetch the data:
//Store the data:
sessionStorage.$(dataFile) = newData;
//Fetch the data:
var storedData = sessionStorage.$(dataFile);
Get it? ... OK, now, how do I ACTUALLY do this?!
...The only other way around this I can see is VERY clumsy - make arrays, one with name, another with values - there MUST be an easier way! TIA.
As always, it is good to visit the docs first. There you can see, that sessionStorage (like localStorage or Map) has no properties at all (except a hidden property pointing to internal memory but thats another thing), but rather makes the data available through its get or set methods:
sessionStorage.set("a name", "a value");
However the session/localStorage provides also global getters/setters, so in theory one can do:
sessionStorage.name = "value";
If the keys name is dynamic one could use bracket notation:
sessionStorage[aName] = aValue;
However, they havent it even mentioned in the docs, so this feature is neither widely supported nor a good coding style.
Try this. Not exactly sure I followed your question clearly but I would try this if you are having issues using the variable name as string within your other code.
var_param = GET_YOUR_VAR_SOMEHOW; // strip your params as needed
let f1 = { getVarName:var_param.toString()} // object = to f2
let f2 = 'getVarName'; // string = to f1 key
var storedData = sessionStorage.$(f1[f2]); // result of f1[f2] should be your incoming var string, de-referenced from any content.
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.
For example I have class:
function Test() {
}
Test.prototype = {
'setTest' : function(test) {
this.test = test;
}
}
var test = new Test();
Test.setTest('test');
I want to save object test in database.
How to serialize object test to string? (methods, variables, etc)
Simple with json
JSON.stringify( test );
In this case, for the question you're asking, there really isn't a way to do what you want. The problem with your request lies in "serializing everything attached to the object, including functions".
Serialization normally only occurs for data, because executables are usually machine bound, in that they are compiled for a given machine, based on certain characteristics. Now, it's reasonable to say that javascript functions just require a javascript interpreter, because javascript is write-once, run-everywhere. But when people write serializers, because all serializers tend to work the same, we write them for data only. In this case, the industry standard is JSON, which is an object-data only serializer.
There are three solutions that avail themselves to you at this point:
Write your own serialier/deserializer that encapsulates functions. This can be tricky, because not all javascript engines will give you access to the source.
Write your own re-loading mechanism that generates a specific new initialized type on each restore, and save the typename as one of the properties on serialization. That way the initialization of each variable gives you the methods, and then merging with the data gives you the complete object.
Store each function as a string and eval it on the fly as you need it. This is incredibly tricky, and is quite prone to errors. I can think of no case where this becomes helpful, because it's quite fragile. However, it is an option, and cannot be overlooked.
I know that 3 is a sub-answer for 1, so you can consider it that there are only two useful answers.
I know that superficially this works on Chrome and IE9, so it should work everywhere the majority of users are likely to use it:
var abc = function(thing) { return thing; }
abc.toString();
// gives "function(thing) { return thing; }" on the command line
So you can certainly serialize the methods as strings in place of the actual method, but you're going to need to create a duplicate object so you can capture every element on the source object (I think, rather than replacing them in place).
Hopefully this helps you think about the problem some more, and maybe to realize you don't need to serialize the methods (nobody ever does that I know of, not reasonably).
The best way to do this is to write your own serialize method which creates a JSON object with attributes, based on your getters. Normally you define a getter per attribute. So it should work for most cases (so you don't have to define a serialize method for each class).
function serialize(obj) {
var serialized = {};
for(var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] == 'function') {
if (/^get.*/.test(prop)) {
var value = obj[prop]();
var name = prop.replace('get', '');
if (typeof value === 'object') {
serialized[name] = this.serialize(value);
continue;
}
serialized[name] = value;
}
}
}
return serialized;
};
To reset your attribute values back to the class you have two options:
Create a function in your class which creates a valid object instance based on the serialized JSON.
Create a unserialize method and map the JSON with your class using the setters.
Example:
function unserialize(obj, emptyClass) {
// Check emptyClass for setters and map the data from obj to it.
return 'class instance';
}
Typically, you'd do this with JSON, which is widely supported across browsers/languages/libraries/etc. The only hangup is that JSON does not support functions – but do you really need to serialize those?
I've had to support functionality similar to this before. I ended up saving the name of the function as a string and serializing it as JSON. Then when I come back to the client, I execute the function using a helper like the one posted in this question.
If anyone has a better way to solve this problem, I'd want to see it!
I recently had to find a solution for this problem. I'm sure it can be improved upon.
First I created a module for instantiating the "serialisable" object.
function MyObj(serialised){
this.val = "";
if(serialised){
var unserialised = JSON.parse(serialised);
for (var i in unserialised) {
this[i] = unserialised[i];
}
}
}
MyObj.prototype.myMethod = function () { return this.val;};
module.exports = MyObj;
you of course have to consider error handling and other validations.
var x = Object.create(null);
x["hello"] = "world";
But can I allow unverified user input as keys? I want to use it as player name -> player object map. Player names will only be constrained by length of 32. I'm worried if there are special property keys that would allow players to gain control of the server.
EDIT: I'm not making web server. JavaScript will be ran server-side via SpiderMonkey embedded into the game server. If someone hijacks the JavaScript running there, they could ruin the game.
In one word: no, just remember the Google Docs __proto__ fail
You should use a Hash-like class, or at least access these keys prefixed:
var hash = {}, key = "something-evil", value = Math.PI;
hash["$" + key] = value;
console.log( hash["$" + key] == value );
Property keys are always strings. You'll never encounter a problem with any property name, except for maybe:
Object.prototype.hasOwnProperty. For example in:
var obj = {hasOwnProperty:'fail'};
for (var i in obj) {
if (obj.hasOwnProperty(i)) ; // ...
}
which can be solved by using Object.keys(obj).forEach( ... ) or:
for (var i in obj) {
if (Object.hasOwnProperty.call(obj, i)) ; // ...
}
The only hazard is caused by how you deal with the object. The previous example is not an uncommon usage of hasOwnProperty, but it can be used to break your script, because you don't expect the key name hasOwnProperty. The same can apply to .toString, or any other property of the object which can be overriden by setting a new name.
No, an object is basically a blank slate, there are no special keys. On top of that, even if somebody hacks your Javascript it is very unlikely that they will gain control of your server unless you are using very lax security policies (like putting the root password in your Javascript or something silly like that).
You cannot control what will be sent to your web server. At all. Ever.
So, you need to put restrictions on what you server will do, in response to anything sent to it. Part of this is validating all user input, even if it's JSON representing a JavaScript object that was created by your code.
I've recently tested UglifyJS and YUI Compressor and noticed something odd.
Both minifiers don't seem to change the names of object properties, only the names of variables and functions.
for instance if I have the following code:
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
the names first and second remain unchanged in the minified version.
Why is that?
Since in javascript a new scope is created in a function, you can scope your code in an immediately invoked function.
// scoped
(function() {
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
})();
Then using Google's Closure Compiler, if you turn on the "Advanced" optimization it will see that the properties are only used locally, and will obfuscate them.
// result
var a={a:2,b:4};alert(a.a+" "+a.b);
It's because it doesn't know where the object is going to be used. It could be used externally by other code and you wouldn't want your other code to have to change whenever you obfuscate it.
Edit So basically, it's like that to prevent obfuscation from breaking external/internal references to properties that may not be possible to figure out while obfuscating.
Since there are no well defined scoping rules around objects in JavaScript it's impossible to obfuscate the names in a way that is guaranteed to be correct.
For example, if you had the following function:
function f() {
return { first: 'foo', second: 'bar' };
}
In order to obfuscate the property names you would have to nail down all the places that f is called from. Since functions are first-class in JavaScript they can be assigned and passed around in arbitrary ways making it impossible to pin down where f is referenced without actually running the program.
Additionally, JavaScript doesn't have any way for you to specify intent around what's public API and what isn't. Even if the minimizer could reliably determine where the function is called from in the code you give it, there would be no way for it to make the same changes to code that it hasn't seen.
I guess that's because the minifiers would break the object properties. Consider this:
function getProp(ob,name) {
return ob[name];
}
var objName = {first: 2, second: 4};
var prop = getProp(objName, "second");
There's no way for the minifier to know the string literal "second" being an object property. The minified code could look like this then:
function a(b,c){return b[c]}var d={p1:2,p2:4};var e=a(d,"second")
Broken now.
The latest release of uglify (today) has object property mangling, see v2.4.19. It also supports reserved files for excluding both object properties and variables that you don't want mangled. Check it out.
The only public tool so far to obfuscate property and function names (afaik) is the Closure Compiler's Advanced mode. There are a lot of limitations and restrictions, but the end result is generally worth it.
As a passing note: the Dojo Toolkit is compatible (with some minor modifications) with the Closure Compiler in Advanced mode -- arguably the only large-scale public JavaScript library that can be fully obfuscated. So if you are looking at obfuscation to protect your IP, you should look into using Dojo for the task.
http://dojo-toolkit.33424.n3.nabble.com/file/n2636749/Using_the_Dojo_Toolkit_with_the_Closure_Compiler.pdf?by-user=t
Stephen
What about doing something like:
// scoped
(function() {
var objName = {first:2, second:4};
var vA = 'first';
var vB = 'second';
alert(objName[vA] + " " + objName[vB]);
})();
Once objName.first and/or objName.second are referenced enough times, this technique will start to save characters. I can't think of any reason that wouldn't work, but I can't find any minifiers that do it.