javascript private inner functions in module with access to "this" scope [duplicate] - javascript

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Javascript outer scope variable access
I have a javascript module that looks something like below. The main issue I'm having is how to access variables in the "this" scope from the private someOtherFunc. Is there a way to access this.myvar in the private someOtherFunc
var mymodule = (function(){
return {
MyObj : function() {
this.myvar = 123;
this.publicfunc = function() {
someOtherFunc();
};
var someOtherFunc = function() {
//this doesn't seem to work
this.myvar = 456;
};
}
}
}
The idea is that I want to be able to do something like
new mymodule.MyObj().publicfunc, but make the someOtherFunc private

Forget my previous answer. You can do this just by adding a private version of this.
var mymodule = (function() {
return {
MyObj : function() {
this.myvar = 123;
var that = this;
this.publicfunc = function() {
someOtherFunc();
};
var someOtherFunc = function() {
that.myvar = 456;
};
return this;
}
};
});
Bear in mind that, with your code, every time you call MyObj you get a new object.
So this would do what you want:
>var o = new mymodule().MyObj()
>o.myvar
123
>o.publicfunc()
>o.myvar
456
but not this
>var m = new mymodule()
>m.MyObj().myvar
123
>m.MyObj().publicfunc()
>m.MyObj().myvar
123
If that's not what you want, consider doing something like this
var mymodule = (function() {
var myObj = null;
this.MyObj = function() {
if(myObj != null)
return myObj;
myObj = {};
myObj.myvar = 123;
myObj.publicfunc = function() {
someOtherFunc();
};
var someOtherFunc = function() {
myObj.myvar = 456;
};
return myObj;
};
});

Declare myvar using the var keyword, making it private, then access it without the this.:
function MyObj(){
var myvar = 123;
this.publicfunc = function() {
someOtherFunc();
};
var someOtherFunc = function(){
alert(myvar);
};
}
var o = new MyObj();
o.publicfunc();
If you need public access to myvar then create a public getter/setter.
jsFiddle Demo
​

I think what you're looking for is a way to encapsulate myvar for changes. When some of the other answers run, myvar usually will stay as 123 because the initially returned object from mymodule holds on to that initial value.
Return a function that gets the value of myvar even after it's been modified, and I think that helps your problem.
Here's the code that works for me:
var mymodule = (function(){
var myvar = 123,
publicfunc = function() { myvar = 456 },
getMyVar = function() { return myvar; };
return {
someOtherFunc : publicfunc,
myPublicVar : getMyVar
};
}());
mymodule.someOtherFunc();
alert(mymodule.myPublicVar());​ //gives you 456
JSFiddle here.
I hope this helps.

Why not build it a little more deliberately?
// this one returns an object used like:
// myModule.myInt; /* 456 */
// myModule.myFunc(); /* 124 */
var myModule = (function () {
var secretData = 123,
publicData = 456,
publicFunc = function () { return privateFunc(secretData); },
privateFunc = function (num) { return num + 1; },
public_interface = {
myInt : publicData,
myFunc : publicFunc
};
return public_interface;
}());
I went through the trouble of explicitly naming the returned, public object, but it's now very clear what is and isn't public, and yet, each one of those things will have access to the variable versions of one another, with the one exception being that if you change myModule.myInt or publicData, they will no longer be equal.
To demonstrate what I mean in the comments below, creating multiple instances with their own private data/methods, I just add in one more layer of function-scope:
var myModule = (function () {
var static_int = 789,
makeInstance = function (/* any constructor values */) {
var secretData = 123,
publicData = 456,
publicFunc = function () { return privateFunc(secretData); },
privateFunc = function (num) {
console.log(static_int);
return num + 1;
},
public_interface = {
myInt : publicData,
myFunc : publicFunc
};
return public_interface;
};
return makeInstance;
}());
You now use it like:
var newModule = myModule(/* instance parameters */);
newModule.myFunc();
...or
var num = myModule(/* instance parameters */).myFunc();
If you wanted to save memory, you could have static helper functions inside of the static-layer:
var myModule = (function () {
var static_int = 789,
static_addOne = function (num) { return num + 1; },
static_divideBy = function (dividend, divisor) { return dividend/divisor; },
makeInstance = function (/* any constructor values */) {
var secretData = 123,
publicData = 456,
publicFunc = function () { return privateFunc(secretData); },
privateFunc = function (num) {
console.log(static_int);
return num + 1;
},
public_interface = {
myInt : publicData,
myFunc : publicFunc
};
return public_interface;
};
return makeInstance;
}());
And now you have "private" functions which are only written one time (ie: you save memory), but any instance can use those functions.
Here's the catch:
Because of how scope and closure work, the static functions have NO access to values inside of the instance (functions inside have access to the static functions, not the other way around).
So, any static helper functions MUST have the values passed to them as arguments, and if you're modifying a number or a string, you MUST return the value out of that function.
// inside of a private method, in any instance
var privateString = "Bob",
privateFunc = function () {
var string = static_helper(privateString);
privateString = string;
//...
};

You don't return anything from MyObj.
return this;
should fix it.

Use the bind method:
var someOtherFunc = function() {
this.myvar = 456;
}.bind(this);

Related

Make object variables be accesible within all "deeper" scope

I'm currently coding a kind of plugin in JS. I've just learnt about objects, and I'm kind of annoyed by the fact that I can't access variables set within the constructor, two or more levels up. Here's what I mean:
var myConstructor = function()
{
this.one = "one";
this.two = "two";
this.publicMethod = function()
{
console.log("I can access: ", this.one);
var privateMethod = function()
{
console.log("I cannot access var two like this: ", this.two);
};
privateMethod();
};
};
var myObject = new myConstructor();
myObject.one = 1;
myObject.two = 2;
myObject.publicMethod();
So, how could I make privateMethod access the variables that are set within the constructor? In the same manner that publicMethod uses this to do so. Is this possible? Thank you very much.
Try this.
var myConstructor = function()
{
this.one = "one";
this.two = "two";
this.publicMethod = function()
{
// new variable
_two = this.two;
console.log("I can access: ", this.one);
var privateMethod = function()
{
console.log("I cannot access var two like this: ", _two);
};
privateMethod();
};
};

Javascript oop undefined value: Method to add a scope?

Code:
var test = {
con: true
};
var conrun= function(){
return this.con;
};
Function.prototype.curry = function(scope){
var fn = this;
var scope = scope||window;
return function(){
fn.apply(scope,arguments);
}
}
conrun = conrun.curry(test);
alert(conrun());
//result:undefined
"curry" method, the function will return, "conrun" fonkiyonuna "test" add to the scope of...
What should I do ?
Your curry loses the return value. Change that line to:
return fn.apply(scope, arguments);

JavaScript Binding Objects

How could I do this?
Class
var Factory = (function() {
var Class = function() {
this.name = 'John';
this.methods = {
get: function(callback) {
callback();
}
};
};
return {
createClass: function() {
return new Class();
}
};
}());
Usage
var MyClass = Factory.createClass();
MyClass.methods.get(function() {
this.name // => returns undenfined
});
Thanks for any help!
You need to save a reference to this in the outer Class function and call call:
var instance = this;
this.methods = {
get: function(callback) {
callback.call(instance);
}
};
var Class = function() {
// Save a reference to this that can be used in local closures.
var me = this;
this.name = 'John';
this.methods = {
get: function(callback) {
// Use 'call()', passing the reference to the 'Class' object
callback.call(me);
}
};
};
#SLaks - The declaration of scope as a Global variable is bad practice.
#Ferdinand Beyer - have you tested if it functions?
The better way will be the scope binding. The Prototype javascript framework produced a nice concept and we can easily implement it like
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
and then yoou code should have only a single change and it will maintin the scope of your class.
var Factory = (function() {
var Class = function() {
this.name = 'John';
var me = this;
this.methods = {
get: function(callback) {
callback();
}
};
};
return {
createClass: function() {
return new Class();
}
};
}());
var MyClass = Factory.createClass();
MyClass.methods.get(function() {
console.info(this.name) // => returns undenfined
}.bind(MyClass));
I mean only the function call get with .bind(MyClass)

Is it possible to append functions to a JS class that have access to the class's private variables?

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());

