how to make javascript string a function call [duplicate] - javascript

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 6 years ago.
I have string logo.cr.Button and function
logo.cr.Button = function(){
//something
}
var strg = 'logo.cr.Button';
strg();
now somehow i have to make that string a function call
like strg(); but it is saying
strg is not a constructor
here

Generally when we write JavaScript functions the resulting function declaration looks like this:
function demo() {
// function stuff here
}
You’re probably more than aware that “In JavaScript Functions are first-class Objects”. It’s a phrase that is spouted everywhere, and for good reason. It’s a very powerful idea that has worked to elevate JavaScript to where it is. We’re not going into the details of first-class objects here. All we care about is the fact that, in JavaScript, functions are objects.
This means that the above function can also be declared by calling its Constructor:
var demo = new Function();
Now lets imagine we have a function with parameters and instructions:
function demo(name, age) {
console.log('my name is ' + name);
console.log('my age is ' + age);
}
and now to convert it to Constructor syntax:
var demo = new Function(
"name,age",
"console.log('my name is ' + name);" +
"console.log('my age is ' + age);"
);
This makes it pretty easy to see that these two functions are the same, they are just declared differently. The important difference is that one has easily accessible strings that we should be able to manipulate.
This applies to your function in a very similar way.
var strfunc = new Function ("", "logo.cr.Button()");
I can't seem to format this because I'm on mobile. But i will asap.

Use eval("logo.cr.Button")();
This will execute the function, of course if you have an object like:
var logo = {
cr: {
}
};

This won't work because JavaScript thinks you are using dot notation. When you write logo.cr.Button() JavaScript is looking for a function Button() within the object cr which is in the object logo.
I recommend changing the name to logoCrButton = function()...

You could use eval, but its not recommended.
Secury issues are just one reason, because an user might exploit eval to execute different code that is not supposed to be executed. Within this question it is explained fully.
var logo={cr:{}};
logo.cr.Button = function(){
console.log("something");
}
var string = "logo.cr.Button()";
eval(string);
If you can avoid eval then use a normal function call, an object or an array instead. For insteads Iterating through an array is much better and more stable compared to evaluating some parameters dynamically, as you can see here.
This second example does not use eval, but nevertheless you can call a certain function by using a string:
var obj={logo:{cr:{Button:function(){console.log("something");}}}};
var string = "logo.cr.Button";
function callFunctionByString(string,obj){
var parts = string.split('.');
parts.forEach(function(part){
obj = obj[part];
});
obj();
}
callFunctionByString(string,obj);
Hope this helps.

Related

Get caller method name in js inside prototype

I have method named my from where I am calling prototype .Inside prototype I want to get Method name from where I am calling . The code below gives all the code of function.
var c = new Object();
c.hello = {}
c.hello.my = function(b) {
var d = 1,
c = 1;
ap('#love').try()
}
x.prototype.try = function(h) {
console.log(arguments.callee.caller);
}
Above program gives all the code present inside c.hello.my . How can we get the name of function (i.e my). If possible object name as well like **c.hello.my*.
This has been deprecated to heck and back for both performance and security reasons. Arguments.caller is already non-functional on most engines, and this works at all because it's ultimately calling function.caller, and because you're not in strict mode. This will not work in modules, inside class definitions, and any distance into the future.
I have before been in situations where I thought it would be nice to distinguish who called a function, but I eventually work around it or let it go. If you need the reference to the CURRENT function expression, you can always give it a name:
...
c.hello.my = function NAME_GOES_HERE(b) {
var d = 1,
c = 1;
ap('#love').try()
}
...
When you give a name this way to a function expression ('x=function F()'), the name might or might not be referenced as a variable outside the function, but it's guaranteed to be usable and valid from inside the function.
If a function has a name, you can read function.name to see it. Bear in mind that the textual name isn't nearly as useful in Javascript as it is in other languages. If you want this for debugging purposes, I suggest looking at error.stack. This is non-standard, but has very similar output across browsers.

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

Putting arrays into custom objects

