How can I refer to a local variable inside a private function? For example, in the next code, in function myDisplay how can I get the object myObject of show function object and obtain id = 'B'?
var charge = (function($){
var open = function(){
var myObj = {
id: 'A'
};
};
var show = function(){
var myObj = {
id: 'B'
};
myDisplay();
};
function myDisplay(){
//Here, how to refer to var myObj of show function object?
}
return {
open: open,
show: show
};
})(jQuery);
The whole idea behind scoping is that you can't. myObj is private to the function stored in show.
Furthermore, in this particular example, myObj won't even exist unless a call to show() is actually in progress. Consider this point. It won't even exist during the myDisplay() call. (And two different calls to show() will each have different myObj instances.)
If you want the outer function and show to share data, move myObj out to the outer scope - the same scope that ret is in.
var charge = (function($) {
var myObjA = {
id: 'A'
};
var myObjB = {
id: 'B'
}
var open = function() {
};
var show = function() {
myDisplay();
};
function myDisplay() {
console.log(myObj);
//Here, how to refer to var myObj of show function object?
};
return {
open: open,
show: show
};
})(jQuery);
I recommended you use module pattern like that.
And, because the javascripts closure.
You can't read the myObj as you want it.
I provided you a solution hope you like it!
Related
I have what I think is a fairly simply question but it's one that I can not find the answer to. I have a objects literal that I have created that groups functions, I want to know how I can create a variable that is inside the objects literal and editable/accessable by all the functions within that objects literal. At the moment the only way I know how to do this is create a global variable but I want to stop populating the global in this way. To better describe what I'm looking fiddle
http://jsfiddle.net/aT3J6/
Thanks, for any help.
var clickCount = 0;
/* I would like to place clickCount inside hideShowFn Object but all function inside need access to it, so global within hideShowFn */
hideShowFn = {
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
Create a function which is invoked immediately and returns the object, with the private variable inside the function, like this:
var obj = (function () {
var privateStuff = 'private';
return {
func1: function () {
//do stuff with private variable
},
func2: function () {
//do stuff with private variable
}
};
}());
http://jsfiddle.net/BE3WZ/
This is the way to have private variables in Functional Programming.
http://jsfiddle.net/mattblancarte/aT3J6/10/
Another option would be the pseudo-classical style:
function Constructor(){
var private = 'private';
this.public = 'public';
this.methods = {
//your methods here...
};
}
var obj = new Constructor();
Don't forget to use the 'new' keyword, or else you are going to be globally scoped.
Your code translated to this style would be:
function Test(){
var that = this,
clickCount = 0;
this.init = function(){
$('.clickMe').click(this.addToCount);
};
this.addToCount = function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
};
}
var test = new Test();
test.init();
You can make a closure as Cokegod says or you can simply add the variable to the object and access it using this
hideShowFn = {
clickCount: 0,
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
this.clickCount++;
$('<p>'+ this.clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
This dosn't work as Musa says the scope in addToCount will be the dom node clicked.
But see Cokegod's answer.
What is the best design pattern for achieving the following (which doesn't work)?
var obj = (function() {
// code defining private variables and methods
var _obj = {
property: value,
method1: function() {
// do stuff
},
method2: function() {
// use property
var prop = _obj.property; // obviously doesn't work
// call method1
obj.method1(); // "obj" not finished being defined yet!
}
};
// obviously now I could do...
var prop = _obj.property;
return _obj;
})();
// and I could now do...
obj.method1();
A variation which I think should work is
var obj = (function() {
var property = value,
method1 = function() {
// do stuff
},
method2 = function() {
// use property
var prop = property;
// call method1
method1();
},
_obj = {
property: property,
method1: method1,
method2: method2
};
return _obj;
})();
Similarly, how does it work for objects meant to be created with the new operator? Within the constructor function itself you can write this.method(). But what if you want to keep the constructor small, only defining those things which will likely be customized upon creation, and then defining the rest in the prototype? (This seems to be the common pattern.) Can the properties / methods within the prototype interact in any way?
var MyObj = function(name) {
this.name = name;
};
var obj = new MyObj('Bob');
MyObj.prototype = {
called_often: function() {
// lots more code than just the following
return document.getElementById('someID').value;
},
global_default: 'value', // can be changed, so need to pull value when run
does_stuff: function(value) {
var str = global_default + value, // can't access global_default on its own
input = MyObj.called_often(), // doesn't work; MyObj.prototype.called_often() DOES
name = this.name; // 'this' used in the prototype doesn't work
// even within a created object
return name + input + str;
}
};
I'm sure there's better ways to achieve my result whenever I run into this problem. This code isn't situation specific and just illustrates the general problem. So you won't be able to give me an alternative for those specific situations I run into. But maybe you can help my overall thinking.
Well, from your first example:
var _obj = {
property: value,
method1: function() {
// do stuff
},
method2: function() {
// use property
var prop = this.property;
// call method1
this.method1();
}
};
That's what the this value is for.
Now, what you cannot do is refer to a property of an "under construction" object from elsewhere in the object literal syntax. (It's hard to give an example because it's just not syntactically possible.) In cases where you want to do that, you do need one or more separate assignment statements.
Guess what? You are making simple stuff complex. Pointy's answer is good, but the prototype way is better for several reasons. That's why I am describing (rather, making corrections in) the last method. Check this fiddle.
var MyObj = function(name) {
this.name = name;
};
MyObj.prototype = {
called_often: function() {
// lots more code than just the following
return 'VALUE'; //document.getElementById('someID').value;
},
global_default: 'value', // can be changed, so need to pull value when run
does_stuff: function(value) {
var str = this.global_default + value, // can't access global_default on its own
input = this.called_often(), // doesn't work; MyObj.prototype.called_often() DOES
name = this.name; // 'this' used in the prototype doesn't work
// even within a created object
return name + input + str;
}
};
var obj = new MyObj('Bob');
I'm having troubles finding detailed information on this issue.
I would like to instantiate Bar() within Foo() without having to pass a pointer to Foo(). Or some way for Bar() to know it's a child of Foo(). Is this possible? Or am I already using a sufficient method?
Basically, I'm trying to avoid a call like:
var bar1 = new Bar(this,someValue);
Below I have a rough example of the method I'm currently using.
function Bar(p,val) {
var par = p,
value = val;
this.__defineGetter__("value", function() {
return par.dun.value + value;
});
}
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
var dun = new Dun(15);
var bar1 = new Bar(this, 10);
var bar2 = new Bar(this, 20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
}
var myFoo = new Foo();
myFoo.bar1.value;
Thanks.
No this is not possible, since there is no built in parent/child logic in JavaScript. They are just references to objects.
Update
oh sorry, I think I misunderstood your question. I´ve asked the same question some time ago:
here. What you are trying to do, is to get the object that is "this" in the function that called the current function.
The answer is: you can´t do it...
But you could do it using the scope:
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
var dun = new Dun(15);
var bar1 = new Bar(10);
var bar2 = new Bar(20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
function Bar(val) {
this.__defineGetter__("value", function() {
return dun.value + val;
});
}
}
var myFoo = new Foo();
myFoo.bar1.value;
PS: Not related to your question, but nice to know:
since
function(val){}
is the same as
function(){
var val = arguments[0];
}
you don`t have to create a new var and pass the arguments value to it. You can use the argument variable directly.
There is no way to automatically know the this pointer of the caller of a new. So, if you want to know what that this value is without passing it as part of the constructor, then you'd have to set some semi-global state that contains the appropriate information. You could do so like this:
function Bar(val) {
var par = Bar.parent(),
value = val;
this.__defineGetter__("value", function() {
return par.dun.value + value;
});
}
// global methods and state on the Bar function
Bar.createContext = [];
Bar.push = function(o) {Bar.createContext.push(o);}
Bar.pop = function() {Bar.createContext.pop();}
Bar.parent = function() {return(Bar.createContext[Bar.createContext.length - 1]);}
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
Bar.push(this); // set global state
var dun = new Dun(15);
var bar1 = new Bar(10); // don't need to pass "this" since it's in the global state
var bar2 = new Bar(20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
Bar.pop(); // restore global state
}
var myFoo = new Foo();
myFoo.bar1.value;
And, you can see it work here: http://jsfiddle.net/jfriend00/wMgBL/
You need to give the child object one of the following:
A direct pointer from one object to another, as in your example code.
Unique information about the parent object, such that it can determine what that parent is indirectly through other means.
For example, you could store all instances of Foo in a global registry object (either an object literal or array), which the child bar object could search through. It would be looking for the object that has a child bar equal to itself.1 In this way, the fact that it is a child of Foo is the unique identifier. Unless, of course, one bar can be shared across multiple foos. Then you're hosed. :)
1: The downside to this is that you're storing every instance of Foo ever created, which means they'll never be garbage collected: you'll be leaking memory, which could be bad if your environment sticks around for a while (e.g. a node.js app).
I have a function name in a string:
var func = "doTest";
I need this function to be applied to the current instance ("this");
So I need it to call:
this.doTest();
How can I do this? I cannot go via window.
Thanks,
Wesley
Just use the construct of object[functionName]();, like so:
function Person() {};
Person.prototype.speak = function() { alert('ohai'); };
var john = new Person, action = 'speak';
john[action]();
Alternative style:
var Person = {
speak: function() { alert('ohai'); },
speakDelegate: function() { var action = 'speak'; this[action](); }
};
Person.speakDelegate();
this[func]();
No need to .call or .apply since context is held in the reference.
For example:
var obj = {
doTest: function(){ console.log(this); },
fn: function(){ var name='doTest'; this[name](); }
};
obj.fn(); // logs the object, proving this has the correct context.
Try the following
var funcObj = this["doTest"];
funcObj.apply(this);
What this does is grab the member named doTest from this. It then executes the function via apply and tells javascript to bind this as this within the function. I think the example is a bit less confusing if you consider the same code on a non-this value
var obj = {
doTest: function() {
console.log("doTest called");
}
};
var doTestFunc = obj["doTest"];
doTestFunc.apply(obj);
In this case the method doTest will be executed with the value obj as this
If you are using jquery you can just do:
$(this)[func]()
I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());