I have a simple issue, but i can't understand.
<script type="text/javascript">
var man = function(){
var age = 1;
this.shoes = 2;
};
man.prototype = {
create: function(){
//age = 5;
console.log(age);
console.log(this.shoes);
}
}
var man1 = new man;
man1.create();
</script>
-Ok,I create a man with 2 vars, age and shoes. I use "this" only in shoes. After I prototype a method in man.
-If I execute this code, first console.log say me:
Uncaught ReferenceError: age is not defined (logic)
And the second console is "2" (correct).
-If I write: console.log(this.age) the message error is: undefined.
-But if I put a value for age (age=5)(without using "var" for create var) in new method, it works.
Why I can only use age var if I put a value before read this but?
The age variable is within the "constructors" closure, which makes it only available there. You can use the age variable inside that function (closure), but not outside.
If you want to make it accessable from outside, add it to this or make a getter function like:
var man = function(){
var age = 1;
this.shoes = 2;
this.getAge = function() { return age; };
};
But if you don't put declare the variable inside the function, but still set it, then it will be defined on the global object, in the browser window. This will not make age available on the man object, but you will get access to it anywhere. Here's an to clarify a bit:
function tellAgeDelayedGlobal() {
age = 1;
setTimeout(function() { console.log(age) }, 1000);
}
function tellAgeDelayedDeclared() {
var age = 1;
setTimeout(function() { console.log(age) }, 1000);
}
tellAgeDelayedGlobal();
tellAgeDelayedDeclared();
age = 2;
this will print to console:
2
1
When you use var inside a function it is available within it(local scope).
var man = function(){
var age = 1;
this.shoes = 2;
};
Here age will be available only in the man method / constructor because this creates a local scope or rather is private to the constructor.
man.prototype = {
create: function(){
age = 5;
console.log(age);
console.log(this.shoes);
}
}
Here age will create a global scope. That is, this is equivalent to window.age = 5 and hence making it available in the entire app. Because of which you will be able to retrieve the value in any function since it is global now.
This must be avoided since it will not be automatically garbage collected(GC). If you really need it because other parts of your code has a dependency w.r.t. it, you can namespace it like: MyApp.age = 5. But w.r.t your current situation, I do not find a need in here.
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
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.
example:
function Foo() {
this.bla = 1;
var blabla = 10;
blablabla = 100;
this.getBlabla = function () {
return blabla; // exposes blabla outside
}
}
foo = new Foo();
original question:
I know that bla will be assigned to every instance of Foo.
What will happen with blabla?
new question:
what I understand now:
this.bla = 1; // will become an attribute of every instance of FOO.
var blabla = 10; // will become a local variable of Foo(**not** an attribute of every instance of FOO), which could be accessed by any instance of FOO only if there's a method like "this.getBlabla".
blablabla = 100; // will define a **new** (or change if exist) global(window) variable.
[Question:] Did i understand correctly?
Any internal-methods you give to this -- ie: this.method = function () {}; while inside of your Foo constructor function, are all going to have a reference to the blahblah which is unique to each instance of a Foo object.
function Wallet () {
var balance = 0;
this.checkBalance = function () { return balance; };
this.depositAmount = function (amount) { balance += amount; };
}
var wallet = new Wallet();
wallet.checkBalance(); // 0
wallet.depositAmount(3);
wallet.checkBalance(); // 3
But it's completely protected from access outside of wallet, unless you return it to somebody, from a privileged function.
wallet.balance; // undefined;
(added bit of interest -- if balance is a string, a number, or a boolean, even if you return it, that won't give people editing rights, or even permanent viewing access -- scalar variables are passed by value, so you're just passing the value of balance at the time -- if, however, balance was an object, a function or an array, they'd have permanent access to modify the crap out of your internal workings)
Note: methods HAVE to be assigned inside of the constructor for this to work.
Prototypes can't access internal variables.
Adding methods later won't give them access to internal variables.
This means that each instance will take up a little more memory, because each has its own copy of the methods, and has its own copy of the vars.
But if what you're doing requires private data, this would be a good way to get it.
In your example blabla is a local variable, so it will go away when the constructor function ends.
If you declare a function inside the constructor, which uses the variable, then the variable will be part of the closure for that function, and survives as long as the function (i.e. normally as long as the object):
function Foo() {
this.bla = 1;
var blabla = 10;
this.getBlabla = function() {
alert(blabla); // still here
}
}
It will become a local (think of 'private') variable within Foo(). Meaning that you can't access it outside of Foo().
function Foo() {
this.bla = 1; // this becomes an extension of Foo()
var blabla = 10; // this becomes a "Local" (sort of like a 'private') variable
}
You could expose it (by returning it) with a Foo method.
function Foo() {
var blabla = 10; // local
this.getBlabla = function () {
return blabla; // exposes blabla outside
}
}
Now outside of Foo():
var FooBar = new Foo();
var what_is_blabla = FooBar.getBlabla(); //what_is_blabla will be 10
jsFiddle demonstration
Variables declared with var inside a function used as a constructor will, like all other variables declared with var inside any function, be visible only during the execution of that function (unless the value is closed over using closures).
In other words, blabla is effectively invisible outside the function:
var foo = new Foo();
console.log(foo.bla); // 1
console.log(foo.blabla); // throws NameError
By defining functions which close over these variables, they become the closest thing JavaScript has to "private" variables:
function Foo() {
this.bla = 1;
var private = 1;
this.increment = function() {
++private;
}
this.getPrivateValue = function() {
return private;
}
}
foo = new Foo();
console.log(foo.bla); // 1
foo.bla = 6; // legal
console.log(foo.bla); // 6
console.log(foo.getPrivateValue()); // 1
// console.log(foo.private); // would throw an error
foo.increment(); // legal
console.log(foo.getPrivateValue()); // 2
// foo.getPrivateValue() = 5; // syntax error. Still can't reassign to private no matter what you try!
That variable is local to the constructor and won't be accessible outside of that scope (be it through this or otherwise), unless it is captured by a closure.
If you don't use the var keyword, "blabla" becomes a global variable. At other points in the code if you also use blabla without var, it will also be global, and you can accidentally change other instances of blabla and introduce unintended bugs in your code. "var" puts the variable in the current scope, so in the case above, it's only accessible to Foo.
blabla can almost be considered a private member of Foo.
See this article from Douglas Crockford.
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;
}
I'm trying to assign a callback dynamically to an Object of mine, I can't seem to figure out a way to do this while granting this function access to private variables. I've listed the relavant code below with comments where I ran into walls.
Object Factory
function makeObj ( o ) {
function F() {}
F.prototype = o;
return new F();
}
Module
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
return myMod;
})();
Various Attempts
myMod.someDynamicFunc = function someDynamicFunc(){
//privateVar === undefined;
alert( privateVar );
}
myMod.someDynamicFunc();
myMod.prototype.someDynamicFunc = function someDynamicFunc(){
//ERROR: Cannot set property 'someDynamicFunc' of undefined
alert(privateVar);
}
myMod.someDynamicFunc();
In this attempt I tried making a setter in the module object... to no avail.
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.setDynamicFunction = function ( func ){
if(func !== undefined && typeof func === "function"){
//Uncaught TypeError:
// Cannot read property 'dynamicFunction' of undefined
myMod.prototype.dynamicFunction = func;
//also tried myMod.dynamicFunction = func;
}
}
return myMod;
})();
var myModule = makeObject( MODULE );
myModule.setDynamicFunction(function(){
alert(privateVar);
});
myModule.dynamicFunction();
Am I just using JavaScript wrong? I'd really like to be able to assign callbacks after the object is initiated. Is this possible?
You can't access the private variable via a callback function set dynamically (since it can't be a closure if it's attached later), but you can set up a system by which you would be able to access the variable:
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.callback = function(fn) {fn(privateVar);};
return myMod;
})();
var someDynamicFunc = function(param) {alert(param);};
myMod.callback(someDynamicFunc);
Of course, this makes it not really private, since anyone could do this. I don't see how it would be possible at all for you to have a "private" variable that you access via dynamically attached functions, without allowing anyone else's dynamically attached functions to have the same privilege (thus making it not really private).
I guess you did not really understand exactly how closures work.
Closures mean that scopes always have access to the outer scope they were defined in.
function Counter(start) {
var count = start;
return {
increment: function() { // has access to the outer scope
count++;
},
get: function() {
return count;
}
}
}
var foo = new Counter(4);
foo.increment();
foo.get(); // 5
The above example returns two closures, both the function increment as well as get keep a reference to the count variable defined in the constructor.
One cannot access count from the outside, the only way to interact with it is via the two "closured" functions.
Remember, closures work by keeping a reference to their outer scopes, so the following does not work:
var foo = new Counter(4);
foo.hack = function() { // is not getting defined in the same scope that the original count was
count = 1337;
};
This will not change the variable count that's inside of Counter since foo.hack was not defined in that scope, instead, it will create or override the global variable count.