Below is from a textbook that I am working through, but something doesn't make sense. Can someone please explain to me how I'm able to access the local variable "secret" from the global scope? When I run the code the output is '100'. I thought that variables declared inside of a function can't be accessed from outside the function. What is happening here that I can set "secret" to 100?
var set, get;
function val() {
var secret = 0;
set = function (arg) {
if (typeof(arg) === "number") {
secret = arg;
}
};
get = function () {
return secret;
};
}
secret = 100;
document.write(secret);
output > 100
By the way, the textbook originally has the function as an immediate function. I changed to the above hoping that it would lead to a different outcome.
You have a global and a local secret variable.
// Creating a global variable, not affecting the one inside val
secret = 100;
// This is accessing the global variable
document.write(secret);
If you actually run your val function, you'll see that they are different
var set, get;
function val() {
var secret = 0;
set = function(arg) {
if (typeof(arg) === "number") {
secret = arg;
}
};
get = function() {
return secret;
};
}
val();
secret = 100;
document.write("global secret = " + secret + '<br />');
set(5);
document.write("private secret = " + get() + '<br />');
document.write("global secret unaffected = " + secret + '<br />');
Related
I would really like to do this:
var Html = function() {
alert('internal: ' + this.val);
};
Html.val = "x";
alert('external: ' + Html.val);
Html();
but it doesn't work. why? how can I get the function code to see values set after its creation?
- update -
because my original post was not so clear in its intent, and because I've posted a solution that's closer to the intention than that of other posters here, allow me to say that what I wanted was a mechanism for accessing the internal members of a function with the explicit purpose of being able to create a generic function that can be seeded to modify its behaviour later and independently
The this context of a JavaScript function depends on how you call the function. You can pass the context explicitly with call:
var Html = function() {
alert('internal: ' + this.val);
};
Html.call({ val:'x' });
If you meant to use the function as a constructor you can instantiate with new:
function Html(val) {
this.val = val;
}
var html = new Html('x'); // Must be used with `new`
alert('internal: '+ html.val);
You can add methods to the prototype if you want to extend your object:
Html.prototype.getVal = function() {
return 'internal: '+ this.val;
};
var html = new Html('x');
alert(html.getVal());
In Javascript, the "this" is the object associated to a method, not the method itself. The simplest solution would be to change the Html function to a method:
var html = {
val: "x",
draw: function(){
console.log('internal: ' + this.val);
}
}
html.draw();
html.val = "y"
html.draw();
If you want to keep the html function as a direct function you can either craete a wrapper around a method.
var Htmldraw = function(){
return html.draw();
}
html.val = "asd"
Or you can change the function to use lexically scoped variables instead of "this"
var val;
var Html = function() {
console.log('internal: ' + val);
};
val = "x";
alert('external: ' + val);
Html();
thank you both for taking the time to post elaborate answers. you both got thank you points.
I'm going to answer my own question for the sake of some poor sod who may struggle with this in the future... what I wanted to do is best accomplished as shown below (please see my edits in the original posting to clarify what my intention was):
function fn() {
this.val = "x";
this.show = function() {
alert("internal = " + this.val);
};
return this;
};
var x = fn();
alert("initial = " + x.val);
x.val = "y";
alert("reset = " + x.val);
x.show();
from which you can see that a variable internal to my function is accessible from the outside. This allows me to manufacture a function and subsequently load it with a bunch of data for its use, without having to pass parameters during its creation (which is useful because when the function is actually called (as opposed to created), it will receive a different set of parameters)
i want to send an url with parametres, those parametres are values taken by a form with javascript and i want to use JSON to do it, but when i debug i see this error : Uncaught ReferenceError: name is not defined..
function recup()
{
var selectElmt = document.getElementById("name");
var selectcat = document.getElementById("msg");
var name = selectElmt.options[selectElmt.selectedIndex].value;
var msg = selectcat.options[selectcat.selectedIndex].value;
}
function go() { // button send who call the function go
var p_url="http://mysite.com/class?name=" + name + "&message=" + msg +
$.getJSON(p_url, {
}).done(function( data ) {
$.each(data, function (key, field) {
alert(field);
});
});
return false;
}
it's a syntax error when calling the value name and msg but i don"t know how to fix it or in the go function
You two errors, closing curly brace and plus character, the code shoud be:
var msg = "hello"; // i just simplified the value
var name = "test";
function go() { // button send who call the function go
var p_url="http://mysite.com/class?name=" + name + "&message=" + msg;
$.getJSON(p_url, {
}).done(function( data ) {
$.each(data, function (key, field) {
alert(field);
});
});
return false;
}
UPDATE: You need to make name and msg global:
var name, msg;
function recup() {
var selectElmt = document.getElementById("name");
var selectcat = document.getElementById("msg");
name = selectElmt.options[selectElmt.selectedIndex].value;
msg = selectcat.options[selectcat.selectedIndex].value;
}
function go() { // button send who call the function go
var p_url="http://mysite.com/class?name=" + name + "&message=" + msg;
$.getJSON(p_url, {
}).done(function( data ) {
$.each(data, function (key, field) {
alert(field);
});
});
return false;
}
and recup need to be executed before go
the two variables are in another function
Well, that explains it. A variable that is local to a function cannot be accessed by another function.
You have to define the variables in a scope that is shared by both functions. This could be the global scope, but you should avoid creating global variables (you cannot have a global variable with name name anyways, because it exists already).
If you want to assign a value to a variable in a higher scope, use name = ...; instead of var name = ...;.
Example:
(function() {
// create a new scope so that we don't pollute the global scope
// this variable can be accessed by both functions
var answer;
function foo() {
// don't use `var` here, otherwise you create a local variable which
// shadows the variable with the same name in a higher scope
answer = 42;
}
function bar() {
alert(answer);
}
foo();
bar();
}());
Consider this trivial code I tried in Chrome's console:
function Container() {
var secret = 3;
this.getSecret = function() {
return secret;
}
}
Now, I cannot retrieve 3 by executing:
var c1 = new Container();
c1.secret //yields undefined
However, this works as expected
c1.getSecret() //returns 3
Now, this is the quirky thing I tried:
c1.secret = 10;
c1.getSecret(); //I was expecting it to return 10
However, it returns 3. When I see the object in the console, it looks like this:
Container {getSecret: function, secret: 10}
Can someone explain why c1.secret = 10 didn't change the value of the secret private variable in the object? Are there two fields with the name "secret"?
I'm confused what the final object really looks like in memory.
private is a really confusing word.
The secret var you declared using var secret = 3; is not a 'private' variable. This is a variable that is only visible in the Container constructor scope. And because you declare the method getSecret in the same scope, it has access to it.
if you had done:
function Container() {
var secret = 3;
}
Container.prototype.getSecret = function() {
return secret;
}
calling getSecret would say that secret is undefined.
And, with your current code, adding:
Container.prototype.getSecret2 = function() {
return this.secret;
}
would return 10. Because your object has now a property called secret when you do
c1.secret = 10;
But remember:
var secret = 3; does not attach the variable to the current object. It just create a variable that live in the current scope. Every function declared in that scope will have access to it.
In JavaScript, you can set a variable equal to a method like this:
variable = function () { alert("My name is bob"); };
Or like this:
function SayMyName() {
alert("My name is bob");
}
variable = SayMyName;
You can also enclose a function with arguments like so:
function SayMyName(name) {
alert("My name is "+ name);
}
variable = function () { SayMyName("bob"); };
But trying to store a variable the following way will call the function, not store it as a variable:
function SayMyName(name) {
alert("My name is "+ name);
}
variable = SayMyName("bob");
There was a clever way you used to be able to work around this by using [callee][1], but callee is depreciated and won't work on most modern browsers.
Is there any way to set a variable equal to a function with arguments without using an enclosure?
Can't you use a nested anonymous function for this?
var variable = function(name) {
return function() {
alert('My name is ' + name);
};
};
Calling it yields your desired result:
var test = variable('bob');
test(); // Alerts "My name is bob"
You can use the bind method to fix some parameters
var variable = SayMyName.bind(null, "bob");
However, this does not work in IE <= 8 so you would have to use a similar replacement or polyfil in tha case.
You can return a function, like:
function SayMyName(x) { return function() { alert("My name is Bob.");}};
var x = SayMyName('bob');
x();
var name = (function sayMyName(name) {
return alert('My name is: ' + name);
});
name('Mike');
public class ToyProgram{
public static void main(String[] args){
String funcCallVar = aFunc();
System.out.println(funcCallVar);
}
public static String aFunc(){
String aVariable = "yes you can set a variale equal to a function";
return aVariable;
}
}
I was wondering if there is any way to access variables trapped by closure in a function from outside the function; e.g. if I have:
A = function(b) {
var c = function() {//some code using b};
foo: function() {
//do things with c;
}
}
is there any way to get access to c in an instance of A. Something like:
var a_inst = new A(123);
var my_c = somejavascriptmagic(a_inst);
A simple eval inside the closure scope can still access all the variables:
function Auth(username)
{
var password = "trustno1";
this.getUsername = function() { return username }
this.eval = function(name) { return eval(name) }
}
auth = new Auth("Mulder")
auth.eval("username") // will print "Mulder"
auth.eval("password") // will print "trustno1"
But you cannot directly overwrite a method, which is accessing closure scope (like getUsername()), you need a simple eval-trick also:
auth.eval("this.getUsername = " + function() {
return "Hacked " + username;
}.toSource());
auth.getUsername(); // will print "Hacked Mulder"
Variables within a closure aren't directly accessible from the outside by any means. However, closures within that closure that have the variable in scope can access them, and if you make those closures accessible from the outside, it's almost as good.
Here's an example:
var A = function(b) {
var c = b + 100;
this.access_c = function(value) {
// Function sets c if value is provided, but only returns c if no value
// is provided
if(arguments.length > 0)
c = value;
return c;
};
this.twain = function() {
return 2 * c;
};
};
var a_inst = new A(123);
var my_c = a_inst.access_c();
// my_c now contains 223
var my_2c = a_inst.twain();
// my_2c contains 446
a_inst.access_c(5);
// c in closure is now equal to 5
var newer_2c = a_inst.twain();
// newer_2c contains 10
Hopefully that's slightly useful to you...
Answers above are correct, but they also imply that you'll have to modify the function to see those closed variables.
Redefining the function with the getter methods will do the task.
You can do it dynamically.
See the example below
function alertMe() {
var message = "Hello world";
console.log(message);
}
//adding the getter for 'message'
var newFun = newFun.substring(0, newFun.lastIndexOf("}")) + ";" + "this.getMessage = function () {return message;};" + "}";
//redefining alertMe
eval(newFun);
var b = new alertMe();
now you can access message by calling b.getMesage()
Of course you'll have to deal with multiple calls to alertMe, but its just a simple piece of code proving that you can do it.
The whole point to that pattern is to prevent 'c' from being accessed externally. But you can access foo() as a method, so make it that it will see 'c' in its scope:
A = function(b) {
var c = function() {//some code using b};
this.foo = function() {
return c();
}
}
No, not without a getter function on A which returns c
If you only need access to certain variables and you can change the core code there's one easy answer that won't slowdown your code or reasons you made it a closure in any significant way. You just make a reference in the global scope to it basically.
(function($){
let myClosedOffObj = {
"you can't get me":"haha getting me would be useful but you can't cuz someone designed this wrong"
};
window.myClosedOffObj = myClosedOffObj;
})(jQuery);
myClosedOffObj["you can't get me"] = "Got you now sucker";
Proof of concept: https://jsfiddle.net/05dxjugo/
This will work with functions or "methods" too.
If none of the above is possible in your script, a very hacky solution is to store it in a hidden html-object:
// store inside of closure
html.innerHTML+='<div id="hiddenStore" style="display:none"></div>';
o=document.getElementById("hiddenStore")
o.innerHTML="store this in closure"
and outside you can read it with
document.getElementById("hiddenStore").innerHTML
You should be able to use an if statement and do something like:
if(VaraiableBeingPasses === "somethingUniqe") {
return theValueOfC;
}