I have an object mainly composed of functions/ methods, much like this (Which should work!):
function thing1(){
this.thing2 = function(){
this.thing3 = function(){
alert();
}
}
}
But
When I call thing1.thing2.thing3(), I get
Cannot read property 'thing3' of undefined
complete pseudocode:
function thing1(){
this.thing2 = function(){
this.thing3 = function(){
alert();
}
}
}
var foo = new thing1();
foo.thing2.thing3();
thing2 doesn't return anything which results in returning undefined.
If you want to write chained functions, you need to return this:
function thing1() {
this.thing2 = function() {
this.thing3 = function() {
alert();
}
return this; // chained
}
}
Generally speaking, it's better to assign methods to a functions prototype if you intend to use it as a constructor. You can still chain functions on the prototype.
function thing1() {
}
thing1.prototype.thing2 = function() {
return this; // chained
};
thing1.prototype.thing3 = function() {
alert('thing3');
return this; // you can make this one chained as well, if you like
};
var t = new thing1();
t.thing2().thing3().thing2().thing3();
If you want to just create a basic chain without requiring parentheses, you could create a separate getter function.
function thing1() {
}
Object.defineProperty(thing1.prototype, 'thing2', {
get: function() {
return this;
}
});
thing1.prototype.thing3 = function() {
alert('thing3');
return this;
};
var foo = new thing1();
foo.thing2.thing3().thing2.thing3();
Those are constructors:
function thing1(){
this.thing2 = function(){
this.thing3 = function(){
alert();
}
}
}
(new (new thing1()).thing2()).thing3()
If you want to call thing1.thing2.thing3() you should format it like this:
function thing1(){
this.thing2 = {
thing3: function(){
alert();
}
}
}
var foo = new thing1();
foo.thing2.thing3()
Related
I can't figure out how to chain methods within same namespace (I do not want to create a class but rather call it directly):
var namespace = {
one: function(args) {
// do something
},
two: function() {
// do something in addition
}
}
// call both
namespace.one(true).two();
You need to return namespace or this.
var namespace = {
one: function(args) {
// do something
console.log('one');
return this;
},
two: function() {
// do something in addition
console.log('two');
return this;
}
}
// call both
namespace.one(true).two();
You need to return a refernce to the namespace object to chain it.
var namespace = {
one: function (args) {
// Do something
return this;
},
two: function () {
// Do something
return this;
}
}
I am new to IIFE and trying to implement namespace in JavaScript on a Siungleton JavaScript class:
I have a JavaScript class (say main class):
var myIIFE = (function () {
var x = null;
//constructor function
var myIIFE = function() {
var a = new IIFE.InsideIIFE(); //says not a constructor
}
myIIFE.prototype = {
//some methods
}
function createIstance() {
return new myIIFE();
}
return {
getInstance: function() {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
Then I have another JavaScript namespaced class:
myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
I want to create an object of myIIFE.InsideIIFE in myIIFE, and this is throwing me an error:
myIIFE.InsideIIFE is not a constructor
Am I doing something wrong? Or if this is a correct approach then what changes I should make.
I tried using new this.InsideIIFE() and just InsideIIFE, but non of them worked.
edit:
From my analysis, I understand that myIIFE (the parent) is an object as it return an object at:
return {
getInstance: function() {
//method body
}
}
There are many issues with this code, let's try to run it in our heads, from the start:
var myIIFE = (function () {
....
})();
This results in myIIFE being an object, to be precise, this object:
{
getInstance: function() {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
}
So, then I assume, you do
myIIFE.getInstance()
Which tries to return new myIIFE();
It runs into myIIFE() and tries to do this:
new IIFE.InsideIIFE();
I assume you meant to write
new myIIFE.InsideIIFE();
because IIFE is not defined it anywhere in the code you provided.
Let's see what is myIIFE.insideIIFE
var myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
First of all you start with var, which is wrong, because myIIFE is already defined and you are just adding a new property to it. so it should be simply
myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
and it should work.
In general, it seems by your code, like you have not grasped the whole "constructor function" concept very well. I would suggest you take look at the following links, they should help.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
this.slideUpComm = function (){
$("#Day-events-content p").addClass("hidden").slideUp("fast");
}
this.showhideEvents = function() {
$("#Day-events-content").on("click", ".eventsToggle", function() {
var obj = $(this).next();
if ($(obj).hasClass("hidden")) {
slideUpComm();
$(obj).removeClass("hidden").slideDown();
} else {
$(obj).addClass("hidden").slideUp();
}
});
}
I would like to use slideUpComm as function that I include on different events but console return Uncaught ReferenceError: slideUpComm is not defined.
How I should pass function to function ? Should I use callback?
function dateObj() {
this.d = new Date();
this.day = this.d.getDate();
this.numDay = this.d.getDay();
this.month = parseInt(this.d.getMonth());
this.year = this.d.getFullYear();
this.slideUpComm = function (){
}
this.showhideEvents = function() {
});
}
}
My Object look like above.
The problem is slideUpComm is a member of an object... so you need to use the object reference to invoke the method
//create a closure varaible to hold the reference to the instance
var self = this;
this.slideUpComm = function (){
$("#Day-events-content p").addClass("hidden").slideUp("fast");
}
this.showhideEvents = function() {
$("#Day-events-content").on("click", ".eventsToggle", function() {
var obj = $(this).next();
if ($(obj).hasClass("hidden")) {
//slideUpComm is a instance property so access it using the instance
self.slideUpComm();
$(obj).removeClass("hidden").slideDown();
} else {
$(obj).addClass("hidden").slideUp();
}
});
}
slideUpComm is a function of dateObj, you can not directly invoke the function. So to invoke a function you need to create an instance of function/object
var a = new dataObj();
then you can invoke the function using
a.slideUpComm()
Could this not be reduced to:
$("<object>").slideToggle();
?
When defining a class in Javascript, how can I call one method from another one?
exports.myClass = function () {
this.init = function() {
myInternalMethod();
}
this.myInternalMethod = function() {
//Do something
}
}
The code above gives me the following error when executing it:
ReferenceError: myInternalMethod is not defined
I also tried this.myInternalMethod and self.myInternalMethod, but both lead to errors.
What's the right way to do this?
I have created this fiddle http://jsfiddle.net/VFKkC/ Here you can call myInternalMedod()
var myClass = function () {
this.init = function() {
this.myInternalMethod();
}
this.myInternalMethod = function() {
console.log("internal");
}
}
var c = new myClass();
c.init();
this.myInternalMethod() does seem to work, though:
var exports = {};
exports.myClass = function () {
this.init = function() {
this.myInternalMethod();
}
this.myInternalMethod = function() {
//Do something
}
}
var x = new exports.myClass();
x.init();
Is it a private member?
exports.myClass = function () {
this.init = function() {
myInternalMethod();
}
function myInternalMethod() {
//Do something
}
}
Lets say I have this class:
function classA(n){
this.name = n
}
classA.prototype.getName = function(){
return this.name
}
var x = new classA('john')
console.log(x.getName())
My question is: can I group multiple methods inside a namespace? So I would like to do that:
var x = new classA('john')
console.log(x.CONSTANT.getName())
So I would like to call some methods as x.someMethod() and others as x.CONSTANT.otherMethod()
PS: I'm looking for a cross-browser method. Bind is not working in Safari and IE9.
You can do it, for example, via bind. Google es5 shim for implementation of bind in browsers, which don't support it natively.
function MyClass(name) {
this.name = name;
this.CONSTANT.otherMethod = this.CONSTANT.otherMethod.bind(this);
}
MyClass.prototype.CONSTANT = {
otherMethod: function() {
alert(this.name);
}
};
As far as I know a constant is just a property and it can't contain methods, you need to separate your objects and use methods to have the same effect:
function A (id) {
this.id = id;
this.showId = function () { return this.id; }
};
function B (a) {
this.a = a;
this.getA = function () { return this.a; }
}
var a = new A(12);
var b = new B(a);
b.getA().showId();
edit:
You can use a literal object as follow
function B (id) {
this.id = id;
this.CONSTANT = { otherMethod: function () { alert("..."); } };
someMethod = function () { return this.id; }
}
but the literal CONSTANT object can't access B-object methods,
Consider the #kirilloid post to round this.
You can, but you have to be careful because it won't act like you think it will. The this for the method will be the namespace, not the root object.
For example, in x.CONSTANT.getName(), the this object will be x.CONSTANT, and not x.
Here's some sample code which kinda does what you ask (or in jsfiddle):
function MyClass() {}
MyClass.prototype.CONSTANT = {
getName: function() {
alert('Foo');
}
};
var c = new MyClass();
c.CONSTANT.getName();
To make sure the this is right, you need to do much more.
You can use getters/setters (read this article) to achieve this. For example you may define it like this:
classA.prototype.__defineGetter__('CONSTANT', function() {
var that = this;
return {
getName: function() {
return that.name;
}
};
});
Note that holding reference to the object. It will work now
x = new classA('test');
x.CONSTANT.getName();
// result - test