Im working in a sub-module pattern code. Want to create sub-modules with objects literals, the problem is this for the objects inside the sub-module is MODULE and not my object literal. Any idea?
var MODULE.sub = (function () {
var myObject = {
key: value,
method: function () {
this.key // this = MODULE and not MyObject... :(
}
};
return myObject.method;
}(MODULE));
This works for me:
var MODULE = MODULE || {};
MODULE.sub = (function () {
return {
myObject : {
key : 10,
method : function() {
console.log(this.key);
}
}
};
})();
Then call it:
MODULE.sub.myObject.method();
You were only returning the method and not the key so "this" would be undefined. You could keep it private if you want like this and pass key in as a var:
var MODULE = MODULE || {};
MODULE.sub = (function () {
var key = 10,
return {
myObject : {
method : function() {
console.log(key);
}
}
};
})();
Solved... just return a function in MODULE.sub calling the public method. I don't know if is the best approach
var MODULE.sub = (function () {
var myObject = {
key: value,
method: function () {
this.key // this = myObject :)
}
};
return function () {
myObject.method();
}
}(MODULE));
The this keywords value depends on how the function is called. So if you assign that function to MODULE.sub, and then invoke it as MODULE.sub(…), then this will point to the MODULE of course. If you had invoked it as myObject.method(…), then this would point to that object.
So you either should expose the whole myObject (like in #BingeBoys answer), or do not export that function and expect it to be a method of myObject. Instead, you could use a bound one:
return myObject.method.bind(myObject);
or the explicit equivalent of that
return function() {
return myObject.method();
};
or you would not put the function as method on that object at all:
…
var myObject = {
key: value,
};
return function() {
myObject.key // no `this` here
…
};
…
Related
I've an object looks like this:
var obj ={
property : '',
myfunction1 : function(parameter){
//do stuff here
}
}
I need to set some private properties and functions, which can not be accessed/seen from outside of the object. It is not working with
var property:, or var myFunction1
Next question is, if I call a function within or outside the object, I always have to do this with obj.myfunction(). I would like to asign "this" to a variable. Like self : this. and call inside the object my functions and variables with self.property and self.myfunction.
How? :)
There are many ways to do this. In short: If dou define a function inside another function, your inner function will be private, as long as you will not provide any reference to if.
(function obj(){
var privateMethod = function() {};
var publicMethod = function() {
privateMethod();
...
};
return {
pubMethod: publicMethod
}
}());
var obj = (function() {
var privateProperty;
var privateFunction = function(value) {
if (value === void 0) {
return privateProperty;
} else {
privateProperty = value;
}
};
var publicMethod = function(value) {
return privateFunction(value);
}
return {
getPrivateProperty: function() {
return privateFunction();
},
setPrivateProperty: function(value) {
privateFunction(value);
}
}
})();
obj.setPrivateProperty(3);
console.log(obj.getPrivateProperty());
// => 3
console.log(obj.privateProperty);
// => undefined
obj.privateFunction();
// => TypeError: undefined is not a function
Use closures. JavaScript has function scope, so you have to use a function.
var obj = function () {
var privateVariable = "test";
function privateFunction() {
return privateVariable;
}
return {
publicFunction: function() { return privateFunction(); }
};
}();
I have the below code:
filtersManager = (function ($) {
var that = this;
function configure() {
// some work
return that;
};
function process() {
// some work
return that;
}
return {
// public functions
configure: configure,
process: process
};
}(jQuery));
but when it's called using the below it fails:
filtersManager.configure().process();
Error: Object doesn't support property or method 'process'
whereas the below works:
filtersManager.configure();
filtersManager.process();
You are returning the wrong thing (this in a plain function invocation is the global object). You want to return the object that you originally created, which I will call the interface.
filtersManager = (function ($) {
var interface = {
// public functions
configure: configure,
process: process
};
function configure() {
// some work
return interface;
};
function process() {
// some work
return interface;
}
return interface;
}(jQuery));
If you're wondering why I can reference the functions defined below, it's due to hoisting.
Immediate function is executed in global object (window) context. Try something similar to this:
filtersManager = (function ($) {
var that = {};
that.configure = function() {
// some work
return that;
};
that.process = function() {
// some work
return that;
}
return that;
}(jQuery));
UPD. Based on comments
Constructor pattern seems to fit your need better:
var FiltersManager = (function($) {
function FiltersManager() {}
FiltersManager.prototype = {
configure: function() {
console.log('configure');
return this;
},
process: function() {
console.log('process');
return this;
}
}
return FiltersManager;
}(jQuery));
new FiltersManager().configure().process();
As to continue what others have said , I think you confused with the function constructor syntax which would work , similar to what you've said ;
var G=function g()
{
this.configure =function (){return this;}
this.process =function (){return this;}
};
var _= new G();
console.log(_.configure().process())
If you wanted to re-use the functions on other objects too, you could do it like this
filtersManager = function ($) {
function configure() {
// some work
return this;
};
function process() {
// some work
return this;
}
return {
// public functions
configure: configure,
process: process
};
}(jQuery);
(OTOH, if you wanted to create aliases to them, you would then have to bind them to the object)
Or if configure and process are quite short, simple functions :
filtersManager = (function ($) {
return {
// public functions
configure: function () {
// some work
return this;
},
process: function () {
// some work
return this;
}
};
}(jQuery));
In JavaScript I am looking for a way to use bind() on an anonymous and async function.
Example:
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
I got this working by making the functions non-anonymous, but I think it makes my code look ugly. Especially after having 4 different anonymous functions in a row.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
function _load(object) {
this.object = object;
}
var _loadThis = _load.bind(this);
var query = new Parse.Query("SomeObject");
query.get(id).then(_loadThis);
}
};
Is there a better way?
Well it's not necessarily "better", but you can call .bind() directly after the closing brace of your function instantiation expression:
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
}.bind(this));
A function instantiation expression gives you a function object reference, so putting a . after it and calling bind makes sense. What gets passed to the .then function, therefore, is the return value from the call to .bind.
This syntax is not correct:
exports.foo.prototype = {
load = function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
The prototype is an object who's properties are defined as load: function() {}, not load = function() {}.
It should be:
exports.foo.prototype = {
load: function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
A simple way to do it is to declare a variable to the correct 'this' and use closuers to keep a reference to it.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var self = this;
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
self.object = object; // this is the wrong this
});
}
};
I spent the better part of the day reading about the module pattern and its 'this' scope. Eventually I found a work-around for my problem, although with a feeling there's a better way of doing things.
The actual code is >200 lines, but I've boiled it down to the following:
objA has a method (publicA) that objB wants invoke by callback. The detail that complicates things is that publicA needs help from publicA_helper to do its job. (http://jsfiddle.net/qwNb6/2/)
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + this.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
var objB = function () {
return {
callback: function (callback) {
callback();
}
}
}();
objA.publicA(); // privateA is found
objB.callback(objA.publicA); // TypeError: Object [object global]
Fair enough – I've grasped that the caller's context tends to influence the value of 'this'. So I add measures to retain 'this' inside objA, of which none seems to work. I've tried the
var objA = (){}.call({}) thingy, setting var self = this; (calling self.publicA_helper() accordingly). No luck.
Eventually, I added a private variable var self;, along with a public method:
init: function() {self = this;},
...and by making sure I call objA.init(); before passing objA.publicA to objB.callback, things actually work.
I cannot stress the immensity of the feeling that there's a better way of doing this. What am I missing?
The generalized solution is extremely simple.
Write all the module's methods as private, then expose those that need to be public.
I write all my modules this way :
var objA = function () {
var privateA = "found";
var A = function () {
console.log("privateA is " + A_helper());
},
var A_helper = function () {
return privateA;
}
return {
publicA: A
//A_helper need not be exposed
};
}();
Thus, all methods are in the same scope, each one having direct access to all other methods in the same module, and the ambiguous this prefix is avoided.
objB.callback(objA.publicA); will now work as expected.
See fiddle
I've tried the var objA = (){}.call({}) thingy,
How? You want to use call on the callback that you want to invoke with a custom this, not on your module closure. It should be
var objB = {
callback: function (callback, context) {
callback.call(context);
}
};
objB.callback(objA.publicA, objA);
I've tried setting var self = this;
The self variable is supposed to be in a closure and point to the object on the methods are stored. That is only this when your module IEFE would be invoked on your module - it's not. Or if it was a constructor - it's not. You could change that with call as above:
var objA = function () {
var privateA = "found",
self = this;
this.publicA = function () {
console.log("privateA is " + self.publicA_helper());
};
this.publicA_helper = function () {
return privateA;
};
return this;
}.call({});
But that's ugly. In your case, the self variable simply needs to point to the object literal which you're returning as your module:
var objA = function () {
var privateA = "found",
self;
return self = {
publicA: function () {
console.log("privateA is " + self.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
Btw, since you're creating a singleton you don't need an explicit self, you could just reference the variable that contains your module (as long as that doesn't change):
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + objA.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
Another method would be to simply make all functions private and then expose some of them - by referencing them local-scoped you will have no troubles.
var objA = function () {
var privateA = "found";
function publicA() {
console.log("privateA is " + helper());
}
function helper() {
return privateA;
}
return self = {
publicA: publicA,
publicA_helper: helper // remove that line if you don't need to expose it
};
}();
The reason is that the context is getting changed when you are invoking the callback. Not a generalized solution, but shows that the code works by specifying the context while invoking callback.
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + this.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
var objB = function () {
return {
callback: function (callback) {
callback.call(objA);
}
}
}();
objA.publicA(); // privateA is found
objB.callback(objA.publicA); // privateA is found
I'm trying to understand how to best use the JavaScript module pattern. My problem is that it seems there's no way to refer to the module from within itself, because this is set to the Window object.
I've got this simple test code:
var Test = function() {
var that = this;
return {
something: function() {
console.info(that);
}
}
}
var test1 = Test();
test1.something();
var test2 = Test();
test2.something();
Both test1 and test2 print a reference to the Window object instead of the module itself.
Any idea how to change it so that I have a valid this inside the module?
If you did
var test1 = new Test()
You could then do
test1.something();
An alternative module structure would be to do something like this:
var myModule = function () {
var obj = {};
obj.something = function () {
return console.log(obj);
};
obj.something2 = function () {
return console.log(obj === this); // true
};
return obj;
};
var test = myModule();
test.something();
test.something2();
Hope this helps
I think you're confusing the JavaScript module pattern with JavaScript constructor functions.
JavaScript constructor functions
If you write a function and call it with the new keyword in front of it, then that function is called as a constructor function.
It will automatically return a new object, that you can refer to within the constructor function using the this keyword.
var Test = function() {
var that = this;
this.something = function () {
console.info(that);
console.info(this);
};
}
var test1 = new Test();
test1.something();
You can return your own object instead, but you wouldn't normally do that in a constructor, you'd just use this instead:
var Test = function() {
var that = this;
return {
something: function () {
console.info(that);
console.info(this);
}
};
}
var test1 = new Test();
test1.something();
If you don't call it with the new keyword in front of it, then it's called like a regular function, meaning any references to this inside of it refer to the object of which the function is a property (which, in the absence of anything else, will be the global object, which in web browsers is window).
var geoff = {
Test: function () {
var that = this;
return {
something: function () {
console.info(that);
}
};
}
};
var test2 = geoff.Test();
var test3 = Test();
Note: with constructor functions, you'd normally define methods on their prototype object, so that the methods don't get unnecessarily redefined for each object you create using the constructor function:
var Test = function() {
this.else = "Something Else"
}
Test.prototype.something = function () {
console.info(this);
}
Test.prototype.somethingElse = function () {
console.info(this.else);
}
var test4 = new Test();
test1.somethingElse() // Logs "Something Else"
(Note that if you return your own object from the constructor function as we mentioned above, then you won't be able to access methods on the prototype object any more.)
Also note that each time you call a constructor function, it returns a new object. You can pass parameters into a constructor function (just like you can with any other function) and use them to customise the object returned:
var Test = function(else) {
this.else = else;
}
Test.prototype.somethingElse = function () {
console.info(this.else);
}
var test1 = new Test("Something else");
var test2 = new Test("Something else again");
test1.somethingElse(); // Logs "Something else"
test2.somethingElse(); // Logs "Something else again"
The problem you have is because this refers to an object, but Test() isn't an object; it's just a function. The object that owns Test() is the Window object (because Test is in the global scope), so therefore that's what you get back when you reference this from within Test().
You may want to try something like this:
var testObj = {
Test : function() {
var that = this;
return {
something: function() {
console.info(that);
}
}
}
}
Now you can call testObj.Test(); and you'll get a reference back to the testObj object.
Hope that clarifies things a bit.