Javascript module pattern, scope and "this" - javascript

I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like
var myLib = (function() {
}())
However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:
Why does the following example alert DOMWindow, rather than the myLib object?
http://jsfiddle.net/slavo/xNJtW/1/
It would be great if you can explain what "this" refers to in all of the methods in that example and why.

Inside any function declared (anywhere) and invoked as follows this will be window object
function anyFunc(){
alert(this); // window object
}
anyFunc();
var anyFunc2 = function(){
alert(this); // window object
}
anyFunc2();
If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods
One
module = (function () {
var privateFunc = function() {
alert(this);
}
var myObject = {
publicMethod: function() {
privateFunc.apply(this); // or privateFunc.call(this);
}
};
return myObject;
}());
module.publicMethod();
Two
module = (function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(_this);
}
var myObject = {
publicMethod: function() {
privateFunc();
}
};
_this = myObject;
return myObject;
}());
module.publicMethod();
These are solutions to your issue. I would recommend using prototype based objects.
EDIT:
You can use the first method.
In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function
var privateFunc = function() {
alert(myObject);
}
The real scenario were you can use a proxy for this is shown below. You can use call also.
Module = function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(this + "," + _this);
}
this.publicMethod = function() {
privateFunc(); // alerts [object Window],[object Object]
privateFunc.call(this); // alerts [object Object],[object Object]
}
_this = this;
return this;
};
var module = new Module();
module.publicMethod();

You need to explicitly state that myPrivateMethod is a member of myLib:
function MyLib ()
{
this._myPrivateField = "private";
this._myPrivateMEthod = function ()
{
alert(this); // Alerts MyLib function;
}
}
var libObject = new MyLib();
Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!
A better way to do the above is like so:
function MyLib(instanceName)
{
this.name = instanceName;
}
MyLib.prototype.myPrivateFunction()
{
alert(this);
}
To call your method after that:
var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.

The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.

In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.
edit: clarification

Related

Calling private js function from prototype

I've been reading SO posts all day and I haven't come up with anything that is working for me.
I have a JS object
function MyObject(a,b){
this.member_a = a;
this.member_b = b;
function operation1(){
$('#someDiv1').text(this.a);
}
function operation2(){
$('#someDiv1').text(this.b);
}
MyObject.prototype.PublicFunction1 = function(){
//There is an ajax call here
//success
operation1();
//failure
operation2();
}
}
Roughly like that. That's the pattern I'm at right now. It's in an external JS file. My page creates a MyObject(a,b) and the breakpoints show that member_a and member_b are both initialized correctly. After some other magic happens from my page callsMyObject.PublicFunction1();, the ajax executes and I enter operation1() or operation2() but when I am inside of those member_a and member_b are both undefined and I don't understand why. I'm losing the scope or something. I've had the private function and the prototypes outside the object body declaration, combinations of both. How can I call a private function from an object's prototype to work on the object's data?
I've also tried
ClassBody{
vars
private function
}
prototype{
private function call
}
and have been reading this
operation1 and operation2 do not have a context and are thus executed in the global context (where this == window).
If you want to give them a context, but keep them private, then use apply:
operation1.apply(this);
operation2.apply(this);
Further reading on the apply method https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
EDIT
#FelixKing is correct - your code should more appropriately be written like this (using the Module Pattern):
//encapsulating scope
var MyObject = (function() {
function operation1(){
$('#someDiv1').text(this.a);
}
function operation2(){
$('#someDiv1').text(this.b);
}
var MyObject = function(a,b) {
this.member_a = a;
this.member_b = b;
};
MyObject.prototype.PublicFunction1 = function(){
//There is an ajax call here
//success
operation1.apply(this);
//failure
operation2.apply(this);
}
return MyObject;
}());
I have built a tool to allow you to put private methods onto the prototype chain. This way you'll save on memory allocation when creating multiple instances.
https://github.com/TremayneChrist/ProtectJS
Example:
var MyObject = (function () {
// Create the object
function MyObject() {}
// Add methods to the prototype
MyObject.prototype = {
// This is our public method
public: function () {
console.log('PUBLIC method has been called');
},
// This is our private method, using (_)
_private: function () {
console.log('PRIVATE method has been called');
}
}
return protect(MyObject);
})();
// Create an instance of the object
var mo = new MyObject();
// Call its methods
mo.public(); // Pass
mo._private(); // Fail

Unable to access the object using `this`. `this` points to `window` object

