Running JS code in limited context - javascript

I'm trying to run trusted JS code in an "isolated" context.
Basically came up with this method:
function limitedEval(src, context) {
return (function() {
with(this) {
return eval(src)
}
}).call(context)
}
This works great, however when the script is using the var keyword it is stored in the execution context as opposed to the provided context in the with statement (which I understand is by design). So for example, the following code doesn't work:
var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo)', ctx); // error: foo is undefined
I'd like to be able to call limitedEval() multiple times and reuse the context. Is that possible?

This seems like a very interesting problem. The problem with your code is that you generate new function every time you execute limitedEval. This means that whatever variables you create using var keyword, will only exist within the context of that function. What you really need is to have 1 function per context and reuse that function's context. The most obvious way to do that is by using generators. Generators are essentially functions that can be paused and then restarted.
// IIFE to store gen_name
var limitedEval = function() {
// Symbol for generator property so we don't pollute `ctx` namespace
var gen_name = Symbol();
return function limitedEval(src, context) {
if(!(gen_name in context)) {
// Generator that will run eval and pause til getting the next source code
var generator = function * () {
with(this) {
while(true) {
yield eval( yield );
}
}
};
context[gen_name] = generator.call(context);
// Initially, we need to execute code until reaching the first `yield`
context[gen_name].next();
}
// First, send the source to the `eval`
context[gen_name].next( src );
// Second, get the `eval` result
return context[gen_name].next().value;
};
}();
And now you can call
var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo);', ctx);
Every limitedEval call will now reuse whatever generator function it will find on the provided ctx object. If the function doesn't exist, it will create it and put it on the ctx object. Because you now have only one function per ctx, it will reuse the function's context when creating variables with var keyword. Note: you will not be able to look up those variables via the ctx object, because they will only exist within the function's context.
I'm not entirely sure if you can achieve the same result without using generators.
Edit: others made great suggestions so I replaced randomly generated property with Symbol and did with(this) instead of with(context)

Related

Exporting p5.js function with Browserify

Here I have a p5 object that I am exporting to be bundled by browserify:
var p5 = require('p5')
var colorPicker = require('./color_picker.js')
module.exports = new p5(function () {
this.setup = function setup () {
this.createCanvas(700, 400)
this.background(205)
this.loadImage('/uploads/uploaded_image', function (img) {
image(img, 0, 0)
})
this.updatePixels()
}
this.clearCanvas = function redraw () {
this.background('black')
}
this.mouseDragged = function mouseDragged () {
var rgb = colorPicker.getRGB()
this.stroke(rgb.r, rgb.g, rgb.b)
this.strokeWeight(10)
this.line(this.pmouseX, this.pmouseY, this.mouseX, this.mouseY)
}
})
All of this works fine and I can access all built in p5 functions in other bundled scripts but not the clearCanvas function that I have defined. I also tried attaching it to the window object based on another SO post, like this:
window.this.clearCanvas = function redraw(){
//code
}
Everything so far has yielded Uncaught TypeError: Cannot set property 'clearCanvas' of undefined
Any idea what I'm doing wrong?
The modules build by browserify have their own scope, so nothing is exposed to the window object per default. You explicitly need to append your stuff to the window object to access it from a browser.
var p5 = require('p5')
var colorPicker = require('./color_picker.js')
module.exports = new p5(function () {
// ...
this.clearCanvas = function redraw () {
this.background('black')
}
// ...
window.clearCanvas = this.clearCanvas.bind(this);
});
First, for the section:
window.this.clearCanvas = function redraw(){
//code
}
To attach something to the window object do it directly,changing it to this:
window.clearCanvas = function redraw(){
//code
}
Worked, however I wanted to attach to the window object as infrequently as possible. For p5.js this section in the documentation is important:
By default, all p5.js functions are in the global namespace (i.e. bound to the window object), meaning you can call them simply ellipse(), fill(), etc. However, this might be inconvenient if you are mixing with other JS libraries or writing long programs of your own. To solve this problem, there is something we call "instance mode", where all p5 functions are bound up in a single variable instead of polluting your global namespace.
https://github.com/processing/p5.js/wiki/p5.js-overview
Running p5.js in instance mode allowed me to use the clearCanvas function without binding it to the window object.

What is the correct way of calling an internal function using the module pattern in Javascript

