Apply `this` to variables in function auto - javascript

I want to parse function dynamic and apply this to variables in the function auto.
var functionContent = "console.log(v)";
var context = {v:'show some thing'}
(new Function(functionContent)).apply(context);
The parsed function will throw an error about can't found v. If I use console.log(this.v) instead, everything will be ok. But for better experience of end users, I don't want use this in functionContext. How can I do this?

What you want to do in javascript terms is called binding. You're setting the function scope for another function to an object.
var ctx = {v:'show some thing'};
var newFunction = (new Function("console.log(this.v)")).bind(ctx);
newFunction();
I would also state, as the other answer does, that this is not a great thing. new Function actually does use eval under the hood, it's basically just
eval("function(yourParams) { " + yourCode + "}")
Whether or not to get rid of it, well that's up to you. If it's used on the broader internet and loads up some data people can edit... then yeah it may be an issue, but less so if it's just something small to play around with.

Related

Executing javascript functions stored as string using AngularJS

Is there any way to inject JavaScript code stored in a string in AngularJS controllers dynamically?
var dynamicJS = "function DoSomething(value){var x = 1+1 return 2;}"
I have to dynamically inject the above function into my AngularJS controller and have it be called on selection change of drop-down, the values of which are bound to the AngularJS controller. The reason is the JavaScript function would vary based on my each row of data which I have based on my configuration at an application level. I am aware we can make use of $eval but would like to get some better approaches, if any exist.
Can anyone give me any idea on this?
Note: I am using AngularJS v1.4.5
I would believe the easier way will be to parse the String and then use the function constructor.
Something like this:
var DoSomething = new Function('value', 'var x = 1+1 return 2');
There are multiple ways to achieve this.
Function object
Create a Function, passing the one argument (i.e. value) and functionBody as parameters:
var dynamicJS = "var x = 1+1; return 2;"
var DoSomething = new Function("value", dynamicJS );
eval()
While arguably more dangerous1, eval() can be used.
var dynamicJS = "function DoSomething(value){var x = 1+1 return 2;}"\
eval(dynamicJS);
Because you mentioned in a comment
"it is intranet application and not going to outer world. no issues on this for this req."
this would likely be fine but please read the section below.
Caution
From the this section of the MDN documentation about eval():
Don't use eval needlessly!
eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension. More importantly, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.
eval() is also generally slower than the alternatives, since it has to
invoke the JS interpreter, while many other constructs are optimized by modern JS engines.
There are safer (and faster!) alternatives to eval() for common use-cases.
2
See a demonstration of these techniques utilized below. Click on the buttons corresponding to each technique to see the output on the console.
var dynamicJS = "function DoSomething(value){var x = 1+1; return 2;}"
var functionBody = "var x = 1+1; return 2;";
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('eval').addEventListener('click', function() {
eval(dynamicJS);
console.log('DoSomething(3) -> ',DoSomething(3));
});
document.getElementById('function').addEventListener('click', function() {
var dynamicFunction = new Function("value", functionBody);
console.log('dynamic function(3) ->',dynamicFunction(3));
});
});
<button id="eval">click to eval</button>
<button id="function">click to use Function</button>
1https://stackoverflow.com/a/4599946/1575353
2https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Don't_use_eval_needlessly!
Perhaps try something like:
function myFunc(obj){
var param = obj.hasOwnProperty('param') ? obj.param : undefined;
console.log(param);
}
var funcString = "myFunc({ param: 'something' });",
Construct = new Function(funcString);
Construct();
Haven't tested it to be honest ... but this way you avoid eval().
more info on Function object

How can I use closures with function pointers?