I have this Javascript constructor-
function TestEngine() {
this.id='Foo';
}
TestEngine.prototype.fooBar = function() {
this.id='bar';
return true;
}
TestEngine.prototype.start = function() {
this.fooBar();
}
TestEngine.prototype.startMethod = function() {
inter = setInterval(this.start, 200);
}
var test = new TestEngine();
test.startMethod();
Gives me this error -
Uncaught TypeError: Object [object global] has no method 'fooBar'
I tried console.log and found out that when I call this.start from within setInterval, this points to the window object. Why is this so?
The this pointer can point to one of many things depending upon the context:
In constructor functions (function calls preceded by new) this points to the newly created instance of the constructor.
When a function is called as a method of an object (e.g. obj.funct()) then the this pointer inside the function points to the object.
You can explicitly set what this points to by using call, apply or bind.
If none of the above then the this pointer points to the global object by default. In browsers this is the window object.
In your case you're calling this.start inside setInterval. Now consider this dummy implementation of setInterval:
function setInterval(funct, delay) {
// native code
}
It's important to understand that start is not being called as this.start. It's being called as funct. It's like doing something like this:
var funct = this.start;
funct();
Now both these functions would normally execute the same, but there's one tiny problem - the this pointer points to the global object in the second case while it points to the current this in the first.
An important distinction to make is that we're talking about the this pointer inside start. Consider:
this.start(); // this inside start points to this
var funct = this.start;
funct(); // this inside funct (start) point to window
This is not a bug. This is the way JavaScript works. When you call a function as a method of an object (see my second point above) the this pointer inside the function points to that object.
In the second case since funct is not being called as a method of an object the fourth rule is applied by default. Hence this points to window.
You can solve this problem by binding start to the current this pointer and then passing it to setInterval as follows:
setInterval(this.start.bind(this), 200);
That's it. Hope this explanation helped you understand a little bit more about the awesomeness of JavaScript.
Here is a neat way to do OOP with javascript:
//Global Namespace:
var MyNamespace = MyNamespace || {};
//Classes:
MyNamespace.MyObject = function () {
this.PublicVar = 'public'; //Public variable
var _privatVar = 'private'; //Private variable
//Public methods:
this.PublicMethod = function () {
}
//Private methods:
function PrivateMethod() {
}
}
//USAGE EXAMPLE:
var myObj = new MyNamespace.MyObject();
myObj.PublicMethod();
This way you encapsulate your methods and variables into a namespace/class to make it much easier use and maintain.
Therefore you could write your code like this:
var MyNamespace = MyNamespace || {};
//Class: TestEngine
MyNamespace.TestEngine = function () {
this.ID = null;
var _inter = null;
//Public methods:
this.StartMethod = function (id) {
this.ID = id;
_inter = setInterval(Start, 1000);
}
//Private methods:
function Start() {
FooBar();
console.log(this.ID);
}
function FooBar() {
this.ID = 'bar';
return true;
}
}
//USAGE EXAMPLE:
var testEngine = new MyNamespace.TestEngine();
testEngine.StartMethod('Foo');
console.log(testEngine.ID);
Initially, the ID is set to 'Foo'
After 1 second the ID is set to 'bar'
Notice all variables and methods are encapsulated inside the TestEngine class.
Try this:
function TestEngine() {
this.id='Foo';
}
TestEngine.prototype.fooBar = function() {
this.id='bar';
return true;
}
TestEngine.prototype.start = function() {
this.fooBar();
}
TestEngine.prototype.startMethod = function() {
var self = this;
var inter = setInterval(function() {
self.start();
}, 200);
}
var test = new TestEngine();
test.startMethod();
setInterval calls start function with window context. It means when start gets executed, this inside start function points to window object. And window object don't have any method called fooBar & you get the error.
Anonymous function approach:
It is a good practice to pass anonymous function to setInterval and call your function from it. This will be useful if your function makes use of this.
What I did is, created a temp variable self & assigned this to it when it is pointing your TestEngine instance & calling self.start() function with it.
Now inside start function, this will be pointing to your testInstance & everything will work as expected.
Bind approach:
Bind will make your life easier & also increase readability of your code.
TestEngine.prototype.startMethod = function() {
setInterval(this.start.bind(this), 200);
}

JS - Scope chain