I am new to Javascript and am still getting my head round the various ways of creating objects i.e constructor+new, prototypal, functional & parts.
I have created what I think is an object factory using the module pattern and want to know what the correct method of calling an internal method would be. Is it via this or function name.
Here is my module:
function chart() {
function my() {
// generate chart here, using `width` and `height`
}
my.sayHi = function(){
console.log('hi');
my.sayBye();
};
my.sayBye = function(){
console.log('Bye');
};
return my;
}
var test = chart();
test.sayHi();
You can see that the first function calls the second using my.sayBye() or is it better to use this.sayBye(). Both produce the same result and run without error.
The module pattern allows you to dispense with the 'this' variable if you want to. I would probably rewrite the above code to look like this and then the question becomes moot.
function chart() {
var hiCount = 0;
function sayHi(){
console.log('hi');
hiCount++;
sayBye();
};
function sayBye(){
console.log('Bye');
};
return {
sayHi : sayHi,
sayBye: sayBye
};
}
var test = chart();
test.sayHi();
In the above code all is defined within the function chart. As JavaScript's scope is at the function level every time the chart function is called a new set of functions will be defined. And a new set of variables can also be defined that are private to the function as they are defined in the function and are not accessible from outside. I added hiCount as an example of how you could do this. The Module pattern allows privacy in JavaScript. It eats more memory than the prototype pattern though as each time a function is declared it is not shared between other instances of the same class. That is the price you have to pay in Javascript to have class variables that are private. I willingly pay it. Removing 'this' from my code makes it easier to understand and less likely that I will fall into problems of misplaced scope.
Using "this" is better approach because you would be able to bind the function directly to the parent function object.And you dont need to return anything from the function.
where as in your case you are explicitly returning another function
Here is the use of "this" approach
function chart() {
this.sayHi = function(){
console.log('hi');
}
}
var test = new chart();
test.sayHi();
Using this approach you would be able to call anything in the prototype of function "chart"
Eg
chart.prototype.hello = function(){
console.log('hello')
}
So you would be able to call the hello function from the same object(test)

Wrapping a namespace with a self-executing function

