I trying to create a sandbox module that can take a object and prevent that object's code reference to window.
here is how it work in concept.
var sand = function(window) {
var module = {
say: function() {
console.log(window.location);
}
};
return module;
}
sand({}).say(); // window.location is undefine
This doesn't work if the object is pass-in
var $sand = (function(){
return function(obj, context) {
return (function(obj, window) {
window.module = {};
// doesn't work even copy object
for (p in obj) {
window.module[p] = obj[p];
}
console.log(window.location); // undefine
return window.module;
}(obj, context));
};
}());
var module = {
say: function() {
console.log(window.location);
}
};
$sand(module, {}).say(); // still reference to window.location
How can i make this pattern work?
As long as you don't have a variable shadowing window in the scope of your function, the function will be able to access window. Even if you had a variable called window, the code will still be able to access the properties by simply omitting window..
(function(window) {
console.log(window.location); //undefined
console.log(location); //this will still work
})({ });
In other words, sandboxing JavaScript in a browser environment is not possible like this.
In your first example, the only reason window is undefined is because you are passing in an empty object and calling the argument window, so it is hiding the real window.
Also, you can always get access to the window object by hoisting the this variable inside a closure, like so:
console.log ( ( function () { return this; } )() );
So even if you somehow manage to block window, it's trivial to get it back again.
If you define the function outside your sandbox, the context will be the current one, and you can't really do otherwise.
If you really want to do some sandboxing, then you should use iframes to achieve that. Take a look at https://github.com/substack/vm-browserify it is a browser version of the vm module of node, you should be able to extract some good pieces of work, and avoiding eval which is not really clean for what you want to do.
Related
I am working with some JavaScript that a colleague wrote and need to override one of the functions in another script file that will be loaded after the first.
I think the problem is that the function I want to override is part of a return object within an immediate function so I cannot access 'private' variables that the original uses in my overridden version as they are out of scope by that point. Perhaps and example would help. The structure looks like this:
(function(){
// stuff here
$.obj=(function(){
var initialized=false;
return {
init:function(){ \\ stuff here}
}
}()
})();
In my override I want to do something like:
$.obj.init = function(){
// different implementation but with access to value of 'initialized'
}
Is there a way that I can achieve what I'm looking to do?
You'd need to make the private variable accesible:
(function(){
// stuff here
$.obj=(function(){
this.initialized = false;
return {
init:function(){ \\ stuff here}
}
}()
})();
so you can access it later:
$.obj.init = function(){
// different implementation but with access to value of 'initialized'
this.initialized = true;
}
But be aware that, for this to work, you need to create an object. I mean, you need to call obj like this:
var newObj = new $.obj();
Let's start from the code:
function say(name) {
var ghost=function () {
function ghost() {
alert('!');
};
return body;
};
eval("var body=''+"+name+';');
eval(name+('=('+ghost).replace('body', body)+')();');
eval(name+'();');
}
function Baal() {
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
say('Baal'); // or just Baal();
Looks like that saying the devil's name invoke his presence (well, maybe he needs somebody for spiritual possession) ..
As you can see the ghost doesn't exist along with Baal, but we can invoke it since there're evals in say(name).
say(name) reassigns Baal to its code body as a closure and makes it captured a ghost method, that's how things work. But I'm trying to avoid eval ..
So .. let me reword the question:
How do I make a nonexistent(and not a member or global) method invocable without using eval?
Let me rephrase your question, just to make sure I’ve got it. Given a function, you want to put a new variable in its scope, without that scope being the global scope or a scope shared between the caller and the subject, without using eval (or the equivalent new Function and other hacks depending on the environment).
You can’t.
In the case you just mentioned, you could define one function, base(), that uses arguments.callee.caller.
Don’t do that.
The short answer: You don't.
That scope is not available. If you were to attach the scope then it would be available inside of the scope used. You could then access the method handles. I assume this is not what you were looking for, but here is what that would look like. demo
function say(name){
var methods = {};
methods.Baal = function(){
alert("!");
};
return methods[name];//this could invoke as well: methods[name]()
}
var handle = say('Baal');
handle();
What your evals break down to is something along these lines (although with dynamic content from string building - this is the end result)
function say(name) {
var Baal = (function () {
function ghost() {
alert('!');
};
return function(){
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
})();
Baal();
}
say('Baal'); // or just Baal();
Note that the meat of what happens here is from the function Baal, namely that it calls a hardcoded ghost() which in turn calls a hardcoded alert. Why go through all of this trouble to access a hardcoded function?
A better way would be to inject this function as a callback which expects some parameters to be injected.
jsFiddle Demo
function say(callback){
var params = "!";
if( typeof callback == "function" ){
callback(params);
}
}
say(function(params){
alert(params);
});
It's very difficult for me to read through your code and figure out what you are trying to accomplish with it, but it appears that you are trying to introduce a variable into the current scope so that you can call it. You cannot do this in javascript with the method that you demonstrated. Scoping only ever "flows down". By that I mean that a variable or function defined within a function will only be available to that function and any other functions defined therein. Your function named ghost will only ever be available within the function where it is defined, regardless of when that function is evaluated.
What you can do, however, is write a function that returns a function. You can then call that function and assign the result to a variable in the scope where you want to expose functionality. Doing that would look something like this.
function defineSpecialAlert() {
return function(name) {
alert(name + "!");
};
}
var newlyDefinedMethod = defineSpecialAlert();
newlyDefinedMethod("Baal");
So if I understand, it seems like you want to create an alias of eval: Something like
#Note this code is not intended as a solution, but demonstrates
#an attempt that is guaranteed to fail.
#
function myAlias(ctx) {
eval.call(ctx, 'var ghost = 42');
}
myAlias(this);
alert(ghost);
Javascript allows many funky sleight-of-hand tricks especially with closures, but this is maybe the one impossible thing that javascript cannot do. I've tried at length to do this exact same thing, and I can tell you that you'll run into nothing but complaints from the browser, saying that eval cannot be re-contexted or aliased in any way.
Hello i have the following issue i am not quite sure how to search for it:
function(){
var sites;
var controller = {
list: function(){
sites = "some value";
}
}
}
So the question is how to access the sites variable from the top defined as
var sites
EDIT:
Here is a more complete part. i am Using marionette.js. i don't want to define the variable attached to the Module (code below) variable but keep it private to the Module, hope that makes sense. Here is the code that works:
Admin.module("Site", function(Module, App, Backbone, Marionette, $, _ ) {
Module.sites = null;
Module.Controller = {
list: function (id) {
Module.sites = App.request("site:entities");
}
};
});
and i would like instead of
Module.sites=null;
to do
var sites;
That sort of thing does make a difference right? Because in the first case i would be defining an accessible variable from outside where as the second case it would be a private one. i am a bit new to javascript so please try to make it simple.
if you are looking for global access, just declare the variable outside the function first, make your changes to the variable inside the function, then you can get the value whenever you need it.
I have found some info on this: sadly what i am trying to do doesn't seem possible.
Can I access a private variable of a Marionette module in a second definition of that module?
So i guess i have to do _variable to make developers know its private.
Disclaimer: I have no experience using Marionette, however, what you're describing sounds very doable.
One of the most powerful (in my opinion) features of JavaScript is closures. What this means is that any function declared from within another function has access to the variables declared in the outer function.
For example:
var func;
function foo() {
var answer = 42;
func = function () {
// I have access to variable answer from in here.
return answer++;
};
}
// By calling foo(), I will assign the function func that has access "answer"
foo();
// Now I can call the func() function and it has access to the "answer"
// variable even though it was in a scope that doesn't exist anymore.
// Outputs:
// 42
// 43
console.log(func());
console.log(func());
What this means is that if you declare var sites from within your module definition function as you described, you should have access to it from within any of your inner anonymous functions. The only exception is if Marionette is re-writing your functions (by using the Function function and toString()), which seems unlikely but possible.
Your original example should would as described, my suspicion is that there is something else going wrong with the code that is unrelated to your scope.
I have a difficulty in understanding, how my current JavaScript code works. I've managed to solve a problem in accessing private object method from event handler closure, but I'd like to know why does it work so.
The code utilizes the well-known module/plugin metaphor:
(function(module, $, undefined)
{
function myPrivateCode(e){ /*...*/ }
module.myPublicCode = function(e) { /*...*/ }
module.init = function()
{
var that = this;
$('.clickable').click(function(e)
{
if($(e.target).hasClass('classX'))
{
that.myPublicCode(e.target); // requires 'that' to work
}
else
{
// that.
myPrivateCode(e.target); // will fail if 'that' uncommented
}
});
}
}(window.module = window.module || {}, jQuery ));
In the code I set a click handler which invokes either public or private method. It's perfectly conceivable that we need to pass an object reference into the event handler closure, which is done by that local variable. What is strange to me is that myPrivateCode does neither require that as a refernce, nor fails due to its "privacy". This makes me think that myPrivateCode accesses not the appropriate object, and works somehow differently to expected way. Could someone explain what happens? Certainly I'm missing something.
Both that and myPrivateCode are available to your event handler through a closure. In short, what's going on is that every variable and function you declare inside of another function has access to the outer scope.
myPublicCode, on the other hand, is not available through closures, because it's being assigned to your module object specifically. So the only way to call it is by using module.myPublicCode() (or that.myPublicCode() as you did – but you don't actually need that there, since module is also available).
Your call to myPrivateCode(e.target); is running in the context of the anonymous function that you pass as a handler to the click function.
For more information, read up on closures.
For a simpler example, try out this code:
var foo = function () {
var a = 1;
return function (b) {
return a+b;
}
};
var bar = foo();
bar(1); // 2
bar(1) will always always gives 2, because a = 1 was in scope when the function was created. In your case, a is your that and your handler is the closed function.
http://jsfiddle.net/Fh8d3/
Is it possible to copy a function (or any object for that matter) from one window context to another in Javascript?
Let's say I have a parent window with a frame in it. The frame defines a function foo(), which I'd like to copy to the outer window. (One reason to do it would be so that foo() is available when the frame document navigates to a different URL.)
I know I can easily create a reference to foo() in the parent by doing
function foo() { ... }
parent.foo = foo;
But with this method foo() still lives in the frame document, and will not be available to the parent should frame get unloaded.
I know I can also create a new function in the parent by using the Function constructor:
parent.foo = new parent.Function(" ... ");
However, this requires me to have my function as a JS string.
DOM supports moving nodes from one document to another via importNode(). Does Javascript have a similar feature?
nitko's solution seems to be correct, though a little more work is required. This function seems to work on FF2, FF3, IE7 and Chrome:
function importFunction(fn, win) {
var code = fn.toString();
var params = code.match(/\(([^)]*)\)/);
if (typeof(params[1]) !== 'undefined') {
params = params[1].split(/\s*,\s*/);
} else {
params = null;
}
code = code.replace(/^[^{]*{/, '');
code = code.replace(/}$/, '');
if (params) {
return new win.Function(params, code);
}
return new win.Function(code);
}
The returned function can be used in the needed window. Something like:
parent.foo = importFunction(foo, parent);
You can always get the code for a given function calling it's toString() method:
parent.foo = new parent.Function( originalFunction.toString() );
Though I don't certainly know it's available in every browser, I think I've seen it working in major browsers, modern versions.