I thought scope chain would make the first "test = new test();" work, but it doesn't. why?
var tool = new Tool();
tool.init();
function Tool(){
var test;
function init(){
//does not work, undefined
test = new Test();
//does work
this.test=new Test();
console.log(test);
}
}
function Test(){
}
EDIT: by not working i mean, it says that test is 'undefined'
It's simple. Your Tool instance does not have a init method. The init function in your code is merely a local function of the Tool constructor. Tool instances do not inherit such functions.
If you want your Tool instances to have a init method, you can:
assign it as a method inside the constructor:
function Tool () {
this.init = function () { ... };
}
or assign it to Tool.prototype (outside of the constructor!):
Tool.prototype.init = function () { ... };
The second option performs better, since all instances share the same init function. (In the first option, each instance gets its own init function which is created during the constructor call.)
Are you trying to access test in the scope of Tool, or on the object returned by it? They are two different variables. I've labeled them A and B:
var tool = new Tool();
function Tool(){
var testA; // Private
this.init = function(){
testA = 1;
this.testB = 9; // Public
}
this.getTestA = function(){ // Public method to access the private testA
return testA;
}
}
tool.init();
console.log( tool.getTestA() ); // 1
console.log( tool.testB ); // 9
testA is known as a Private variable, only accessible through Tool's methods, while testB is public.
Does this cover what you're looking for?
By the way, if you're making a lot of instances of Tool, remember to use Tool's prototype to define the functions instead, so your code is more memory efficient, like so:
function Tool(){
var testA;
}
Tool.prototype.init = function(){
testA = 1;
this.testB = 9;
}
Tool.prototype.getTestA = function(){ return testA; }

Using this.prototype in a class definition?

I have a class definition that is part of a class definition.
var someObject = {
someClass: function() {
this.someMethod = function() {
alert('hello');
};
}
}
I have been told that I should use prototype to add methods, as it then only needs to be created once for all instances of the object. The problem is that it seems I need to add the prototyped method after the constructor function is defined, like this...
var someObject = {
someClass: function() {
}
}
someObject.someClass.prototype.someMethod = function() {
alert('hello');
};
Ideally however I would like to define the prototyped methods within the constructor function like this...
var someObject = {
someClass: function() {
this.prototype.someMethod = function() {
alert('hello');
};
}
}
This causes an error however stating that prototype is null or not an object. Is there a way to accomplish what I would like, or is this not possible?
You can make it work by using arguments.callee or - if you don't overwrite the .prototype property of your constructor function - this.constructor instead of plain this, ie
var someObject = {
someClass: function() {
// this.constructor.prototype should work as well
arguments.callee.prototype.someMethod = function() {
alert('hello');
};
}
};
However, putting the function expression back into the constructor defeats the whole purpose of the exercise - it doesn't matter that you store the reference to the function object in the prototype instead of the instance, you're still creating a new one on each constructor invocation!
One possible solution is using an anonymous constructor instead of an object literal, which gets you an additional scope for free:
var someObject = new (function() {
function someClass() {}
someClass.prototype.someMethod = function() {
alert('hello');
};
this.someClass = someClass;
});
See Paul's answer for an equivalent solution using object literals and a wrapper function, which might be more familiar.
Yes, you can't access prototype property inside the constructor of the class, but you can do a little bit different code notation, so probably it helps to you:
var someObject = {
someClass: (function wrapper() {
var ctor = function(){};
ctor.prototype.someMethod = function(){
alert('hello');
};
return ctor;
})()
}

Initializing singleton javascript objects using the new operator?

In javascript, what is the difference between:
var singleton = function(){ ... }
and
var singleton = new function(){ ... }
?
Declaring priviliged functions as described by crockford (http://www.crockford.com/javascript/private.html) only works using the latter.
The difference is mainly that in your second example, you are using the Function Expression as a Constructor, the new operator will cause the function to be automatically executed, and the this value inside that function will refer to a newly created object.
If you don't return anything (or you don't return a non-primitive value) from that function, the this value will be returned and assigned to your singleton variable.
Privileged methods can also be used in your second example, a common pattern is use an immediately invoked function expression, creating a closure where the private members are accessible, then you can return an object that contains your public API, e.g.:
var singleton = (function () {
var privateVar = 1;
function privateMethod () {/*...*/}
return { // public API
publicMethod: function () {
// private members are available here
}
};
})();
I think that a privileged function as described by crockford would look like this:
function Test() {
this.privileged = function() {
alert('apple');
}
function anonymous() {
alert('hello');
}
anonymous();
}
t = new Test; // hello
t.privileged(); // apple
// unlike the anonymous function, the privileged function can be accessed and
// modified after its declaration
t.privileged = function() {
alert('orange');
}
t.privileged(); // orange

Categories

Resources