I'm building a game and was trying to figure out the workings of the melonJS game engine I am using. I'm at a point where I need to create my own version of their CanvasRender object, so was trying to understand what they've done.
Why wrap the canvas renderer in an anonymous, self-invoking function? Can't I just create the function as such?
me.CanvasRenderer = me.CanvasRenderer || {};
me.CanvasRenderer = {
init: function() {
//...
Or even within a namespace:
var CanvasStuff = {
CanvasRenderer : function() {
}
};
CanvasStuff.CanvasRenderer();
I don't understand how they've laid out this code and the purpose. How and when is (function () { invoked?
Here's a snippet of their code: (link to full code)
(function () {
// The canvas renderer object
me.CanvasRenderer = (function () {
var api = {},
var canvas = null,
//...
api.init = function () {
//...
};
return api;
//...
})();
})();
The self-invoking function is executed immediately, so it is similar to the alternatives you posted.
However, the advantage of the self-invoking function is that you can declare variables within that scope that are not accessible outside the closure. For example, in the code snippet you posted there is a var canvas that is accessible within any of the api functions, but not accessible to any outside code. In the first alternative you suggested, there is no way to declare canvas without it being accessible to any clients/callers of the api. Your second alternative (the namespace) isn't filled out enough to see how it would be used, so you might be able to wrap private vars into that closure as well.

Global variables in Javascript (jQuery)

So this is the first time I am using Javascript in a much more powerful context, having a thick client and doing much of the heavy-lifting through javascript in itself. I am using jQuery, and a lot of the code is getting muddy at the moment coz it's all just a bunch of functions.
Turns out for some of my functions, I required variables to be passed through multiple functions with their value being maintained. The obvious way of doing this is by declaring them outside of the scope of the function and then have the function manipulate it the way it ought to . (These variables are objects and not primitive type, so I guess javascript being pass by reference, this works).
For instance, I probably have something like this
var node = //init with some value;
$(document).ready(setup);
function setup()
{
A();
B();
}
function A()
{
// operate on var node
}
function B()
{
// operate on var node
}
This is obviously a scaled down version of my code, but captures the way I deal with global variables. My question is, is there a more elegant way to do the above ?
Thanks
Any reason why you can't do:
$(document).ready(function() {
var node = //init with some value;
setup(node);
function setup(node) {
A(node);
B(node);
}
function A(node) {
// operate on var node
}
function B(node) {
// operate on var node
}
});
In general, using global variables and functions is a bad idea and should be avoided wherever possible.
Note that while you appear to have been asking specifically about node, your functions setup, A and B are also all global variables in your version.
The simplest approach would be to put all these declarations inside an anonymous function:
$(document).ready(function() {
var node = ...;
function A() {
...
}
function B() {
...
}
function setup() {
A();
B();
}
setup();
});
Only use one global variable (or as few as possible). Make any functions or objects members of your one global variable.
Douglas Crockford says
An objective measure of the quality of a JavaScript program is How
many global variables and global functions does it have? A large
number is bad because the chance of bad interactions with other
programs goes up. Ideally, an application, library, component, or
widget defines only a single global variable. That variable should be
an object which contains and is the root namespace for all of your
stuff.
Yahoo’s single global is YAHOO. It is spelled in all caps to identify
it as something special, since all lower case is ordinary and initial
caps indicates a constructor. Being in all caps, it is unlikely that
someone would use it accidentally, which further reduces the
likelihood of collision.
http://www.yuiblog.com/blog/2006/06/01/global-domination/
Also, you can create objects to further organize your code.
GLOBAL.myObject = {};
GLOBAL.myObject.myFunction = ...
I prefer the "revealing module" pattern:
var myApp = (function () {
// privates
var node;
var a = function () {
// operate on node
};
var b = function () {
// operate on node
};
// publics
var init = function () {
// initialization stuff
a();
b();
};
return {
init: init
};
})();
$(document).ready(function () {
myApp.init();
});
This way you only ever have one global, myApp, which stores everything else your app needs.
I think it makes the code harder to understand, I'd much rather take the variable in as an argument and have it as a return.
$(function(){
var outcome = multiply(add(5));
});
function add(num)
{
return num+1;
}
function multiply(num)
{
return num*5;
}
If you feel like you absolutely want to have global variables wrap your stuff in a closure so it doesn't actually go to a global scope.
ie,
(function(){
var a; // can be used in any functions within this closure, but not polluting window
function A()
{
a = 'blah';
}
})();
There are many. For instance, objects.
// jQuery shorthand for "wait till DOM ready"
$( function() {
// create node object
var node = {
id: /* some value */,
setup: function() {
this.A();
this.B();
},
A: function() {
// operate on this.id
},
B: function() {
// operate on this.id
}
};
// setup node object
node.setup();
} );
Global variables are trouble waiting to happen. Don't dirty up your global namespace. Javascript is an object oriented language, use objects. Notice your object can have a property that you can reference with the this keyword from within the objects methods.

Trying to find a proper way to have global access to a canvas

I'm still kinda new to Javascript and noticed in lot of places in my code I am using JQuery to get a reference to my canvas element like this:
$('#myCanvas')[0].getContext('2d');
I have my suspicions that it is slowing my site down because I have it in a lot of places that may be called quite often. Ideally, I'd just do this once and access the context from any javascript page.
I tried to make a global variable but it didn't see to work (probably because it runs before the page can load) so instead I put this function in global scope in my first referenced javascript file:
var drawingCanvasContext;
function getDrawingCanvas() {
if (drawingCanvasContext == null) {
drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
}
return drawingCanvasContext;
}
So then whenever I need the canvas in my code I just call that method.. But it just seems rather.. messy. I doubt this is an uncommon desire so I'm curious of the proper solution. I'd prefer it just to be a variable instead of a function and to be accessed globally without all these null checks. Does anyone know how to accomplish this? Thanks.
You can simply do this
var drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
instead of defining a function for that.
If you're careful about global scope pollution, you should wrap it up in a function or use namespacing. E.g.
var myNamespace = myNamespace || {};
myNamespace.drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
I've got only two little improvements on your code:
(function(){
// move the var out of the global context by wrapping everything in a closure
var /* static */ drawingCanvasContext;
function getDrawingCanvas() {
if (!drawingCanvasContext) // no need to check for null, defaultvalue is undefined
drawingCanvasContext = $('#myCanvas')[0].getContext('2d');
return drawingCanvasContext;
}
window.getDrawingCanvas = getDrawingCanvas;
})();
Of course you could/should put that method in a namespace object, I guess you have more than one of such.
Ultimately all you can do is store the context around to be retrieved afterwards. The problem I can see here is probably an order of operations, the context is being requested before the page is ready, and possibly you're losing scope with your VAR declaration (i think).
;(function($, window, document) {
/* private */ var canvas = null;
/* private */ var context = null;
$(document).ready(function() {
canvas = $("#myCanvas")[0];
context = canvas.getContext('2d');
$('body').trigger('CanvasReady', [canvas, context]); // You can fire an event to bind to with jquery for when the canvas is ready.
});
/* public */ window.getCanvas = function() { return canvas; };
/* public */ window.getCanvasContext = function() { return context; };
// You can also use a namespace here too if you want
// window.Canvas = {};
// window.Canvas.GetContext = ... etc ...
})(jQuery, window, document);
This will aquire the canvas when it's ready, fire an event you can subscribe to for when the canvas has been found and is ready for manipulation.
It will expose 2 functions globally:
getCanvas which will get you the Canvas Instance
getCanvasContext which will get you the Canvas Context
You can adapt this to use a registry pattern if you want so it can aquire & store multiple canvas elements/contexts but this is just a simple pattern to show you.
Note: It returns null if the methods are called before the canvas/document is ready, you should be doing all of your setup code after domReady anyway.
You can define a getter on your global variable that will execute each time you read from that variable (see here for tips on making this backward compatible):
var _drawingCanvasContext;//behind the scenes variable that keeps the value
Object.defineProperty(this, "drawingCanvasContext", {
get: function() {
return _drawingCanvasContext || (_drawingCanvasContext = $('#myCanvas')[0].getContext('2d'));
}
});
Here's a fiddle where I set it to 'foo' to show you how it works.

Categories

Resources