Issues with closure and a method defined elsewhere

I am pretty new at Javascript so I may not be using the exact terminology.
Suppose that I define an object literal as such.
var myObj = {
someMethod:function() {
//can we have access to "someValue" via closure?
alert(someValue);
}
}
And then we assign the function to another object like this.
var myOtherObject = {
someOtherMethod:function() {
var someValue = 'Hello World';
//If we did this, then the function would have access to "someValue"
this.aMethod = function() {
alert(someValue);
}
//This does not work for "someMethod" to have access to "someValue"
//this.someMethod = myObj.someMethod;
//This does work, however I would like to avoid the use of eval()
this.someMethod = eval("("+myObj.someMethod.toString()+")");
}
}
Is it possible to have myOtherObject.someMethod() work without using eval() as above?
someValue is local to someOtherMethod and can not be accessed by myObj.someMethod() in any way. There are two solutions:
a) Pass someValue as a parameter to the first method:
var myObj = {
someMethod:function(someValue) {
alert(someValue);
}
}
var myOtherObject = {
someOtherMethod:function() {
var someValue = 'Hello World';
// The next line illustrates the 'closure' concept
// since someValue will exist in this newly created function
this.someMethod = function () { myObj.someMethod(someValue); };
}
}
myOtherObject.someOtherMethod();
myOtherObject.someMethod();
b) Store someValue as a member of the object itself, not as a local variable:
var myObj = {
someMethod:function() {
alert(this.someValue);
}
}
var myOtherObject = {
someOtherMethod:function() {
this.someValue = 'Hello World';
this.someMethod = myObj.someMethod;
}
}
myOtherObject.someOtherMethod();
// 'this' in someMethod will here refer to the new myOtherObject
myOtherObject.someMethod();

Categories

Resources