If I have:
name.sub = function() {
var sub = {};
var placeholder = "test"
var test = function() {
return 42;
};
// Desired code would be here
return sub;
};
I want to use a placeholder to access the variable so that I get 42.
Something like
window["name"]["sub"][placeholder] is seemingly looking for name.sub.test.
The only answers I found were if it was a global variable.
Using eval would work, but I've heard it should be avoided where possible.
placeholder = "test";
console.log(eval(placeholder + '()'))
// Would return 42
My actual end goal is to have an associative array where:
console.log(array[placeholder]);
// Would return 42
Any help would be appreciated.
This is what I ended up using for anyone interested:
name.sub= function() {
var sub = {};
var placeholder = "test"
var test = function() {
return 42;
var newObj = {};
newObj["test"] = function() {test()}
console.log(newObj[placeholder]())
// Should return 42
};
You can't access variables inside a function from outside said function.
Instead, you could do this:
name.sub = function(placeholder) {
var functions = {
"test": function() {
return 42;
},
};
return functions[placeholder]();
};
name.sub("test"); // 42
I'm not sure if that's what you're looking for but hopefully it is. Explain more?
You can't access local variables inside a function the same way you can access properties of window in global scope.
kangax wrote an interesting article about Understanding delete [in JavaScript], which includes an explanation of what Activation objects are - which I think is what you're looking for.
I suggest you read the entire article, but long story short:
Inside functions, declared variables (and functions) are added as properties to the activation object of the current scope, as they get added to window in the global scope.
But unlike window:
Note that Activation object is an internal mechanism and is never really accessible by program code.
Conclusion: What you're asking is not (currently) possible.
Your options are limited to:
Using an intermediate object:
name.sub = function() {
var sub = {};
var placeholder = "test";
var array = {};
array.test = function() {
return 42;
};
console.log(array[placeholder]());
return sub;
};
Using eval, exactly like you suggested:
name.sub = function() {
var sub = {};
var placeholder = "test";
var test = function() {
return 42;
};
console.log(eval(placeholder + '()'));
return sub;
};
Using window, by removing var from test's declaration:
name.sub = function() {
var sub = {};
var placeholder = "test";
test = function() {
return 42;
};
console.log(window[placeholder]());
return sub;
};
I suggest the first option for the sake of performance over eval, for compatibility over window (might collide with other code), and simply because of personal taste and what I consider good practice.
By what i understand of your question,
its seem like you are looking for a key/value pair to a JavaScript object literal,
window.name is reserved btw: https://developer.mozilla.org/en-US/docs/Web/API/Window/name
var sub = {
'test': function() {
return 42;
},
'test2': 42;
}
sub['test']();
sub['test2'];
add by
Using dot notation:
sub.test3 = "value3";
Using square bracket notation:
sub["test4"] = "value4";
Maybe im thinking to simple , but seems like this is what you are looking for
Related
var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]["WayCoolTest"]
running this in chrome console, my test app, anywhere results with undefined. I do not understand why, can someone explain why this does not work and help me fix it. Thank you very much!!
Using window is usually redundant - let me demonstrate:
var foo = '123';
alert(foo); //123
alert(window.foo) //123
alert(window['foo']) //123
It is evident which is more convenient. There is a circumstance in which the use of window makes sense, but that circumstance is almost always because of poor architecture. Using window allows us to access a variable global variable - funny wording :) This should clear it up:
var foo = '123';
var bar = 'abc';
var prop;
if (blah) { //some condition here
prop = 'foo';
}
else {
prop = 'bar';
}
Now...how can we use prop to get the value of a corresponding variable?
console.log(window[prop]); //123 or abc - bracket notation lets us use variable property names
This sort of thing is very common within objects, but not with window. The reason is that we should be avoiding global variables (properties of window) as much as possible. Therefore, any logic that needs a variable property name should be inside of an object, dealing with objects - NOT window. Now window can be out of the picture.
It is usually bad practice to create functions inside of other functions. That would mean that each time you call function A, you recreate function B. Most of the time, people do that because they don't know better, not because they need to.
It appears to me that you intended to give steve a property called WayCoolTest, both being functions. That can be done.
var steve = function() {
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
steve(); //I'm Steve!
steve.WayCoolTest(); //I'm a Way Cool Test!
This works because functions are objects in javascript. Therefore, you can add properties to them.
Let's step it up!
To emphasize good practices, I'm going to wrap this example in an object testApp (it acts like a namespace..we're using that instead of window).
I will create a property of testApp called steve, which will be a function.
Rather than creating steve directly as a function, I will use an IIFE (immediately invoked function expression), which is a function that will return something to be set as steve.
Inside the IIFE, I will create the function for steve and also attach WayCoolTest to it, as demonstrated in the previous example, then that function is returned and assigned to steve.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve;
testApp.steve.WayCoolTest(); //I'm a Way Cool Test!
Now, let's consider another variation.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
WayCoolTest(); //Steve can use this, but nothing else can! Encapsulation.
}
var WayCoolTest = function() { //THIS PART!! No longer a property of "steve"
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve! I'm a Way Cool Test
testApp.steve.WayCoolTest(); //undefined, of course
That is very useful if for example steve is a complicated function and you want to break it up into some other small functions that only steve will know about.
To complement the other answers, your code would work this way:
var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]()["WayCoolTest"]();
or
var steve = (function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
})();
window["steve"]["WayCoolTest"]();
or, the dirtiest way...
steve=(function() {
var bob = {};
bob.__defineGetter__("WayCoolTest", function () {console.log('done deal');});
return bob;
})();
window["steve"]["WayCoolTest"];
Assuming steve is in the global scope and you dont seem to use steve as a constructor you can use immediate function and return the new object that you have created inside of it.
var steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
window["steve"]["WayCoolTest"]();
If it is in a closure then you would have to either remove var for hoisting to happen so it becomes a part of window or set it to the window object as a property.
window.steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
If you declare using var it doesn't get associated with the global window scope. It's instead a local variable. Also bob is not a property on the steve object they way you have it set up
ORIGINAL QUESTION:
i am studying js and i would like to know if there is any (useful) difference between these two ways of protecting the global scope other than the fact that the second one can be reused (called again).
option1:
var question = {};
(function(){
question.option1 = function() {
// some code
};
})();
option2:
var question = {};
question.option2 = function () {
//some code
};
question.option();
thanks!
EDIT 1:
thank you #luisperezphd. is there any difference between what you wrote and this (besides verbosity)?
var question = {};
question.option3 = {};
question.option3.privateVar = 0;
question.option3.testing = function () {
question.option3.privateVar++;
// some code
};
question.option3.testing();
EDIT 2:
thank you lanston and luisperezphd! i did not realize that question.option3.privateVar was available in the global.
is there any difference between this:
var question = {};
(function(){
var privateVar = "some value";
question.option4 = function(){
alert(privateVar);
}
})();
question.option4();
and this:
var question = {};
question.option5 = function() {
var privateVar = "some value";
var someFunction = function() {
alert(privateVar);
}
return someFunction;
}
question.option5()();
?
There is no difference in the example you gave, but there is a difference you haven't exploited. In the first example, you can utilize variables and not pollute the global namespace or the object namespace. The equivalent of a private field in most object orientated languages. You would do that like so:
var question = {};
(function(){
var PrivateVariable = 0;
question.option1 = function() {
PrivateVariable++;
// some code
};
})();
alert(question.PrivateVariable); // returns 'undefined'
The reason the code above returns undefined is because PrivateVariable is not a field in question. But functions in question can access PrivateVariable. This is truly a private variable.
On the other hand, if you wrote it like this:
var question = {};
question.PrivateVariable = 0;
question.option1 = function() {
question.PrivateVariable++;
// some code
};
alert(question.PrivateVariable); // returns 0
In this second case, PrivateVariable is in fact not private and publicly accessible.
Incidentally, you normally wouldn't reference question from inside a function that belongs you question. Instead, you would use the this keyword, like so:
var question = {};
question.PrivateVariable = 0;
question.option1 = function() {
this.PrivateVariable++;
// some code
};
But this would only work on public variables. It makes it more clear what is going on. Also, in some cases, it makes maintaining the code easier in that if you change the name of the variable from question you wouldn't have to change references to it inside the function. There are other benefits, but I don't know if I should get into it here.
#svdsvd,It's quite different between liusperezphd's and yours, the PrivateVariable,you can't get it in the global,but you can get your question.option3.privateVar in the global
I have the following JS code:
var Item = function ()
{
this.property = '';
this.myfunction = function ()
{
var value = this.property;
};
};
however, this does not point to the defining class so value doesn't get anything.
how do I access this.property from inside my function?
You need to create a closure which captures the value of parent scope's this:
var Item = function ()
{
this.property = '';
var self = this;
this.myfunction = function ()
{
var value = self.property;
};
};
Update: As others have pointed out, this closure is not needed when Item is used as a constructor (new Item()). Noting it here for future reference.
just create an alias for this. It will get closure'd.
var Item = function ()
{
this.property = '';
var self = this;
this.myfunction = function ()
{
var value = self.property;
};
};
Your code works as is if you call Item() as a constructor.
var item = new Item();
item.property = "the property";
item.myfunction(); // value = "the property"
this changes depending on the context. The context being how a function was invoked, not how it was defined, but how it was called.
Besides that, you seem to be mixing up two patterns here. I'm sure you meant something like:
var Item = function() {
this.property = '';
};
Item.prototype.myfunction = function() {
var value = this.property;
};
Instead you kind of mixed a closure pattern with prototypal, which doesn't seem very useful there. Closure is good for hiding members, allowing for true private members, but here you're exposing the property anyway. There's no reason not to stick that function on the prototype.
Do yourself a favor and ignore any concepts you have of more traditional OO, they won't do you any good here. Prototypal isn't nearly the same thing.
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;
}
My colleague has been using "new function()" with a lower case "f" to define new objects in JavaScript. It seems to work well in all major browsers and it also seems to be fairly effective at hiding private variables. Here's an example:
var someObj = new function () {
var inner = 'some value';
this.foo = 'blah';
this.get_inner = function () {
return inner;
};
this.set_inner = function (s) {
inner = s;
};
};
As soon as "this" is used, it becomes a public property of someObj. So someObj.foo, someObj.get_inner() and someObj.set_inner() are all available publicly. In addition, set_inner() and get_inner() are privileged methods, so they have access to "inner" through closures.
However, I haven't seen any reference to this technique anywhere. Even Douglas Crockford's JSLint complains about it:
weird construction. Delete 'new'
We're using this technique in production and it seems to be working well, but I'm a bit anxious about it because it's not documented anywhere. Does anyone know if this is a valid technique?
I've seen that technique before, it's valid, you are using a function expression as if it were a Constructor Function.
But IMHO, you can achieve the same with an auto-invoking function expression, I don't really see the point of using the new operator in that way:
var someObj = (function () {
var instance = {},
inner = 'some value';
instance.foo = 'blah';
instance.get_inner = function () {
return inner;
};
instance.set_inner = function (s) {
inner = s;
};
return instance;
})();
The purpose of the new operator is to create new object instances, setting up the [[Prototype]] internal property, you can see how this is made by the [Construct] internal property.
The above code will produce an equivalent result.
Your code is just similar to the less weird construct
function Foo () {
var inner = 'some value';
this.foo = 'blah';
...
};
var someObj = new Foo;
To clarify some aspects and make Douglas Crockford's JSLint not to complain about your code here are some examples of instantiation:
1. o = new Object(); // normal call of a constructor
2. o = new Object; // accepted call of a constructor
3. var someObj = new (function () {
var inner = 'some value';
this.foo = 'blah';
this.get_inner = function () {
return inner;
};
this.set_inner = function (s) {
inner = s;
};
})(); // normal call of a constructor
4. var someObj = new (function () {
var inner = 'some value';
this.foo = 'blah';
this.get_inner = function () {
return inner;
};
this.set_inner = function (s) {
inner = s;
};
}); // accepted call of a constructor
In example 3. expression in (...) as value is a function/constructor. It looks like this:
new (function (){...})(). So if we omit ending brackets as in example 2, the expression is still a valid constructor call and looks like example 4.
Douglas Crockford's JSLint "thinks" you wanted to assign the function to someObj, not its instance. And after all it's just an warning, not an error.