My goal is to use closures while still writing clean code. One thing I noticed is that somehow I always end up repeating myself because one of my anonymous functions is needed in more than one case.
To this goal, I want to have these repeated functions stored in an object which I can later reuse.
Now, to my question. I've created this example http://jsfiddle.net/tiagoespinha/tTx64/ and the alert will not fire, because y is null.
However, if I inline the function, everything works fine http://jsfiddle.net/tiagoespinha/tTx64/1/
Is there a trick to work around this? How can I have it working in the first example? The variable y is still there, why can't JS catch it?
You want objects having own variables (y) and sharing functions.
What you really need is probably prototype.
function Holder() {
this.y = 5;
this.myFn();
}
Holder.prototype.myFn = function() {
alert("The value of the closure var is " + this.y);
}
new Holder();
I'd suggest the reading of Introduction to Object-Oriented JavaScript so that you don't try to rebuild OOP with just closures.
//our constructor, each instance will carry a y of 5
function Proto() {
this.y = 5;
}
//a shared function for all instances
Proto.prototype.returnedFn = function() {
alert("The value of the closure var is " + this.y);
}
//just a wrapper for the new instance call.
//I just like it this way to avoid using "new" when making instances
function newFn() {
//return a new instance
return new Proto();
}
//test it out
newFn().returnedFn();
newFn().returnedFn();
Your first example would need some kind of dynamic scoping to work. Javascript is statically scoped.
Closures allow a function to capture some local variables from the scope it's defined in. Holder.myFn isn't defined in a scope that contains variable y.
Also note that every instance of a function has its own closure. Hence it's not possible to define your function once and have it refer to different y's in different contexts. (In your second example the inner function is defined every time you call newFn, so many instances can exist, each with its own copy of y.)
I will also add an answer to my own question to report my findings.
Based on the other solutions provided and partly using the OOP solution, I found another way which also makes use of closures.
// Object prototype which takes an argument
function MyObj(abc) {
// Declare function using a closure
// and thus being able to use the argument
this.myFn = (function(){
return function() {
alert("abc is " + abc);
};
})();
}
// Then we can simply create an object with the
// desired argument and the function will behave as expected
var v = new MyObj(10);
v.myFn();
I think nobody provided this solution possibly because I omitted that I don't really want to store the values locally in the object. I simply want to pass some values in, make use of them in one function and then get rid of the object.
In this case I believe a pure OOP solution might be overkill.
Anyhow, thank you for all the proposed solutions!​

Executing dynamically passed function call with jQuery

I have this function call passed as a string:
var dcall = "tumbsNav(1)";
Is it possible to execute this dynamically like exec in SQL??
exec(dcall)
eval is the equivalent, but you should NOT use it.
Instead, pass the function like this:
var dcall = function() {tumbsNav(1);};
Then call it with:
dcall();
To do this, you want eval(dcall).
eval can open terribly security holes and performance issues in your program. If you need to use it, that usually means you have designed your program poorly.
Instead, you might keep a reference to the function you want to call and hold an array of arguments and use apply, e.g., tumbsNav.apply(null, [1]);. I don't know your code, so that's most general solution I can offer.
Wherever you're storing
var dcall = "tumbsNav(1)";
You can instead store
var dcall = function() {
return tumbsNav(1);
};
Wherever you were calling it, instead of calling
eval(dcall);
You can instead call
dcall();
The only case this wouldn't work is if tumbsNav wasn't defined at the time var func = ... is called. Then you would have to store the string. If the string is completely under your control, then there's no security hole, but be aware of all the problems mentioned by #Porco
As Kolink mentioned, my example would not cause a problem if tumbsNav was not defined when assigning it with a wrapped anonymous function that calls tumbs. The comment above would only make sense if the example had been the following:
var dcall = tumbsNav, darg = 1;
// later in the code, you can call
dcall(darg) ;
Use eval(dcall).
As others have mentioned eval is considered bad practice. The main reasons for this are
1) Improper use can leave your code vulnerable to injection attacks.
2) Maintaining code becomes more difficult (no line numbers, can't use debugging tools)
3) Executes more slowly (browsers can't compile)
4) Scope becomes impossible to predict.
However, if you understand all these then eval can be very helpful.

non-recursively replace built-in javascript functions

I am writing some bookmarklets here and I have some questions related to built-in javascript functions.
Let's say I want to replace the built-in prompt function (not necessarily in a bookmarklet). That seems easy enough, but is there a way to call the builtin prompt function from within this replacement?
prompt = function(message){
var tmp = prompt(message);
hook(tmp);
return tmp;
}
I couldn't get the scoping to work out right; this example yields infinite recursion.
Also is there a way to restore the default behavior of a builtin javascript function that has been replaced (without hanging on to an extra reference).
(function () {
var old_prompt = prompt;
prompt = function (msg) {
var tmp = old_prompt(msg);
hook(tmp);
return tmp;
};
prompt.restore = function () { prompt = old_prompt; }
// analogous for other functions you want to replace
})();
Wrapping it up in a (self-executing) function ensures that old_prompt doesn't leak to the outside. You do need to expose something though. I chose to provide a function doing the restoring, for convenience and perhaps, one could say, future-proofing and encapsulation. As long as higher order functions refrain from fiddling with someone else's scope...
Also, no, it's (I'd assume) not possible to restore the previous value of a variable without any reference to it (the old value), even if that value happened to be a built-in. Even if it was possible, it'd be a pretty obscure trick - this way works, so let's just stick with it.
(Credit for func.restore goes to Martijn)