I am attempting to build my first custom object and it looks something like this:
function URLObject()
{
this.syllables = new Array();
etc...
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
}
var myobj = new URLObject();
myobj.AdtoSyllables("text");
The execution of the above code results in the JS engine printing out the following:
This is Sylcount: NAN
-or-
This is SylCount: undefined.
I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.
And yet I am doing something wrong here and I do not know what. Can anyone help?
Here you go:
function URLObject()
{
this.syllables = [];
etc...
}
URLObject.prototype.addToSyllables = function(aWord) {
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
var myobj = new URLObject();
myobj.adtoSyllables("text");
.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())
Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.
Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.
http://jsfiddle.net/J3tUb/
That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:
function createURLObject() {
// Use closed-over locals instead of attaching properties.
var syllables = new Array();
function AddToSyllables(AWord) {
// Since syllables is closed over, it is accessible here
// (but WON'T be accessible outside this scope).
syllables.push(AWord);
return syllables.length;
}
// Expose whatever functionality you want to be "public"
// in the returned object.
return {
AddToSyllables: AddToSyllables
};
}
var myObj = createURLObject();
myObj.AddToSyllables("text");
It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.
you need to do this :
function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
etc...
Like this you can add method and attributes to one object.
The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:
function URLObject()
{
//...
}
URLObject.prototype.AddtoSyllables = function (AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
adds the AddtoSyllables function as an entry to the object this points to.
The code
myobj.AdtoSyllables(...)
is equivalent to
myobj["AdtoSyllables"](...) // now a retreiaval operation
or even
var fn = myobj["AdtoSyllables"];
fn (...);
Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.
The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.
From an alternative point of view:
function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};
bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;
In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.

Execute private function inside the class by its name (string)

At the moment I have simple JavaScript class like this:
function MyClass() {
// ... some code ...
this.Create = function() {
funcName = 'myTestFunc()';
cTimer = setTimeout(funcName, 1000);
}
// ... more code ...
var myTestFunc = function() {
alert ('everything\'s OK!');
}
// ... more code ...
}
and to test it I'm using this code:
x = new MyClass();
x.Create();
I have some troubles to execute this function by it's name. If I put just eval(funcName); instead of setTimeout call it works fine but can't figure out why it doesn't work this way.
Course, this is part of more complex code but rest of code is irrelevant to this problem.
My question is obvious - How to execute function by its name set as setTimeout function's argument? Is it possible?
Note: Making this function public (this.myTestFunc = ...) isn't an option!
Update:
funcName = "myTestFunc()"; is just an example. In real code it looks like funcName = getRandomEffectFunctionName();! It's just a random value.
Referring to the update:
Instead of setting:
var funcName = "getRandomEffectFunctionNeme()";
Thus, setting a reference to the function's name you should do
var funcRef = getRandomEffectFunctionNeme;
And set a reference to the function itself . Not only this avoids the issues setTimeout with strings has*. It also solves your closure issue since your code is structured in such a way the timeout has access to the function itself.
In your case, let's assume you have some functions that are filters, for example lowPass highPass and blur. In that case, instead of choosing a function name we would be choosing a function.
First, we store these functions in an array:
var filters = [lowPass,highPass,blur];
In JavaScript, functions are first-class objects, you can pass them around just like other objects.
Next, we'll get a random number
var chosen = Math.floor(Math.random()*3);//get a random number between 0 and 2
Finally, we'll choose the filter and invoke it
var filter = filters[chosen];
setTimeout(filter,1000);
( * just try debugging it, it basically invokes the compiler whenever ran and is painfully slow)
You just pass a function to setTimeout as a parameter, rather then a string, setTimeout(myTestFunc,1000) .
When calling Create it would have access to it anyway because they are in the same closure.
NOTE: This solution is only applicable if you can not pass the function name as a function reference, for example if you're integrating with code that is outside your control. Generally, when possible, you should pass a function reference since in JavaScript, all functions are objects.
Assuming that the timeout and the function are in the same closure your code is pretty close. The problem is that your eval call executes in the global context because it is in a timer. This means they are no longer in the same lexical scope.
You can however, grab a reference to the function by clever use of eval which you can later call in the setTimeout invocation.
var F=eval(funcName);// gain a reference to the function given the function's name
cTimer = setTimeout(F, 1000);
If you're using AIR or don't trust the functionName string you can do the following:
function Test(){
var functionContainer={
t:function(){
console.log("it's t");
}
};
this.callT=function(functionName){
var F=functionContainer[functionName];
console.log("F is:",F);
setTimeout(F,500);
}
}
(new Test()).call("t");
This is preferable since you are invoking setTimeout with a function's name and not a string. In general, using setTimeout with a string can have issues, it's hard to debug or maintain.

