I have an object like so:
var x = {
"fx": function() {...}
}
I have the name of the object (y = "x") and the function (z = "fx") and have them as strings.
I know I can call the function through the use of eval through the following method or similar:
eval(y.z)
However, I would like to avoid using eval to accomplish this. I know the apply prototype method takes a function and applies it to an object, however searching for the function reference is impossible as the function is contained within the object.
I know this problem is not a new one and hence must have a solution, but I cannot find it. Any help would be appreciated.
You can use
x[y]()
to call the function with a variable
What I've understood is that y and z are some variables and you want to call z method of y object using these variables.
It can be accomplished by various ways. For instance:
(function () {
x = {
"fx": function () {
alert("Hey!");
}
}
y = "x";
z = "fx";
this[y][z]();
}());
DemoFiddle
Related
The challenge & explanation.
I want to reassign a global variable when it's passed to a function as an argument but here is the catch I don't want to reference it directly inside of the function so here is the result I want to occur.
let number = 5;
function changesVariable() {
number = 3;
}
changesVariable();
console.log(number); // 3
but I don't want to directly add "number" inside of the function I want a behavior like below I want to pass "number" as an argument and then the function reassigns it by that.
let number = 5;
function changesVariable(n) {
n = 3;
}
changesVariable(number);
console.log(number); // here it returns 5 but would like to see 3
BTW I know the above code is wrong it's here only to explain the concept.
How I tried to solve it
so below are some examples that how I approach it. but their arent the answer.
function changesVariable(n) {
arguments[0] = 3;
}
changesVariable(number);
console.log(number); // still 5
we can do something like:
function changesVariable(n) {
return (arguments[0] = 3);
}
number = changesVariable();
console.log(number);
but I am seeking an answer with these conditions:
reassign the "number" by passing it to function as an argument.
I don't want to use "number" variable directly inside the function.
If all the text above didn't help
I want to create a Utils function that you can pass different global variables to it and it will reassign them that's why I have this approach I want the function to be reusable like:
changesVariable(number1);
changesVariable(number2);
changesVariable(number3);
changesVariable(number4);
You have a let binding in your example.
There is no accessible namespace for a let (or const, but that's beside the point here since you're talking about writing things) bound variable, so in short, what you're asking for is impossible in JavaScript.
If you had a var in global scope, you could access it via globalThis by name:
> var foo = 8;
> globalThis.foo
8
> globalThis.foo = 9
9
> foo
9
However, it sounds like you don't really even need global variables here; why not just put these variables in an object of your own?
> const things = {foo: 8};
> function modify(name, value) { things[name] = value; }
> modify("foo", 9)
> things
{ foo: 9 }
(And yes, you can use modify with globalThis too...)
I think with primitive it's not possible cause it's not a reference data type.
Try to put it into an object like: {n: 5}, and pass it like this.
let number = {n:5};
function changesVariable(number) {
number.n = 3;
}
changesVariable(number);
console.log(number.n);
This is going to work because it's not a primitive, but more like a reference type with a primitive in it. So the function parameter and the global variable will be pointing to the same memory address.
More info: https://www.tutorialspoint.com/What-are-reference-data-types-in-Java#:~:text=Reference%20datatypes%20in%20java%20are,an%20object%20of%20a%20class.
JavaScript is a pass-by-value language, i.e. functions are being passed a copy of the value (not to be confused with object references). I.e. what you want isn't possible, at least not exactly like that...
I want to create a Utils function that you can pass different global variables
How about that utils function accepts a callback which accepts the new value and can do whatever it wants with that?
function change(callback) {
callback(3)
}
//...
change(newValue => {
number1 = newValue;
number2 = newValue;
})
If the function needs the current value of the/a variable you can pass that in too (but your requirements are not clear).
You can do that with eval(), just pass the name of the global var to the function:
let number = 5;
function changesVariable(arg) {
let a = eval(`'(${arg}) = 3'`)
a = a.replace('(','')
a = a.replace(')','')
console.log(a);
eval(a)
}
changesVariable('number');
console.log(number);
But using eval() is not recommended...
Everything is in the the title really... I know that functions created using prototype can't have access to private object data/functions, but what about having access to the arguments that were passed to the object when it was created ?
var Voice = function (word)
{
/*
I know I can obviously do something like : 'this.word = word;'
But I was wondering whether there is a standard way of calling an
argument from within a prototype function without having to do
the above ?
*/
};
Voice.prototype.speak = function ()
{
console.log({{word}});
};
x = new Voice('all I can say is this');
x.speak();
Thanks!
No.
The functions on the prototype weren't defined within the function that the variables are in scope for, so they don't have access to them.
You can store the variable as an object property and then read it back from there.
this.word = word;
Maybe like this:
var Voice = function (word) {
this.init_word = word;
};
Voice.prototype.speak = function (){
console.log(this.init_word);
};
x = new Voice('all I can say is this');
x.speak();
Suppose I have a JavaScript function. and it contain a variable x;
function A(){
var x = 12+34;
}
Is it possible to access x from outside function x?
No, the ability to do so would not make any sense. Suppose we changed your function slightly and called it 3 times:
function x(n){
var x = n+34;
}
x(1), x(2), x(3);
At this point, the function has run 3 times, so the variable x has been created 3 times — which x would you expect to be able to access? Then there's garbage collection; how could references and data be cleared from memory if the browser had to keep variables alive once they're no longer in scope?
If you want to, you can do something like this:
function x() {
x.x = 12+34;
}
x();
or, if the variable will be static/constant as you have it
function x() { }
x.x = 12+34;
or finally, as others have pointed out, by declaring x under a different name outside of the function's scope:
var y;
function x() {
y = 12+34;
}
x();
You can not access it directly by its name, try removing 'var' from the variable declaration, as this should make the variables globals, or placing them outside the ready function. and return the value of x from the function.
You can do some thing like this:
$(document).ready(function() {
var x;
function x(){
x = 12+34;
return x;
}
alert(x());
});
Here is its jsfiddle
Hope this helps.
Yes, but not as scoped in your example above. You must use closure. Consider the following:
var x,
A = function () {
x = 12 + 34;
};
In this manner you can access x from inside the function A. What is even better is that x has direct access to the private members of A and so can be used to leak private data outside of A.
I had a "class" defined and was making only one instance of it. The instance possessed a member function that would end up being passed around (it's a mouse handler, but that's not important). Since I would only ever make one instance of my "class", I decided to rewrite it as a singleton by using an object literal.
So I have
var mySingleton = {
theObjects : [];
}
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}());
mySingleton.addObject = function(newObj) {
this.theObjects.push(newObj);
}
However, when I try to use this code (after adding a few objects), I keep getting an that.theObjects is undefined error. It's referring to the line in the for loop.
Update for 2015 – Use Function.bind() to specify the value of this within the function. Then, instead of using that, you can use this.
mySingleton.mouseHandler = function (e) {
for (var indx = 0; indx < this.theObjects.length; indx++) {
// do something to this.theObjects[indx];
}
}.bind(mySingleton);
This doesn't work if you want mouseHandler to have the context of the 'moused' element. For that, use my original answer below.
If you need to support IE8 or (heaven forbid) earlier, you'll need to use a polyfill.
Since you are calling the function that creates mouseHandler immediately, it is run in the context of window, not mySingleton. So that refers to window. Instead of calling it immediately, just change it to a method so that it runs in the context of mySingleton:
mySingleton.getMouseHandler = function() {
var that = this;
return function() { ... };
};
myElement.onclick = mySingleton.getMouseHandler();
Of course, since you are already using a singleton, you can just reference it directly. In your click handler, instead of checking that.theObjects, check mySingleton.theObjects. Or, in mouseHandler change var that = this to var that = mySingleton.
Edit: Or, pass the context to your anonymous function when you call it:
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}).call(mySingleton);
There are a few popular ways to do this. First, super-simple solution is just reference mySingleton directly and bypass the confusion associated with this. Instead of that.theObjects just do mySingleton.theObjects and move on with your life and things will work fine.
However, there is a common pattern to do this binding. Here's how underscore.js does it
Check out the annoted source to underscore, where you will find this
_.bind = function(func, obj) {
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
};
The other answers here so far are also correct. Providing my viewpoint here in case it helps.
The key to understanding why the code doesn't behave as you expect requires understanding how this works in JavaScript. The problem is that this depends on how the function is called.
First, if you call the function in the method style, this is what you'd expect:
mySingleton.mouseHandler(); // this === mySingleton
If you attach the function to something esle, that works too.
var anotherSingleton = {};
anotherSingleton.foo = mySingleton.mouseHandler;
anotherSingleton.foo(); // this === anotherSingleton
If you detach the function, this becomes the global scope object (window)
var foo = mySingleton.mouseHandler;
foo(); // this === window
And finally, you can force this to be something else using call or apply:
var randomThingy = {};
mySingleton.mouseHandler.call(randomThingy); // this === randomThingy
The takeaway is that this is determined at runtime based on the context of how the function was called. Often, frameworks that allow you to make "classes" abstract these details from you by implicitly applying the bind pattern on your behalf. This is why it used to work, and no longer does.
As others have mentioned, you can change your handler to reference the variable by its scoped name (mySingleton) or otherwise bind it as discussed.
Here's an article I wrote on the subject a few years ago that goes into more detail: http://trephine.org/t/index.php?title=Understanding_JavaScript%27s_this_keyword
Hope this helps!
I'm trying to reuse a complicated function, and it would work perfectly if I could change the value of a local variable that's inside a conditional inside that function.
To boil it down:
var func = complicated_function() {
// lots of code
if (something) {
var localvar = 35;
}
// lots of code
}
I need localvar to be some other number.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Update: The answer is yes! See my response below.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Nope.
No, but it is possible to assign it conditionally so that the function signature (basically, the required input and output) does not change. Add a parameter and have it default to its current value:
var func = complicated_function(myLocalVar) {
// lots of code
if (something) {
// if myLocalVar has not been set, use 35.
// if it has been set, use that value
var localvar = (myLocalVar === undefined)?35:myLocalVar;
}
// lots of code
}
No.
Without changing the complicated function there is no way, in javascript you can manipilate this by using call and apply. You can override functions in the complicated function or add new if this is an option (but they won't be able to access the local variable localvar).
this is more for fun my real answer is still no.
If you are feeling crazy :)
var complicatedFunction = function() {
var i = 10;
var internalStuff = function() {
console.log(i); // 10 or 12?
};
return internalStuff();
};
var complicatedFunction;
eval("complicatedFunction = " + complicatedFunction.toString().replace(/i = 10/, 'i = 12'));
complicatedFunction(); //# => 12
If the function uses this.localvar:
var func = function() {
alert(this.localvar)
if (true) {
var localvar = 35;
}
// lots of code
alert(this.localvar)
}
var obj = {localvar: 10};
func.call(obj); // alerts 10 twice
If not, then you can't change it without changing the function.
In javascript variables are "pushed" to the top of their function. Variables in javascript have function scope, not "curly brace" scope like C, C++, Java, and C#.
This is the same code with you (the developer) manually pushing it to the top:
var func = complicated_function() {
var localvar = 0;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
}
Does declaring the variable "up" one function help you out? At least the declaration is isolated.
function whatever() {
var localvar = 0;
var func = function() {
var something = true;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
};
func();
alert(localvar);
}
whatever();
Here is the jsFiddle: http://jsfiddle.net/Gjjqx/
See Crockford:
http://javascript.crockford.com/code.html
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I asked this question about three weeks ago and within a half hour got five answers that all basically told me it wasn't possible.
But I'm pleased to announce that the answer is YES, it can be done!
Here's how:
var newfunc = func.toString().replace('35', '42');
eval('newfunc = ' + newfunc);
newfunc();
Of course, it uses eval, which probably means that it's evil, or at least very inadvisable, but in this particular case, it works.