Javascript - get a variable from inside the local scope of a function

I am not great with anything beyond basic javascript so please forgive the simple question.
I am using the jsDraw2D library. This library has a graphics object that looks something like the following:
function jsGraphics(canvasDivElement) {
var canvasDiv;
this.drawLine = drawLine;
function drawLine(point1, point2) {
// do things with canvasDiv
}
}
You use it like this:
var gr = new jsGraphics(document.getElementById('canvas'))
gr.drawLine(new jsPoint(0,0), new jsPoint(10,10))
I would like to add a function to jsGraphics so that I can call
gr.getCanvasElement()
Is there a way to do this without editing the library itself?
I have tried
jsGraphics.prototype.getCanvasElement = function() { return canvasDiv }
but this doesn't seem to work. I have an intuitive feeling that its something with that new keyword but if you could explain why exactly it doesn't that would be helpful too.
Nope, this isn't using the normal JavaScript prototype-based inheritance, it's adding a separate drawLine function to every instance of jsGraphics, each with a closure around its own canvasDiv variable.
Once function jsGraphics() { is closed } there is no further way to access the canvasDiv variable at all, unless one of the functions inside provides access to it. This is often done deliberately to make private variables, explicitly to stop you getting at canvasDiv.
You can't just get to the canvasDiv element necessarily, because if it is never assigned to the object in the constructor using the this keyword, the reference to that object exists in a closure created by the constructor function itself.
You can however wrap the constructor in a new constructor and then set the prototypes equal:
function myJsGraphics(canvasDivElement) {
this.canvasDiv = canvasDivElement;
jsGraphics.call(this, cavasDivElement);
}
myJsGraphics.prototype = jsGraphics.prototype;
Now you should be able to access the element using your new constructor:
var obj = new myJsGraphics(document.getElementById('blah-elem'));
elem = obj.canvasDiv;
The whole closure thing is a little weird if you're not used to it, but the gist is that functions defined in a certain scope but available elsewhere can refer to variables in the scope in which they were defined at all times. The easiest example is when you have a function that returns a function:
function makeIncrementer(start) {
return function () { return start++; };
}
var inc = makeIncrementer(0);
var inc2 = makeIncrementer(0);
inc(); // => 0
inc(); // => 1
inc(); // => 2
inc2(); // => 0
That reference to the "start" variable is "closed over" when the function is returned from the makeIncrementer function. It cannot be accessed directly. The same thing happens in an object's constructor, where local variables are "closed" into the member functions of the object, and they act as private variables. Unless there was a method or variable reference to a private member defined in the constructor, you just can't get access to it.
This "private state" technique has become more and more idiomatic in the last few years. Personally I've found it oddly limiting when trying to quickly debug something from the console or override behavior in a 3rd party library. It's one of the few times I think "Damn it, why can't I do this with the language". I've exploited this bug in Firefox 2 to good effect when I've really needed to debug a "private variable" quickly.
I'd be curious to know when others use this idiom or when they avoid it. (#bobince I'm looking at you).
Anyway #bobince has pretty much answered your question (nutshell: No, you can't access the canvasDiv variable from the scope you are in).
However, there is one thing you can do that is a tradeoff between a hack or editing the 3rd-party library (I always go for the hack ;): you can augment the object to hold a reference you know you will need later.
Hack 1: if you control the object instantiations yourself:
var canvas = document.getElementById('canvas');
var gr = new jsGraphics(canvas);
gr._canvasDiv = canvas; // Augment because we'll need this later
// Sometime later...
gr._canvasDiv; // do something with the element
If the library supports some concept akin to a destructor (fired on unload of the page or something), be sure to null out or delete your property there too, to avoid memory leaks in IE:
delete gr._canvasDiv;
OR Hack 2: Overwrite the constructor just after including the library:
// run after including the library, and before
// any code that instantiates jsGraphics objects
jsGraphics = (function(fn) {
return function(canvas) {
this._canvasDiv = canvas;
return fn.apply(this, arguments)
}
}(jsGraphics))
Then access the element (now public) as gr._canvasDiv. Same note about deleting it on page unload applies.

Categories

Resources