Get "this" context in a JS "class" method function - javascript

I am trying to create a "class" in JS, a simplified structure of which is below:
http://codepen.io/Deka87/pen/WpqYRP?editors=0010
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', function() {
this.show();
}.bind(this));
};
Alert.prototype.show = function() {
setTimeout(function() {
console.log(this.message);
}, 50);
};
var alert = new Alert();
When you click on the document it should show you the this.message contents in console. However, it is now shown as undefined. I believe the problem is that this.messsage can't get the original this context because it is wrapper in another function (setTimeout in my case). Any help would be appreciated!

Here's what worked for me, you get your this.message by referencing self, which is the correct context you need.
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', function() {
this.show();
}.bind(this));
};
Alert.prototype.show = function() {
var self = this;
setTimeout(function() {
console.log(self.message);
}, 50);
};
var alert = new Alert();

You can use arrow functions which will preserve your this context.
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', () => {
this.show();
});
};
Alert.prototype.show = function () {
setTimeout(() => {
console.log(this.message);
}, 50);
};
var alert = new Alert();
Read more: https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Functions_and_function_scope/Arrow_functions.

Related

test new object instance (jasmine)

I have tests run by karma, in one of them I create new instance of object and call function where is used this. On normal browser this is reference to current instance but in test after console.log it I see:
Object{document: < !-- This is the execution context.
Loaded within the iframe. Reloaded before every execution run.
Why?
// createing the object
window.gr = window.gr || {};
gr.Notification = (function () {
function Notification(node, message) {
this.liveTime = 5000;
this.template = this.createTemplate(message);
this.node = null;
this.appendTo(node);
setTimeout(this.remove, this.liveTime);
}
Notification.prototype = {
createTemplate: function (message) {
var notification = document.createElement("div");
notification.className = "notification";
var _message = document.createTextNode(message);
notification.appendChild(_message);
return notification;
},
appendTo: function(node){
this.node = node.appendChild(this.template);
},
remove: function(){
console.log(this)
this.node.parentNode.removeChild(this.node);
}
};
return Notification;
})();
//test
beforeEach(function(){
Notification = gr.Notification;
jasmine.clock().install();
});
it("should remove notification after 5s", function(){
new Notification(document.body);
jasmine.clock().tick(5001);
expect(document.querySelectorAll(NOTIFICATION_SELECTOR).length).toEqual(0);
});
your this references to window, because you call setTimeout, which is method of window object, so this inside that method points to window,
you could do something like that:
function Notification(node, message) {
this.liveTime = 5000;
this.template = this.createTemplate(message);
this.node = null;
this.appendTo(node);
var self = this;
setTimeout(function() {
self.remove()
}, self.liveTime);
}

Javascript TypeError: this.init is not a function Error

This is my Javascript code
Html5Template_300x250 = function(config) {
this.config = config;
var self = this;
this.init();
Html5Template_300x250.prototype = {
// Function That Creates Element Var
d: function(id) {
return document.getElementById(id);
},
// Initialize DCO HTML5 template
init: function() {
alert("test1");
this.startAd();
},
startAd: function() {
alert("test2");
}
};
}
From the HTML file i am creating method like this
var sr_Config = {
bgColor:'#fff',
ctaText:'Learn More',
border: 'true'
};
var Html5Template = new Html5Template_300x250(sr_Config);
But i am getting Error
TypeError: this.init is not a function this.init();
I am not sure what is wrong here i have also tried self.init() but still it is not working.
I am new to javascript and learning OOPS in Javascript if anyone can tell me what i am doing wrong here that would be great. Thanks in advance
You need to assing the methods to the prototypes properties (at least thats how i do it). You also need to do so before you call the function (above).
Html5Template_300x250 = function(config) {
this.config = config;
var self = this;
Html5Template_300x250.prototype.d = function(id) {
return document.getElementById(id);
};
Html5Template_300x250.prototype.startAd = function() {
alert("test2");
};
// Initialize DCO HTML5 template
Html5Template_300x250.prototype.init = function() {
alert("test1");
this.startAd();
};
self.init();
}
Another way to do this w/o the prototype-stuff would be sth. like that:
Html5Template_300x250 = function(config) {
this.config = config;
var self = this;
this.d = function(id) {
return document.getElementById(id);
};
// and so on..
self.d('myid');
}
See this working fiddle with some sample code.
Further interesting reading on the topic OOP in JS is provided by JS-Guru Douglas Crocford ;)

Accessing a containing object from with in its method?