Javascript local variable declare

Basically this is a question how to access local scope handler. I trying to achieve something similar for global variable definition like:
window['newObject'] = "some string";
alert(newObject);
but for local scope. Right now only solution I have is using evals:
eval("var newObject='some string'");
But this is really ugly solution... The best one would be like using some reference to local scope like in a window[] solution, but I never heard of any reference to local scope... Any ideas ?
Example goes here:
function x(arg)
{
localScope[arg.name]=arg.value;
alert(sex);
}
x({name:"sex", value:"Male"});
What you're looking for is called the call object. But according to this, you can't access it directly, so you're out of luck.
Why not create an object in local scope and then use it as a container for any variables you wish to create dynamically?
function x(arg)
{
var localSpace = {};
localSpace[arg.name] = arg.value;
}
Okey I found related question that is talking about what I need...
How can I access local scope dynamically in javascript?
I just remember that in ECMA 262 is only one way to add dynamically local variables to scope using "with" statement (and eval of course), here are solution:
var x=function(obj)
{
with(obj)
{
alert(someObj);
}
}
alert(typeof someObj);
x ( {someObj:"yea"}) ;
alert(typeof someObj);
I must be missing something. How is what you want different from just doing:
var newObject = 'some string';
? (OP has clarified question)
I don't think there is a way to do what you are asking. Use members of a local object, e.g.
function doSomething(name, value)
{
var X = {};
X[name] = value;
if (X.foo == 26)
alert("you apparently just called doSomething('foo',26)");
}
If you choose a 1-character variable like $ or X, it "costs" you 2 characters (variable name plus a dot), and avoids trying to use eval or doing something weird.
You could try the named arguments trick
EDIT: This isn't cross browser
function x( {sex:sex, height:height} ) {
alert( sex );
alert( height );
}
x( { sex: 'male', height: 'short' } );
x( { height: 'medium', sex: 'female' } );
// male
// short
// female
// medium
Not sure what you need exactly, but here's my 2 cents.
The only way to dynamically create vars in an existing function is the eval method you've already mentioned.
Another option (mentioned by others) is that your function take a context map, and the template access it with dot notation (context.var1)
My final suggestion is the Function constructor. But I have a feeling this may be what you're looking for. (Note that the function constructor suffers from the same problems as an eval call)
var arg1 = "first";
var arg2 = "last";
// This is the body of the function that you want to execute with first
// and last as local variables. It would come from your template
var functionBody = "alert(first + ' ' + last)";
var myCustomFun = new Function(arg1, arg2, functionBody);
myCustomFun("Mark", "Brown"); // brings up and alert saying "Mark Brown";
Hope it helps
Interesting question, never thought of something like this. But what is the usecase?
The reason you'd want to do something like this, is if you don't know the name of the variable. But then in that case, the only way to access the variable again would be using the same reference object. I.e. you could just use any old object to store data in.
Reading from such a reference object would be interesting for debugging purposes, but I don't see why you'd want to write to it.
Edit:
The example you posted doesn't convince me of the need for access to the local scope, since you still have the name sex hard coded in the alert. This could be implemented as:
function x(arg)
{
container = {};
container[arg.name] = arg.value;
alert(container.sex);
}
Could you elaborate more on the example?
I'm not entirely sure I understand your question. When creating a class x, I generally do this:
function x(args) {
var _self = this;
_self.PriviledgedMethod(a) {
// some code
}
function privateMethod(a) {
// some code
}
}
var newObject = new x(args);
You can continue to access _self and args since it is closed on by the contained functions.

Categories

Resources