I have a feeling I'm missing something obvious. I'm returning a variable from my javascript module, but it keeps coming back undefined.
Here's the module:
var MyNs = MyNs || {};
MyNs.Global = function () {
var privateTestVar;
var init = function () {
if (privateTestVar == null ) {
privateTestVar = "this is a test" ;
console.log( 'Init: ' + privateTestVar);
}
};
var Public = {
init: init,
TestVar: privateTestVar
}
return Public;
} ();
Here's the call:
MyNs.Global.init();console.log( 'Called: ' +MyNs.Global.TestVar);
The console.log in the init function works fine and returns the value, but the other console log returns undefined. I'm totally missing it. Any help would be appreciated.
Update: I've change the code a bit, to this:
var privateTestVar = function () { return 'Test!'; }
var Public = {
TestVar: privateTestVar
}
And variations of that, but it returns this exact text to the console: "function () { return 'Test!'; }"
At the time that Public is assigned here:
var Public = {
init: init,
TestVar: privateTestVar
}
privateTestVar is still undefined (because init() hasn't been run yet) so the TestVar property is initialized to the value of privateTestVar which is undefined.
The TestVar property gets assigned the value of privateTestVar. If it's initially undefined (which it is in this case), it will stay that way until you assign something different to the TestVar property. I won't automatically inherit future values of privateTestVar which is perhaps what you were expecting. Javascript does not have a way of specifying that one variable will always contain whatever is assigned to another variable. privateTestVar and the TestVar` property each have their own value. Assigning something to one variable does not affect the other.
I'd suggest making a private variable really a private one, using getters instead. This will work correctly:
var Public = {
init: init,
getVar: function() { return privateTestVar; }
}
MyNs.Global.init();console.log( 'Called: ' +MyNs.Global.getVar());
Issue is as stated by #jfriend00. Change the code to
var init = function () {
if (privateTestVar == null ) {
privateTestVar = "this is a test" ;
Public.TestVar = privateTestVar;
console.log( 'Init: ' + privateTestVar);
}
};
I didn't test this out but theoretically it should work.
I think this is the structure you are looking for:
function PrivateFunc(private, public){
this.privateVar = private;
this.publicVar = public;
}
function PublicFun(public){
this.publicVar = public;
if(this.publicVar == null)this.publicVar = 'This is a public variable.';
this.PrivateFun = function(private){
return new PrivateFunc(private, this.publicVar);
}
}
var pf = new PublicFun('public variable');
var pv = pf.PrivateFun('private variable');
console.log('pf.publicVar = '+pf.publicVar);
console.log('pf.privateVar = '+pf.privateVar);
console.log('pv.publicVar = '+pv.publicVar);
console.log('pv.privateVar = '+pv.privateVar);
Notice that PrivateFunc is not PrivateFun. The real factor comes down to the key word this. this refers to the current Object as when you type this. var is only accessible inside your method. You should think of a JavaScript Object as an Associative Array. If that doesn't suit your needs try:
var jsObject = {
publicVar: null,
PrivateFun: function(private){
var privateVar = private; //cannot access with dot
return this;
},
PublicFun: function(public){
this.publicVar = public;
if(this.publicVar == null)this.publicVar = 'This is a public variable';
return this;
}
}
var pf = jsObject.PublicFun();
var pv = jsObject.PrivateFun('private variable');
console.log('pf.publicVar = '+pf.publicVar);
console.log('pf.privateVar = '+pf.privateVar);
console.log('pv.publicVar = '+pv.publicVar);
console.log('pv.privateVar = '+pv.privateVar+' //cannot access with dot');
Note that Object Literals are not Constructors, so you cannot make new instances. Also, in the Object Literal case, var privateVar is virtually useless, unless you don't want the privateVar returned. this must be returned in order to access jsObject, which holds the reference to publicVar.
Related
Trying to understand JS better, have a couple of clarifications. Lets suppose we have the following method
var customer = function(){
var name = "Contoso";
return {
getName : function(){
return this.name;
},
setName : function(newName){
this.name = newName;
}
}
}();
why is name not visible outside ?, when we log (customer.name) its undefined, however if we remove the self initializing parenthesis on function and change the variable declaration to (this.name) & again when we log the same we are able to see the value. what am i missing in here.
You need to take in consideration that JavaScript doesn't really have native classes. With this said, the way you can create constructors in order to "mimic" a class and be able to use this you need to create something like so:
function fnc (string) {
this.string = string;
}
fnc.prototype.getString = function() {
return this.string;
}
var x = new fnc('bar');
console.log(x.getString()); //bar
This is called the Constructor Pattern.
What you're trying to do is use something called the Module Pattern which works something like so:
var fn = (function() {
var string = 'foo';
return {
getString() {
return string;
}
}
})();
console.log(fn.getString()); //foo
Here is a working example: https://repl.it/FCn7
Also, a good read: https://addyosmani.com/resources/essentialjsdesignpatterns/book/
Edit
Example using getString and setString with the Module Pattern
var fn = (function() {
var string = 'foo';
return {
getString() {
return string;
},
setString(str){
string = str;
}
}
})();
fn.setString('xyz');
console.log(fn.getString()); // xyz
var is creating variable inside function scope which is not available outside as function property. If you want to access properties like customer.name you need to initialize it as this.name as you noticed.
var in this example is like creating private variable which can be modified by functions, but not directly.
SO this will work:
var customer = function(){
var name = "Contoso";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
}();
I have this Javascript class and want to add some kind of function (like prototype)
to properties of this class.
function theUploader(virtualField)
{
var self = this;
//self.v = virtualField;
self.v = (function(){return self.v; this.clear = function(){self.v = '';}})()
self.v.prototype = function clear() {
self.v = '';
}
}
i tried those lines.
i couldn`t find out the right way to define such a thing.i want to call it like this
var temp = new theUploader('smart');
temp.v.clear();
someone guid me with jsaon.but still working on it
The problem(s) with this line:
self.v = (function(){return self.v; this.clear = function(){self.v = '';}})()
...would be more obvious if you split it out over several lines:
self.v = (function(){
return self.v;
this.clear = function(){
self.v = '';
}
})()
It's an immediately invoked function expression which returns on its first line, so it never gets to the this.clear = ... line. The value returned, self.v, will be undefined at that point, which means the self.v property you assign that value to will also be undefined, which means then on this line:
self.v.prototype = function clear() {
...you'll get an error TypeError: Cannot set property 'prototype' of undefined.
It's a bit hard to tell exactly what you're trying to do given the confusion in your theUploader() function, but given that you said you want to be able to do this:
var temp = new theUploader('smart');
temp.v.clear();
Then you need to create a .v property that is itself an object that has a .clear() method, so:
function theUploader(virtualField)
{
var self = this;
self.v = {}; // create a v property that is an object
self.v.clear = function(){self.v = '';}; // add a method to v
}
...would do it. Or you could define the clear function directly in the object literal:
self.v = {
clear : function(){self.v = '';}
};
(Either way it doesn't really make sense to me that calling self.v.clear() would actually overwrite the .v property with an empty string, but if that's what you want this is how you could do it.)
self.v.prototype = function clear() {
self.v = '';
}
Should be
self.v.clear = function() {
self.v = '';
}
I have declared this javascript class:
var TablixColumns = function(){
this.g = 'wtf';
this.tablixColumns = []; //[];
return {
addTablixColumn: function(tablixColumn){
alert(this.g);
//this.tablixColumns.push(tablixColumn.getTablixColumn());
}
}
};
my problem is that when I try this: alert(this.g) the alert comes out undefined
of course my initial function definition read: this.tablixColumns.push(tablixColumn.getTablixColumn());
but then I get the error that reads something like "No Method push of undefined"
what's weird is I have this class declaration:
var TablixColumn = function(){
columnWidth = '<Width>3.135cm</Width>'; //default width value
return{
setColumnWidth: function(width){
this.columnWidth = '<Width>' + width + 'cm</Width>';
},
getTablixColumn: function(){
return '<TablixColumn>' + this.columnWidth + '</TablixColumn>';
}
}
};
and the TablixColumn class works fine,
and yes, I have declared this.g and this.tablixColumns without the 'this.' part, but it's just refusing to work!
I'm going to kill someone if this doesn't work tonight can someone help me please?
You need to set a reference to the current object (this) outside the nested function expression. Here's how your code should look:
var TablixColumns = function() {
...
var self = this;
return {
addTablixColumn: function(tablixColumn) {
alert(self.g);
}
};
};
You can even set a property to the returned object literal if you want:
// ...
return {
g: 'wtf',
addTablixColumn: function(tablixColumn) {
alert(this.g); // 'wtf'
}
};
// ...
Note that you shouldn't use TablixColumns as a constructor if you're returning from it like this. You're using two idioms here; prototypal inheritance and the module pattern. Are you going to instantiate the constructor with new? If so, then don't return the object literal. Rather, set the methods on the prototype of the function:
var TablixColumns = function() {
this.g = 'wtf';
this.tablixColumns = [];
};
TablixColumns.prototype.addTablixColumn = function addTablixColumn() { ... };
TablixColumns.prototype./* ... */
...
Otherwise, don't use this inside the constructor. Simply make the properties normal variables.
Okay guys so I figured out my problem:
all the references to variables of the current instance should not have been preceded by the this. keyword
so this is how my declaration looks now:
var TablixColumns = function(){
g = 'wtf';
tablixColumns = []; //[];
return {
addTablixColumn: function(tablixColumn){
alert(g);
tablixColumns.push(tablixColumn.getTablixColumn());
}
}
};
Thanks #Bergi for pointing this out
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());
I need to create simple reusable javascript object publishing several methods and parameterized constructor. After reading through several "OOP in JavaScript" guides I'm sitting here with an empty head. How on the Earth can I do this?
Here my last non-working code:
SomeClass = function(id) {
this._id = id;
}
(function() {
function intFun() {
return this._id;
}
SomeClass.prototype.extFun = function() {
return incFun();
}
})();
This is my usual approach:
MyClass = function(x, y, z) {
// This is the constructor. When you use it with "new MyClass(),"
// then "this" refers to the new object being constructed. So you can
// assign member variables to it.
this.x = x;
...
};
MyClass.prototype = {
doSomething: function() {
// Here we can use the member variable that
// we created in the constructor.
return this.x;
},
somethingElse: function(a) {
}
};
var myObj = new MyClass(1,2,3);
alert(myObj.doSomething()); // this will return the object's "x" member
alert(myObj.x); // this will do the same, by accessing the member directly
Normally the "this" keyword, when used in one of the object's methods, will refer to the object itself. When you use it in the constructor, it will refer to the new object that's being created. So in the above example, both alert statements will display "1".
An exception to this rule is when you pass one of your member functions somewhere else, and then call it. For example,
myDiv.onclick = myObj.doSomething;
In this case, JavaScript ignores the fact that "doSomething" belongs to "myObj". As a result, the "this" inside doSomething will point to another object, so the method won't work as expected. To get around this, you need to specify the object to which "this" should refer. You can do so with JavaScript's "call" function:
myDiv.onclick = function() {
myObj.doSomething.call(myObj);
}
It's weird, but you'll get used to it eventually. The bottom line is that, when passing around methods, you also need to pass around the object that they should be called on.
I usually don't worry too much about hiding the internals, although I do prefix them with underscores to mark them as not intended to be used outside the "class". Normally what I will do is:
var MyClass = function() {};
MyClass.prototype = {
_someVar : null,
_otherVar : null,
initialize: function( optionHash ) {
_someVar = optionsHash["varValue"];
_otherVar = optionsHash["otherValue"];
},
method: function( arg ) {
return _someVar + arg;
},
};
And use it as so...
var myClass = new MyClass( { varValue: -1, otherValue: 10 } );
var foo = myClass.method(6);
All vars are private:
SomeClass = function (id) {
var THIS = this; // unambiguous reference
THIS._id = id;
var intFun = function () { // private
return THIS._id;
}
this.extFun = function () { // public
return intFun();
}
}
Use THIS within private methods since this won't equal what you might expect.
From http://learn.jquery.com/code-organization/concepts/#the-module-pattern:
// The module pattern
var feature = (function() {
// private variables and functions
var privateThing = "secret";
var publicThing = "not secret";
var changePrivateThing = function() {
privateThing = "super secret";
};
var sayPrivateThing = function() {
console.log( privateThing );
changePrivateThing();
};
// public API
return {
publicThing: publicThing,
sayPrivateThing: sayPrivateThing
};
})();
feature.publicThing; // "not secret"
// logs "secret" and changes the value of privateThing
feature.sayPrivateThing();
So using returning an object that aliases its "methods" could be another way to do it.
I've read from http://www.amazon.com/Programming-Oracle-Press-Poornachandra-Sarang-ebook/dp/B0079GI6CW that it is always good practice to use getters and setters rather that accessing the variable directly from outside the object, so that would eliminate the need of returning variables by reference.
BTW you could just use this.variable to reference/declare a public variable and var variable to declare a private variable.
I know this is a late answer, but I hope it helps anyone who reads it in the future.