I need to get the value of a variable using its name. But I also need to consider the scope stuff. For example, my user may write the following code:
var x = 20;
function func1(){
var x = 30;
return function(){
return x;
}
}
var func = func1();
Now they pass me this func, and also a string named "x", and I need to evaluate x from the scope that func belongs to.
To be more clear, I need to implement a function, which takes two arguments, one is an object, the other is a string represent the variable name. The function need to return the value of the variable represented by the second argument from the scope that the first object belongs to.
function resolveValue(obj, name){
//unimplemented;
}
resolveValue(func, "x"); //return 20 in this example.
I think this can be done if I can get the scope chain, but is this possible in javascript?
Related
This is probably a basic question, and I am aware that there have been some similar questions around here, but still I did not find an answer. Please consider the following code:
function Outer(inner2) {
var x = 5;
this.inner1 = function() {return (x);}
this.inner2 = inner2.bind(this);
}
var outer = new Outer(function() {return (x);});
alert(outer.inner1()); // works
alert(outer.inner2()); // does not work
If I would replace the second line by this.x = 5;, the second alert would work. So I guess the problem is that x when declared with var is not part of this, so that bind will have no effect.
Is there any way to make this work without using this.x?
Is there any way to make this work without using this.x?
No.
Btw, you probably don't even need to use bind, just calling inner2 as a method on the object would suffice when both the constructor and the method use this.x.
If you don't want to make x a property of the object, but keep it as a local variable, the usual strategy would be to pass it to the callback as an argument, not trying to somehow make it available in its scope implicitly:
function Outer(callback) {
var x = 5;
this.inner1 = function() { return x; };
this.inner2 = function() { return callback(x); };
// ^^^
}
var outer = new Outer(function(y) { return y; });
// ^ ^
alert(outer.inner1()); // works
alert(outer.inner2()); // works
I think you need clarification on what the word "this" is referring to.
"this" is not pointing to the function "Outer."
When you invoke a constructor function with the "new" keyword, a few things happen.
The constructor function returns an object.
The "this" variable is changed, so that it is set to point to that object that is returned.
(Also, the .proto of the object returned is set to the .prototype of the constructor function, but that step is not relevant here).
So, you are binding the callback function to the object that you are returning from the constructor function, not the constructor function itself.
Thus, the callback function is bound to outer (with a lower-case), not outer (with an upper-case).
Also, when you bind, you are not binding to the scope of a function. X is not assigned to any property. I think you only can bind to an object and access its properties with this.a etc.
The x in the first function worked because its value was assigned in the scope of the function.
I found an, albeit ugly, solution:
function Outer(inner2) {
var x = 5;
this.inner1 = function() {return (x);}
eval('this.inner2 = ' + inner2.toString());
}
This works and shows my point: the parameter inner2 is just a prescription of how this.inner2 should look like; it is never invoked itself.
Let me know, if you have a neater solution than this.
I'm trying to assign a variable to itself in a function, and if the variable has the same name as an argument to the function it doesn't seem to work, but does if they're not the same name. A code example shows this more clearly.
Is this behavior I should expect? This is a pared down example for my d3 use case which prompted this question. I've shown that below as well.
Non working example
var a;
function assign(a) {
a = a;
}
assign("test")
console.log(a)
undefined
Working Example
var a;
function assign(b) {
a = b;
}
assign("test")
console.log(a)
test
Use case
var data
d3.csv("data.csv", function(error, data) {
//Doesn't work for me
data = data
}
console.log(data)
undefined
In your first example, the argument a that is passed to the function shadows the variable a which is defined outside, so: a=a is assignment of the argument (that was passed to the function) to itself.
In Javascript the scope is functional level scope, so whenever the variable is referenced it is searched for its declaration in the containing scope(function), if it finds it it uses it else it keep searching in prototypical chain upto global scope. So in your case it tries to search a and it founds it as argument a so it stops the search there & uses a from argument.
So to avoid the conflict you have use two ways.
Use the different names
If you want to use the same name then use the explicit scope resolution.
Ex.
var a;
function assign(a) {
Global.a = a //Global is placeholder here for outerscope that variable a is coming from.
}
assign("test")
console.log(a);
Useful links for more clear understanding
Closures
Variable Hoisting
you could use the window object to access the global variable.
var a;
function assign(a) {
window.a = a; // specifying the scope.
};
assign("test")
console.log(a)
More information on 15-common-javascript-gotchas
I am trying to create a function which will dynamically set the value of whatever global variable is passed as a parameter. It's not working, and I'm trying to figure out why. Can someone please explain why this doesn't work:
var things = 5;
function setup(variable) {
variable = 7;
}
setup(things);
console.log(things); //should return 7. returns 5 instead. the function had no effect on the global variable
and this also doesn't work:
var things = 5;
function setup(variable) {
window.variable = 7;
}
setup(things);
console.log(things); //should return 7, but returns 5. still not accessing the global variable.
but this does:
var things = 5;
function setup(variable) {
window[variable] = 7;
}
setup("things");
console.log(things); //returns 7
I suspect that what is happening is that the parameter variable is being set as a local variable inside of the function, so any changes are only happening to the local version. But this seems strange because the parameter that's been passed is a global variable. Can someone explain to me what is happening and how to better write this code? Does this require a method (which can then use this to access the original object)?
Thanks!!
Javascript is pass-by-value. (Objects, arrays, and other non-primitives are passed by value-of-reference.) That means that the value of the variable (or reference) is passed to the function, but the function parameter does not become an alias for the actual argument. Thus, you cannot change a variable outside a function without referencing it (as you do in your last example).
See this answer in another thread for more information.
Inside of functions are "variable environments". When the function setup is declared, and the parameter variable set, it creates a local variable in setup's variable environment for variable (the parameter).
So that is why this assignment
function setup(variable) {
variable = 7;
}
Will never change the value sent to variable.
Variables in JavaScript are values. As the variable is passed around, the only thing passed is the value of the variable. However, the value of the variable is assigned to the parameter (again poorly named in this example) variable. When the value of the parameter is assigned to 7, that only changes the local variable, and not the value of the passed variable.
//the value of things is 5
var things = 5;
//the passed value 5 is assigned to variable
function setup(variable) {
//the value of variable is changed to 7 (and nothing is done with 5)
variable = 7;
}
//the value of things is sent to setup
setup(things);
Hopefully this will be a little more enlightening. Consider a situation where setup was actually modifying the value of variable. A good example is when the value has state, such as an array or an object.
//the value of things this time is an object
var things = {};
//the passed value of object is assigned to variable
function setup(variable){
//the value of variable (the object) has a property added named msg with a value of "hello world"
variable.msg = "hello world";
}
//the value of things (an object) is sent to setup
setup(things);
alert(things.msg);//hello world
When variables are passed as arguments to functions, a copy of their value is made and assigned to the name of the argument in the function.
For example:
function foo(a) {
a = 7; // sets the temporary variable(argument) a to 7
}
var bar = 24;
foo(bar); // copies bar's value and passes in the copy to foo
For a function to modify a variable itself, you would have to access it another way. In other languages there are things called pointers that point to a place in memory. This allows you to modify variables directly, as you have where they are located - you can simulate this with JavaScript:
var spam = 3;
var memory = ["bar", 29, "x", foo, false];
function foo(a) {
memory[a] = 7;
}
foo(3);
The above example sets an array called memory and fills it with random gibberish. Then, a function named foo is created that allows for the modification of elements in this memory array.
How does greaterThanTen(9) become the y variable in the return function? What I mean is how does the parameter (9) become the y in the return function argument? Wouldn't 9 be replaced with x since greaterThanTen = greaterThan(10)? Wouldn't the 9 just replace the x = 10 parameter? I just don't understand how that 9 parameter is getting to y in the return function.
function greaterThan(x) {
return function(y) {
return y > x;
};
}
var greaterThanTen = greaterThan(10);
show(greaterThanTen(9));
It doesn't "become the y variable". The function greaterThan returns a function, and the value passed to greaterThan is "captured" in that returned function.
In other words, greaterThan(10) creates the following function:
function(y) { return y > 10; }
It's similar to writing:
function greaterThan10(y) { return y > 10; }
Functions that create functions take advantage of closures ("the thing that 'captures' the 10).
The advantage is that you don't need to keep writing greaterThanNnn functions for every number you want to use, you just call greaterThan(n) for whatever you need. This is a contrived, but popular, example, of course.
For chunks of info relating to referencing functions, when to use () and when not to, and some more realistic examples, see also:
Difference between calling function and referencing function?
When do I use parenthesis and when do I not?
Why function statement requires a name?
when you called greaterThan(10) it assigned value of x and return the function in greaterThanTen variable which now becomes
var greaterThanTen = function(x){10>x};
then in next line you called greaterThanTen(9) so it will assign the x value. i hope you understood what i said.
You must have to know the basis about the closures concept in JavaScript. Closures are the most tricky and special addition to the JavaScript language. As you will notice they follow the lexical scope of the language flow. Here in this example;
function greaterThan(x) {
return function(y) {
return y > x;
};
}
var greaterThanTen = greaterThan(10);
console.log(greaterThanTen(9));
If you see there is the main concept of closures. Once you call the function greaterThan it creates another function. But as you pass the first argument 10, it takes the place of x. Further when you call the function and pass the second argument 9
it takes place on y the function built inside. In this way the values are stored in the function call stack and you can compare and operate on those values.
just a bit confused by this code
var counter = function() {
//...
var count = 0;
return function () {
return count = count + 1;
}
}
var nextValue = counter();
console.log(nextValue());
nextValue.count = 7;
console.log(nextValue());
console.log(nextValue.count);
console.log(nextValue());
Output is
1
2
7
3
It's counter intuitive. There are two representations of count. One on the outerfunction nextValue and one that only the inner anonymous function can see.
Correct, or are my missing something?
The expression nextValue.count does not refer to the local variable "count" declared inside the function. It is not possible, in fact, to create a reference to a variable local to a function from code outside the function. What you're referencing there is simply a property of the function object.
So, yes, the "count" variable that the returned function has access to is effectively completely private to that function, and it is persisted in the closure formed by the call to the "counter" function.
If you did want that to work, you could do this:
function counter() {
function actual() {
return actual.count = actual.count + 1;
}
actual.count = 0;
return actual;
}
edit — (fixed bogus code) the name "actual" inside gives the returned function safe access to the function object itself; originally I typed "this" there, and that would not work unless the external code set it up explicitly.
The way you describe it, count is effectively a private variable. When you're assign to nextValue.count, you're creating a separate property--not accessing the internal count being incremented by your counter.