I originally had code like that below, where I had nothing in the global namespace and I was able to call functions in obj2 from obj1 and vice versa. And all was well.
(function() {
var obj1 = {
obj1_f1 : function() {
},
obj1_f2 : function() {
obj2.obj2_f1();
}
};
var obj2 = {
obj2_f1 : function() {
obj1.obj1_f1();
},
obj2_f2 : function() {
}
};
$(document).ready(function () {
obj1_f1();
});
})();
But now I need to call a function in the obj1 object from the global context, so I have to introduce a global object:
var com_mycompany_make_sure_unique = new function() {
// use 'this.' so that obj1 is not in the global namespace
this.obj1 = {
obj1_f1 : function() {
},
obj1_f2 : function() {
com_mycompany_make_sure_unique.obj2.obj2_f2();
}
};
this.obj2 = {
obj2_f1 : function() {
com_mycompany_make_sure_unique.obj1.obj1_f1();
},
obj2_f2 : function() {
}
};
$(document).ready(function () {
com_mycompany_make_sure_unique.obj1.obj1_f1();
});
};
but I'm not overly happy with that - I have to prepend all function calls with my global object name when calling functions across obj1 and obj2. I think I'm missing a trick.
Thanks for any help,
Paul
You can do this (see comments):
var com_mycompany_make_sure_unique = function() {
// Continue using variables as you were before
var obj1 = {
obj1_f1 : function() {
},
obj1_f2 : function() {
obj2.obj2_f2();
}
};
var obj2 = {
obj2_f1 : function() {
obj1.obj1_f1();
},
obj2_f2 : function() {
}
};
$(document).ready(function () {
obj1.obj1_f1();
});
// Return an object that can be used via the `com_mycompany_make_sure_unique` variable
return {
obj1: obj1,
obj2: obj2
};
}();
This is sometimes called the "revealing module pattern" because everything inside the outer anonymous scoping function is private, and then you "reveal" the parts you want to reveal by putting them on the object you return. If you only needed to expose obj1, for instance, and not obj2, you could do that:
return {
obj1: obj1
};
My question, though, is why do you need to call functions from the global context? With modern event handling and Asynchronous Module Definition loaders like RequireJS, the only global you should really require (ugh) is the AMD function(s).
Side note: I replaced your var ... = new function() { ... }; with var ... = function() { ... }(); There's no need to use new here, and doing so can tend to confuse people (and gives the resulting object an extra prototype it doesn't need). But you could use your original form if you like, just change the end to
this.obj1 = obj1;
this.obj2 = obj2;
...rather than returning an object.
Related
var obj = {
someFunc : function() {
console.log("Hello");
console.log(this);
var obj1 = {
someFunc1 : function() {
console.log("Hi");
}
};
}
};
obj.someFunc();
obj.obj1.someFunc1();
I have just created an object. And inside an object, a method, and then a new object and obj1. I am just trying to check 'this' keyword. But, it seem to me it's grammatical error in js. That is not possible. Right? But, why?
var obj = {
someFunc : function() {
console.log("Hello");
console.log(this);
return {
someFunc1 : function() {
console.log("Hi");
}
};
}
};
obj.someFunc().someFunc1();
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
…
};
…
I am writing some JavaScript code. I am a little confused about this keyword. How do I access logger variable in the dataReceivedHandler function?
MyClass: {
logger: null,
init: function() {
logger = LogFactory.getLogger();
},
loadData: function() {
var dataReceivedHandler = function() {
// how to access the logger variable here?
}
// more stuff
}
};
You can do something like this inside the loadData function to access your object...
MyClass: {
logger: null,
init: function() {
this.logger = LogFactory.getLogger();
},
loadData: function() {
var self = this;
var dataReceivedHandler = function() {
// how to access the logger variable here?
self.logger.log('something');
}
// more stuff
}
};
Assuming loadData is called like so:
MyClass.loadData();
then:
loadData: function() {
var self = this;
var dataReceivedHandler = function() {
self.logger ...
}
// more stuff
}
Because dataReceivedHandler is an anonymous function this will refer to the window object on the global scope. I think of two way you can bypass that.
a) Create a variable inside loadData to hold it's context then use it inside dataReceivedHandler as such:
loadData: function() {
var self = this;
var dataReceivedHandler = function() {
console.log(self.logger);
}
// more stuff
}
b) Change the context of your anonymous function using apply or call.
loadData: function() {
var dataReceivedHandler = function() {
console.log(this.logger);
}
// more stuff
dataReceivedHandler.call(this); // by passing this as the first argument we make sure the context of the excuted function is our current scope's this
}
I prefer option B due to performance and memory usage optimizations, but both would work just fine.
var Foo = (function () {
var foo = function() { };
var privateMethod = function(){ };
foo.prototype = {
init: function() {
console.log(this.privateMethod); //undefined
}
};
return foo;
})();
I know that I can access privateMethod directly without using the this pointer. But since I come from the c# world, I would like to use it for readability purposes.
Is there any way to reference my "private methods" using a pointer?
You can't. You can only use this to refer to "public" methods. If you really want to use a something.method notation, you could use:
var Foo = (function () {
var foo = function() { };
var private = {
privateMethod : function(){ };
}
foo.prototype = {
init: function() {
console.log(private.privateMethod);
}
};
return foo;
})();
privateMethod is not specific to each instance of foo. Just reference it without the this. qualifier—although you probably want to log the results of a function call, not the function itself:
console.log(privateMethod());
test.html
<script src="jsv/test1.js"></script>
<script src="jsv3/test2.js"></script>
test1.js:
(function ($) {
var settings = {
taphold_threshold: 750,
hold_timer: null,
tap_timer: null
};)
};
test2.js:
var Navigation = {
init: function () {
self = this;
$('#button').live(tapMode, function () {
alert(settings[taphold_threshold]);
});
}
}
I would like to get the value of settings : taphold_threshold, but it seems i can not get the value by simply alert it. test2.js is the caller and test1.js is callee. It should be some scope problem. How to get the value (750) ? Thanks
The problem is indeed scope - settings will be in an anonymous scope which is not available outside of the closure.
You could change test1 to have a sort of "namespace" - say something like global (although I would personally use a more descriptive name than global).
var global = {};
global.settings = {
taphold_threshold: 750,
hold_timer: null,
tap_timer: null
};
The from test2 you can use:
alert(global.settings.taphold_threshold);
Your code hints at a namespace pattern but falls slightly short.
You might like to consider something like this
var TAP = (function($) {//functional namespace
var settings = {
hold_threshold: 750,
hold_timer: null,
timer: null
};
var setSettings = function(s) {
settings = $.extend(settings, s);
};
var getSettings = function() {
return settings;
};
return {
set: setSettings,
get: getSettings
};
})(jQuery);
Thus, TAP has private member settings and public members set() and get(). You will see that further private and public members are easily added.
Now you have a mechanism to both set and get TAP settings from anywhere that TAP is within scope:
TAP.set({hold_threshold: 500});
var Navigation = {
init: function () {
self = this;
$('#button').live(tapMode, function () {
alert(settings[TAP.get().hold_threshold]);
});
}
}
With TAP as a member in the global namespace, it's public methods are available in all scopes.
More typically, you will use the MODULE pattern, which puts just one PROJECT member into the global namespace, containing any number of MODULES, each containing any number of functional NAMESPACES, for example :
var MYPROJECT = {};//global
MYPROJECT.MODULE1 = {};
MYPROJECT.MODULE1.TAP= (function($) {
var settings = {
hold_threshold: 750,
hold_timer: null,
timer: null
};
var setSettings = function(s) {
settings = $.extend(settings, s);
};
var getSettings = function() {
return settings;
};
return {
set: setSettings,
get: getSettings
};
})(jQuery);
By convention, MYPROJECT, its MODULES and its functional NAMESPACES are capitalized.
settings is nested within a closure and it cannot be accessed from the outside. One solution is to remove the closure so that it becomes a global object. Another solution is to assign it to the window object, same as making the variable global but this works from inside closures. Here is an example:
(function ($) {
window.my_namespace = window.my_namespace || {};
window.my_namespace.settings = {
taphold_threshold: 750,
hold_timer: null,
tap_timer: null
};
});
var Navigation = {
init: function () {
self = this;
$('#button').live(tapMode, function () {
alert(my_namespace.settings[taphold_threshold]);
});
}
};
Since var settings is defined in test1.js inside a closure, hence the problem exists.
You might want to define the settings variable as
window.settings = ...
OR
window['settings'] = ...
So now settings would be defined as a global variable.