In the snippet below, an object literal holds properties, one of which is a method that needs access to the the object literal.
However, b.c. it is only used as an event handler callback, this always points to the element that triggered the event.
I need to access the containing object.
Otherwise, I'm forced to put a function in a function which seems odd.
/***************************************************************************************************
**MSimMenu - simple drop down menu
*/
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
// in mouseout this points to the element that triggered the event
// need access to containing object
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
init: function () {
var self = this;
// tempoaray fix - function in function seems odd
function mouse_out() {
self.A.time_out_id = NS.setTimeout(self.hideBottom, self.A.TIME_DELAY);
}
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
self.E.hold_name.addEventListener("mouseout", mouse_out, false);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
Final Code Using Bind
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
init: function () {
var self = this;
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", self.mouse_out.bind(self), false);
self.E.hold_name.addEventListener("mouseout", self.mouse_out.bind(self), false);
},
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
I have seen alot of people create a variable to assign the object to and then use the variable.
var that = {
myfunc:function(){
console.log(that)
}
};
NS.parsel(that);
I actually like moving most of the logic into the init method. Provides nice encapsulation with an easy way to declare public and private methods/variables. For example:
NS.parsel({
init: function() {
var self = this;
//public instance variable
self.Name = 'MSimMenu';
//private instance variables
var A = {
time_out_id: null,
TIME_DELAY: 1000
};
var E = {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
};
//public instance method
self.showBottom = function () {
E.wrap_bottom.style.visibility = 'visible';
};
//private instance method
E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
function mouse_out() {
A.time_out_id = NS.setTimeout(self.hideBottom, A.TIME_DELAY);
}
}
});
There's a lot of ways you can get what you want.
One trick you can do is to not use the mouse_out function directly, but provide a helper function like get_mouse_out() that returns a bound version of the function.
var myobject = {
data:"Some data",
_mouse_out: function() { console.log(this.data); }
get_mouse_out: function() {
var self = this;
return function(){ return Function.apply(self._mouse_out,self,arguments); }
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//This doesn't work.
do_callback( myobject._mouse_out);
//But this does
do_callback( myobject.get_mouse_out() );
EDIT: Improved version inlining _mouse_out and using bind.
var myobject = {
data:"Some data",
get_mouse_out: function() {
function _mouse_out() { console.log(this.data); }
return _mouse_out.bind(this);
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//But this does
do_callback( myobject.get_mouse_out() );
If you're willing to have init be called as setup before mouse_out is used then you can do this.
var myobject = {
data:"Some data",
init: function() {
function _mouse_out() { console.log(this.data); }
this.mouse_out = _mouse_out.bind(this);
}
}
myobject.init();
fn( myobject.mouse_out );
Finally there's a nice variant on Shanimals that works a similar way, but provides encapsulation.
NS.parcel( (function(){
var myobj = {};
myobj.data = "Some data";
myobj.mouse_out = function(){ console.log(myobj.data); }
return myobj;
})()
);

JavaScript "this" references wrong object [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
Well, this doesn't really refer to the wrong object, but I do not know how to refer to the correct one.
function someObj() {
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
this.someMethod2(); //I want this.someMethod2() to be called
//...but it tries to call elementBtn.someMethod2() i believe.
};
};
this.someMethod2 = function() {
alert('OK');
};
}
So when my myBtn is clicked I want someObj.someMethod2() to run. And I want it to be that someObj, not any other someObj. But how?!
You might need to make a tweak like this:
function someObj() {
var that = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
that.someMethod2();
};
};
this.someMethod2 = function() {
alert('OK');
};
}
"that" captures the scope you are after.
The function keyword changes scope. One solution is to maintain the reference to the "this" that you want to use.
Try the following:
function someObj() {
var self = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
self.someMethod2(); //NOTE self
};
};
this.someMethod2 = function() {
alert('OK');
};
}
You could use coffee script, which has a fat arrow (used for onclick function) to deal with this kind of thing, and compiles to well formed javascript. By using fat arrow, coffee script ensures the same scope as the function is defined in will be used in the callback function.
play with code here
Coffee Script
someObj = () ->
#someMethod1 = () ->
elementBtn = document.getElementById 'myBtn'
elementBtn.onclick = () =>
#someMethod2()
this.someMethod2 = () ->
alert 'OK'
JavaScript
var someObj;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
someObj = function() {
this.someMethod1 = function() {
var elementBtn;
elementBtn = document.getElementById('myBtn');
return elementBtn.onclick = __bind(function() {
return this.someMethod2();
}, this);
};
return this.someMethod2 = function() {
return alert('OK');
};
};

In javascript, how do I call a class method from another method in the same class?

I have this:
var Test = new function() {
this.init = new function() {
alert("hello");
}
this.run = new function() {
// call init here
}
}
I want to call init within run. How do I do this?
Use this.init(), but that is not the only problem. Don't call new on your internal functions.
var Test = new function() {
this.init = function() {
alert("hello");
};
this.run = function() {
// call init here
this.init();
};
}
Test.init();
Test.run();
// etc etc
Instead, try writing it this way:
function test() {
var self = this;
this.run = function() {
console.log(self.message);
console.log("Don't worry about init()... just do stuff");
};
// Initialize the object here
(function(){
self.message = "Yay, initialized!"
}());
}
var t = new test();
// Already initialized object, ready for your use.
t.run()
Try this,
var Test = function() {
this.init = function() {
alert("hello");
}
this.run = function() {
// call init here
this.init();
}
}
//creating a new instance of Test
var jj= new Test();
jj.run(); //will give an alert in your screen
Thanks.
var Test = function() {
this.init = function() {
alert("hello");
}
this.run = function() {
this.init();
}
}
Unless I'm missing something here, you can drop the "new" from your code.

Categories

Resources