How can I call PrintIt foo from Set()? I get error that it can't find it...
I know it's possible to call it via MyObject.prototype.PrintIt but this way i will "lose" the object and it's property (Num)
MyObject = function(){
this.Num=6;
}
MyObject.prototype = {
initialize: function(){
document.getElementById("button1").onclick = this.Set;
},
Set: function(){
this.PrintIt();
},
PrintIt: function(){
alert("I Print");
//alert( this.Num);
}
}
window.onload = function(){
obj = new MyObject;
obj.initialize();
}
The problem lies not in the prototype but in the way how you assign the method to the click handler. There it loses its connection to the object. You can use a closure:
initialize: function(){
var that = this;
document.getElementById("button1").onclick = function(){
that.Set();
};
},
Related
I create object var myObj = new functon () {...}.
In that object i add functions like :
var myObj = new function () {
this.func1 = function() {
func2();
}
this.func2 = function() {
...
}
}
As you can see in func1 I try to call func2 but it is always undefined. Why? Cause everything is in one object.
Change your scripts to
var myObj = function () {
var self = this;
this.func1 = function () {
self.func2();
};
this.func2 = function () {
...
};
};
On top of solutions provided by others. If you are going to call a javascript function that is defined like this
var func = function(){}
the function definition needs to come before the function call.
In the other way of defining a function this does not matter.
function func(){}
So Overall Code should be
var myObj = function(){
this.func2 = function(){
...
}
this.func1 = function(){
func2();
}
}
It's undefined because you don't have local variable func2. So correct reference should be this.func2().
However even in this case your code is not ideal construction object like this (mixing constructor and anonymous function) (although correct). In this case it's better to use object literal in the first place rather then create constructor function for just creating one single object instance:
var myObj = {
func1: function () {
this.func2();
},
func2: function () {}
};
You should call func2 like this
var myObj = new function () {
this.func1 = function () {
this.func2();
}
this.func2 = function () {
console.log('func2');
}
}
myObj.func1();
if you want call func2 with this. and without, you can do it like this
var myObj = new function () {
function func2() {
console.log('func2');
}
this.func1 = function() {
this.func2();
func2();
}
this.func2 = func2;
}
myObj.func1();
you can call like this.
Calling func2() directly, searches the function of window object.
var myObj = functon(){
var current = this;
this.func1 = function(){
current.func2();
}
this.func2 = function(){
...
}
};
My code:
function Demo (){
this.name = 'abc';
this.age = 20;
}
var demo = {
init : function(){
$('#test').hover(this.stop, this.start);
},
start: function(){
//here is the error
alert(this.name);
}
stop: function(){
alert(this.age); // 'this' does not mean the Demo object, but $('#test') object.
}
}
Demo.prototype = demo;
Demo.prototype.constructor = Demo;
(new Demo).init();
When the hover event of $('#test') is triggered, the stop method is called. However, 'this' in the method does not point to the demo object, but the $('#test') object. So, the alert is undefined. I need to have access to the attributes in the Demo object. And the stop and start method will be reused in other place, so I don not like to write the whole method code into hover's argument.
How should I solve this problem?
The this in the start and stop methods don't necessarily point to the same this as in the init. This is because they are callback functions. If you want to refer to the same object context then try the following:
var demo = {
init : function(){
$('#test').hover(this.stop.bind(this), this.start.bind(this));
},
start: function(){
//here is the error
alert(this.name);
}
stop: function(){
alert(this.age); // 'this' does not mean the Demo object, but $('#test') object.
}
}
Using bind will pass the this context through to the callbacks.
MDN docs for bind are here.
JQuery uses apply behind the scenes to call the event callbacks, that's why the context changes.
To mitigate this, you can do one of two things:
Use bind
var demo = {
init : function(){
$('#test').hover(this.stop.bind(this), this.start.bind(this));
},
start: function(){
alert(this.name);
}
stop: function(){
alert(this.age);
}
}
call the method directly
var demo = {
init : function(){
// Closure here
var self = this;
$('#test').hover(function() {
self.stop();
}, function() {
self.start();
});
},
start: function(){
alert(this.name);
}
stop: function(){
alert(this.age);
}
}
A None JSON implementation that will allow you to set the variable self
function Demo(){
this.name = 'abc';
this.age = 20;
}
Demo.prototype = new (function(){
var self = this;
this.init = function(){
$('#test').hover(self.stop, self.start);
}
this.start = function(){
//here is the error
alert(self.name);
}
this.stop = function(){
alert(self.age); // 'this' does not mean the Demo object, but $('#test') object.
}
})();
(new Demo()).init()
EDIT:
I have updated to show what i was meaning without the use of var demo = {...} the point i was trying to make was not to use the Object Literal aka JSON style so you could support a variable inside the prototype
I'm creating an Javascript "class" with prototyping. I don't understand why the first/second block won't work, and the third block will work. For the first/second block I get: "Object # has no method 'validate' ". Why does it do that, and is block 3 the correct way?
--Edit
I have tested this in Chrome/FF
--Edit2
If I call the Test prototype with:
var test = new Test();
And call the test var in de login prototype it will work....
Block 1
function Test(){
this.init();
}
Test.prototype.init = function(){
$(".login").click(this.login);
};
Test.prototype.login = function(event){
event.preventDefault();
this.validate();
console.log("login");
};
Test.prototype.validate = function(){
console.log("validate");
};
new Test();
Block 2
function Test(){
this.init();
}
Test.prototype.init = function(){
$(".login").click(this.login);
};
Test.prototype.login = function(event){
var self = this;
event.preventDefault();
self.validate();
console.log("login");
};
Test.prototype.validate = function(){
console.log("validate");
};
new Test();
Block 3
function Test(){
if(!(this instanceof LoginController)){
return new LoginController();
}
self = this;
this.init();
}
Test.prototype.init = function(){
$(".login").click(this.login);
};
Test.prototype.login = function(event){
event.preventDefault();
self.validate();
console.log("login");
};
Test.prototype.validate = function(){
console.log("validate");
};
new Test();
Test.prototype.init = function(){
$(".login").click(this.login);
};
Here you're attaching this.login as event handler. Done this way, the function will have it's this value reassigned by jquery to the element that triggered the event.
To to keep a reference to the this value you actually want, try:
Test.prototype.init = function(){
var self = this;
$(".login").click(function (evt) {
return self.login(evt);
});
};
or for browsers implementing bind:
Test.prototype.init = function(){
$(".login").click(this.login.bind(this));
};
or jQuery.proxy, which does the same thing as bind:
Test.prototype.init = function(){
$(".login").click($.proxy(this.login, this));
};
demo: http://jsbin.com/ilejiw/1/
Update: No, the 3rd variant is not the correct way, as every instance of Test would overwrite the same global self variable. So self would point to the last instance of Test (as long as it has not been overwritten by something else).
I am trying to make a "Class" factory with Javascript so that I can create different types of objects.
Here is the function I'm using:
var Class = function(methods) {
var klass = function() {
var self = this;
this.initialize.apply(this, arguments);
};
for (var property in methods) {
klass.prototype[property] = methods[property];
}
if (!klass.prototype.initialize) klass.prototype.initialize = function(){};
return klass;
};
Then I can do:
var myObject = Class({
initialize: function() { console.log(self);}
});
var createdObject = new myObject();
However, the console.log(self) is always referring to Window, and I'd like it to refer to the object itself.
I know this is a scope issue, but I'm confused on how to create a reference to the object?
I am trying to make a "Class" factory with Javascript so that I can create different types of objects.
Here is the function I'm using:
var Class = function(methods) {
var klass = function() {
var self = this;
this.initialize.apply(this, arguments);
};
for (var property in methods) {
klass.prototype[property] = methods[property];
}
if (!klass.prototype.initialize) klass.prototype.initialize = function(){};
return klass;
};
Then I can do:
var myObject = Class({
initialize: function() { console.log(self);}
});
var createdObject = new myObject();
However, the console.log(self) is always referring to Window, and I'd like it to refer to the object itself.
I know this is a scope issue, but I'm confused on how to create a reference to the object?
For example, if I wanted to do:
var myObject = Class({
initialize: function() {
$('#myDiv').click( function() {
self.anotherFunction();
});
},
anotherFunction: function() {
alert('hi');
}
});
I would need to be able to reference the "myObject" with self...
Use this instead of self. self will not be accessible to initialize function as it is defined outside the scope of klass self
Best option is define self inside each function as last solution I provided.
var myObject = Class({
initialize: function() { console.log(this);}
});
OR
var myObject = Class({
initialize: function() { console.log(createdObject);}
});
OR
var myObject = Class({
initialize: function() { var self = this; console.log(self );}
});
How can i get variable in handler function of obj? Without reference of the obj in MyClass.
var obj = {
func: function(){
var myClass = new MyClass();
myClass.handler = this.handler;
myClass.play();
},
handler: function(){
//Here i don't have access to obj
console.log(this); //MyClass
console.log(this.variable); //undefined
},
variable:true
};
function MyClass(){
this.play = function(){
this.handler();
};
this.handler = function(){};
};
obj.func();
That's construction need you, if you use Base.js or another similar way of oop.
_.bindAll(obj) (underscore metod) also not suitable. It's break overriding in Base.js.
Bind only handler method: http://jsfiddle.net/uZN3e/1/
var obj = {
variable:true,
func: function(){
var myClass = new MyClass();
// notice Function.bind call here
// you can use _.bind instead to make it compatible with legacy browsers
myClass.handler = this.handler.bind(this);
myClass.play();
},
handler: function(){
console.log(this.variable);
}
};
function MyClass(){
this.play = function(){
this.handler();
};
this.handler = function(){};
};
obj.func();
Use a variable to refer original context:
...
var self = this;
myClass.handler = function(){ self.handler(); };
...
Declare variable before handler:
var obj = {
variable: true,
func: function(){
// ...
},
handler: function(){
console.log(this.variable); //true
}
};
Use Function call with this from obj in declared in a scope var to solve it.
var obj = {
func: function(){
var self = this;
var myClass = new MyClass();
myClass.handler = function() { return this.handler.call(self); };
myClass.play();
},
handler: function(){
//Here i don't have access to obj
console.log(this); //MyClass
console.log(this.variable); //undefined
},
variable:true
};
You don't have access to obj because this is bind to the instance of MyClass constructor - myClass. If in handler you want to have access to myClass through this and access to obj you have to use obj name directly so:
console.log(this); // myClass
console.log(obj.variable); // true
If you want to have this bind to obj use what Juan Mellado or gryzzly suggested.