Here's the deal,
we have a big JS library that we want to compress, but YUI compressor doesn't fully compress the code if it finds an "eval" statement, out of fear that it will break something else.
That's great and all, but we know exactly what is getting eval'd, so we don't want it to get conservative because there's an eval statement in MooTools JSON.decode
So basically the question is, is there any alternative (maybe creative) way of writing a expression that returns the eval function?
I tried a few, but no dice:
window['eval'](stuff);
window['e'+'val'](stuff);
// stuff runs in the global scope, we need local scope
this['eval'](stuff);
// this.eval is not a function
(new Function( "with(this) { return " + '(' + stuff + ')' + "}"))()
// global scope again
Any ideas?
Thx
Thanks for all the ideas, I ended up just doing text replacement in the build script that outputs the JS, basically replacing $EVAL$ with eval, after everything has been compressed. I was hoping for a purely JS way, but with so many different eval browser implementations, it's probably better to just leave eval alone
But based on Dimitar's answer and some fiddling around, here's what I found.
Seems like the reason why this['eval'] wasn't work is because the place where it's happening, in MooTools JSON.decode, is also a inside a Hash:
var JSON = new Hash({
// snip snip
decode: function(string, secure) {
if ($type(string) != 'string' || !string.length) return null;
if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '#').replace(/"[^"\\\n\r]*"/g, ''))) return null;
return this.eval('(' + string + ')'); // Firefox says: TypeError: this.eval is not a function
}
});
However, if I store the "top level" local scope (all the code, including mootools, runs inside an anonymous function), then it works:
var TOP = this;
var JSON = new Hash({
// snip snip
decode: function(string, secure) {
if ($type(string) != 'string' || !string.length) return null;
if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '#').replace(/"[^"\\\n\r]*"/g, ''))) return null;
return TOP.eval('(' + string + ')'); // All good, things run within the desired scope.
}
});
However this doesn't work in Safari, so bottom line is, what I was trying to do can't be done cross-compatibly. eval is a special touchy function and every browser treats it differently.
Not sure if I understood you, but you can apply a function to a specific local (this) scope:
var x = 5;
var f = new Function('alert(this.x)');
function A(x){
this.x = x;
f.apply(this,[]);
}
a = new A(10);
This alerts 10 as f is applied with A.this
Could refactor eval calls to some external shim function that is not part of the file being compressed?
am i missing something?
var noteval = this.eval; // can be defined before the file is loaded
noteval("alert('not eval. at all');");
(function() {
console.log(this);
noteval("alert('chavs!');");
}).bind(window)();
(function() {
console.log(this);
noteval("alert('crappy parents');");
}).bind(window.parent)();
check it http://www.jsfiddle.net/nGL79/ with the frames as different eval scopes.
and specific to mootools:
window["ev"+"al"].pass("alert('what');")();
this["ev"+"al"].pass("alert('no!');")(); // local scope too?
and
var noteval = window["ev"+"al"].create({
bind: this
});
hope some of that helps... hope you don't get function eval must be called directly, and not by way of a function of another name though
var e = "e";
window[e+"val"](stuff);
If possible you may want to try one of the other compression libraries since YUI isn't the only game in town anymore.
Here is a couple articles on the other compression tools available.
http://www.coderjournal.com/2010/01/yahoo-yui-compressor-vs-microsoft-ajax-minifier-vs-google-closure-compiler/
http://www.coderjournal.com/2010/01/performance-optimizations-made-by-microsoft-google-and-yahoo-javascript-minimizers/
Microsoft and Google seem to do a better job than YUI anyways.
This way needs jQuery.
function NotEval(code, callBack) {
$.ajax({
url: 'data:application/javascript;charset=utf-8,' + encodeURIComponent(code),
cache:true,
success: function (r) {
if (typeof callBack === "function") {
callBack()
}
},
error: function (r) {
console.log("Eval error");
console.log(r)
}
})
}
Related
I have a bunch of extension methods of String and other JavaScript types, they now reside in global namespace.
What is the best practice to organize those extension methods? Should I encapsulate them inside a namespace? If yes, how to achieve that? Thanks!
Namespace your JavaScript if you need to refer to it elsewhere.
// define your global namespace
var Extensions = Extensions || {};
// add modules to it
Extensions.String = function() {
var myPrivateProperty = 2;
var myPublicProperty = 1;
var myPrivateFunction = function() {
console.log("myPrivateFunction()");
};
var myPublicExtension = function() {
// this extension is being called, now what?
console.log("myPublicExtension()");
};
// this object will be returned, giving access to public vars/methods
return {
myPublicProperty: myPublicProperty,
myPublicExtension : myPublicExtension
};
}();
console.log("Calling myPublicExtension()...");
Extensions.String.myPublicExtension();
Anonymously scope JavaScript if you’re never going to call it elsewhere.
// This will keep your namespace clean
(function() {
// here you can define your modules, functions, etc..
var x = 123;
console.log(x);
// to make something global you can define it like
window.globalVar = 5;
}());
Or you can extend the native javascript objects with prototype like this:
String.prototype.myExtension = function(p1, p2) {
// here is your function
return this + p1 + p2;
}
This way you don't need to define namespaces and you can call your extensions directly from any object you extended:
var otherString = "mystring".myExtension(" is", " great!");
console.log(otherString);// mystring is cool
you can do that with any object in javascript
EDIT:
Prototype extensions don't pollute global namespace, because they are accesible only through the object you extended.
If you have many extensions consider taking them into a file like extensions.js, then add it to your pages whenever you need those extensions. This way extensions.js can be cached by the browser and will be loaded faster
There are 2 ways of doing that:
Encapsulating in a namespace (I think the bare minimum to keep things tidy). A custom namespace ie:
window.MyNameSpace.trim = function(str) {
return str.replace(/^\s+|\s+$/g, "");
}
(replace MyNameSpace with a single letter! R for Raphael, L for Leaflet, etc)
Extend prototypes! Lots of people will disagree with that but I see no harm if it is your site and you don't override/conflict with anyone else code:
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, "");
};
I find this "cleaner" since you don't pass unnecessary arguments around... but again, it is a matter of opinion... This will work for any build-in type. The rest I think should follow #1
DISCLAIMER: Code from This post
I would like to setup a console in the web browser using form fields. It needs to behave much like nodejs's repl (command line). In fact, I will be using the same API in both.
This falls-short because the properties in context are only available under this. Can you please suggest a tweak to get this going? It is ideal if I can keep context unchanged, I use this object to loop (via Object.keys(context)` and set properties on nodejs' repl context.
var context = {
debug: 'I am debug'
}
function evalInContext(js) {
return function() { return eval(js); }.call(context)
}
//This does not need to work, but it
//confirms that the context is under 'this'
evalInContext('console.log(this.debug)') //prints 'I am debug'
//This really needs to work:
try{
evalInContext('console.log(debug)')
}catch(e){
//not good: ReferenceError: debug is not defined
console.log(e)
}
evalInContext('var a=2')
try{
evalInContext('console.log(a)')
}catch(e){
//not good: ReferenceError: a is not defined
console.log(e)
}
http://jsfiddle.net/hy8hewq4/
This in no way removes the dangers of eval, however you can create some String from an Object which evals as a var statement that you do in your function before evaling the other piece of code.
In my example below it is very important that the keys of variables are valid identifier names and note the values are turned into JSON to protect them from tampering across invocations, if you want functions etc you'll have to implement them your own way
var variables = {
variables: undefined, // shadow self
debug: 'foo'
};
function evalWithVariables(code) {
var key, variable_string = '';
for (key in variables) {
variable_string += ', ' + key + ' = ' + JSON.stringify(variables[key]);
}
if (variable_string.length) eval('var' + variable_string.slice(1));
return eval(code);
}
evalWithVariables('console.log(debug)'); // logs foo
You may wish to combine this with another abstraction to achieve your own this (as you're currently doing)
You may also wish to put this definition inside an IIFE that just returns your custom eval function to protect the references to your variables Object, etc
<script type="text/javascript>
(function($, win) {
function mySettingsInitJS () {
var self = this;
var opts = {
'params' : "userId=" + userId;
};
self.init = function() {
self.initUnlinkAction();
};
self.initbtnAction = function() {
$('#Btn').click(self.btnAction);
};
self.btnAction = function(e) {
if(e) { e.preventDefault(); }
jQuery.post(
'http://abc/rest/PostRequest',
opts.params, function(data) {
alert('This worked!');
}, "json");
};
}
function win.MyFilesSettingsInitJS = new MyFilesSettingsInitJS();
}(jQuery, window));
</script>
I have this this script in a velocity template page and a Btn also in it. Which is basically a fancy Link. I am also sure the rest API on the server side is working fine. But somehow my java script function is not called. Could some one please help me ?
Seems like you forgot quotes here:
'http://abc/rest/PostRequest'
It becomes pretty obvious with good syntax highlighting. Plus if you use JSLint or similar it will find most problems, as well as the console when debugging your code.
Your URL value needs to be a string...add quotes to it
You should use some developer tools available in the browser. Most browsers have at least an error console that would display any JS errors. For example, this code has several syntax errors:
In var opts = { 'params' : "userId=" + userId; }; it is illegal to end a line with ; when you're defining an object literal (a.k.a. map or dictionary).
Again at this line, where is userId defined? It is a bad practice to have global variables, so if userId is a global variable defined in another script, you should refactor the code
function win.MyFilesSettingsInitJS = new MyFilesSettingsInitJS(); is illegal, since you're adding a property to an object, you're not declaring a function or a variable. Just use win.MyFilesSettingsInitJS = new MyFilesSettingsInitJS();
Actually, that might be wrong as well, since above you defined mySettingsInitJS, not MyFilesSettingsInitJS (but that function could actually be defined somewhere else, I don't have the whole code)
I was reading through the javascript design patterns book and came across the code below, while reading "The Command Pattern". I've been trying to understand why this code is wrapped around an anonymous function which is immediately invoked, especially since there is no other private variables to be closured with. How is this different from just declaring CarManager as an object literal?
(function(){
var CarManager = {
// request information
requestInfo: function( model, id ){
return 'The information for ' + model + ' with ID ' + id + ' is foobar';
},
// purchase the car
buyVehicle: function( model, id ){
return 'You have successfully purchased Item ' + id + ', a ' + model;
},
// arrange a viewing
arrangeViewing: function( model, id ){
return 'You have successfully booked a viewing of ' + model + ' ( ' + id + ' ) ';
}
};
})();
The example is slightly half-baked.
The goal is to be able to provide a public-interface.
Inside of that IIFE, you put together all of the pieces required for your interface.
You don't have to pass it back out through a return statement.
jQuery, for example, is built in the same way.
Instead of having a return statement:
var jQuery = (function () { return magic; }());
They manually set window's jQuery (and $) properties from within the function, like so:
(function () { window["jQuery"] = magic; }());
Moreover, what's actually happening is a little bit different, still.
They're passing the window object into the IIFE's window parameter.
It doesn't have to be window, then.
It could be any previously-defined object you're extending, in theory.
var myApp = {};
(function (window, document) { window["jQuery"] = public_interface; }(myApp, document));
myApp.jQuery("...");
When building libraries similar to jQuery, you can do similar.
If you typically namespace any large libraries/applications (a good idea), you can shorten the name, internally, to make life easier.
Instead of:
var NAMESPACED_AWESOME_APP_OF_DOOM = {};
NAMESPACED_AWESOME_APP_OF_DOOM.module1 = {};
You can do something like:
(function (namespace) {
var ns = {};
window[namespace] = ns;
ns.module1 = {};
ns.module2 = {};
ns.service1 = function () {};
}("NAMESPACED_AWESOME_APP_OF_DOOM"));
Then you can do all of your internal setup inside, and once your setup is complete, you can reference the application by name, in the global scope.
In other cases, you can create sandboxes for code, using closures in this way, with mediators to send messages back and forth between components.
Nicholas Zakas has a couple of good talks on this.
And lastly, sometimes you just want some work to get done, which is 100% irrelevant to the rest of your program, but still needs to get done, all the same (like doing compatibility-checks and tying the results to the DOM elements, a la Modernizr... ...or setting cookies that just need to be there, or firing off calls to analytics software... ...et cetera).
In this specific instance, the anonymous function only serves to keep CarManager from being accessible elsewhere, i.e. entering into the global scope.
Also specific to this code instance, its entirely pointless. CarManager is not usable by any other code.
Looking at the link you provided in the comments, http://addyosmani.com/resources/essentialjsdesignpatterns/book/#commandpatternjavascript
As far as I can tell, the entire section of code being documented, in addition to the CarManager.execute bit, will completely fail to work. Trying to define CarManager.execute = ... outside of the anonymous function will fail because CarManager doesn't exist.
I'm the OP. Based on the discussion above, and after trying to interpret what the author wanted to express, I'm coming to a conclusion that the following code might have been what the author wanted to express. At least for me this seems to make sense.
(function(){
var CarManager = {
requestInfo: function(model, id){
/* blah blah */
},
buyVehicle: function(model, id){
/* blah blah */
},
arrangeViewing: function( model, id ){
/* blah blah */
}
};
CarManager.execute = function(name){
return CarManager[name] && CarManager[name].apply(CarManager, Array.prototype.slice(arguments, 1));
}
return CarManager;
}());
Basically, I added the part where the anonymous function execution returns the CarManager object literal. Also, I placed the execute method before returning (Although I don't quite understand why it should be outside of the original CarManager object, other than potentially code readability) What do you think?
(By the way, the web version of the section of the book is here: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#commandpatternjavascript )
I'm trying to write 'better' javascript.
Below is one pattern I've found, and am trying to adopt. However, I'm slightly confused about its use.
Say, for example, I've got a page called "Jobs". Any JS functionality on that page would be encapsulated in something like:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
As you can probably deduct, all I've done is replaced all the code that would have sat inside the anonymous event-handler function, with a call to a function in my global jobs object. I'm not sure why that's a good thing, other than it's reduced the possibility of variable collisions and made the whole thing a bit neater, but that's good enough for me.
The - probably fairly obvious - question is: all my event-binding init-type stuff is still sitting outside my shiny new jobs object: where should it be? Inside the jobs object? Inside the return object inside the jobs object? Inside an init() function?
I'm just trying to get a sense of a stable, basic framework for putting simple functionality in. I'm not building JS apps, I'd just like to write code that's a little more robust and maintainable than it is currently. Any and all suggestions are warmly welcomed :)
You can break down your application in whatever number of modules / objects you like too.
For instance, you can have another object / module which caches and defines all your DOM nodes and another one, which just handles any event. So for instance:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
It doesn't really matter how you create singletons in this (module) pattern, either as literal, constructor, Object.create() or whatnot. It needs to fit your requirements.
But you should try to create as many specific modules/objects as necesarry. Of course, if makes even more sense to separate those singletons / modules / objects into multiple javascript files and load them on demand and before you can say knife, you're in the world of modular programming patterns, dealing with requireJS and AMD or CommonJS modules.
Encapsulation-wise, you're fine: you could even just declare addNew in the jQuery closure and you'd still avoid the global scope. I think what you're getting at is more of implementing something close to an MVC architecture.
Something I like to do is create an object that you instantiate with a DOM element and that takes care of its own bindings/provides methods to access its controls etc.
Example:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
The way you are doing it right now is exactly how I do it also, I typically create the window objects inside the anonymous function itself and then declare inside that (in this case: jClass = window.jClass).
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
The reason I leave them completely anonymous like this, is that let's say in another file I want to add much more functionality to this jClass. I simply create another:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
As you can see I prefer the object.object notation, but you can use object literals object : object, it's up to you!
Either way by leaving all of this separate, and encapsulated without actual page logic makes it easier to have this within a globalJS file and every page on your site able to use it. Such as the example below.
jClass._log('log this text for me');
You don't want to intertwine model logic with your business logic, so your on the right path separating the two, and allowing for your global namespace/class/etc to be more flexible!
You can find here a comprehensive study on module pattern here: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html It covers all the aspects of block-scoped module approach. However in practice you gonna have quite a number files encapsulating you code, so the question is how to combine them property. AMD... multiple HTTP requests produced by every module loading will rather harm your page response time. So you can go with CommonJS compiled to a single JavaScript file suitable for in-browser use. Take a look how easy it is http://dsheiko.github.io/cjsc/