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.
Related
Let's say I have the following code:
var Obj = function() {
this.property = 1;
this.arr = [...] // array containing elements we want to add event listeners to
for (...) {
this.arr[i].addEventListener("click", this.listener, false);
}
}
Obj.prototype.listener = function() {
console.log( this.property ); // DOES NOT WORK! *this* does not point to Obj.
}
var a = new Obj();
How do I access object properties (and methods) within a listener? I would assume I'd need to pass it as a parameter? Is the way I'm going about this structurally wrong?
When the function is called as an event listener, the context (this) is changed to something other that the object itself.
To resolve this, manually bind the context to the object instance in the constructor using bind(). This way, this will always point to the object instance, independent of the calling context:
var Obj = function() {
this.property = 'foo';
this.listener = this.listener.bind(this);
}
Obj.prototype.listener = function() {
console.log(this.property);
}
var a = new Obj();
a.listener.call({});
As suggested by #Tushar, you can use Function.prototype.bind() and pass this.property as parameter
<body>
click
<script>
var Obj = function() {
var obj = this;
this.property = 1;
this.arr = [document.body];
for (var i = 0; i < obj.arr.length; i++) {
obj.arr[i].addEventListener("click"
, obj.listener.bind(obj.arr[i], obj.property), false);
}
}
// note order of parameters; e.g., `prop`, `e`
Obj.prototype.listener = function(prop, e) {
console.log(prop, e); // `1`, `event` object
}
var a = new Obj();
</script>
</body>
It is comfortable to create self = this variable. In all methods we always can use self, and don't worry about method context - some times this in method not we expected.
But in prototype method we can't use this hint;
Look at the example (jQuery needed onle to show the question)
var myClass = function () {
this.propery = 'someData';
var self = this;
this.method = function () {
console.log(self.propery);
}
}
myClass.prototype.method2 = function () {
// want to use self here
console.log(this);
}
var my = new myClass();
var eventBus = $({});
eventBus.bind('onMyEvent', my.method);
eventBus.bind('onMyEvent', my.method2);
eventBus.trigger('onMyEvent');
What is the best way to declare the class with possibility to use self in prototype methods?
You don't need self, just need to set the value of this by binding the object to the function:
var MyClass = function () {
this.property = 'someData';
this.method = function () {
console.log(this.property);
};
};
MyClass.prototype.method2 = function () {
console.log(this);
};
var my = new MyClass();
var eventBus = $({});
eventBus.bind('onMyEvent', my.method.bind(my)); // bind
eventBus.bind('onMyEvent', my.method2.bind(my)); // bind
eventBus.trigger('onMyEvent');
I'm not sure if I phrased the question title correctly; please consider the following to clarify...
(function() {
var foo = {
bar: function() {
// Is it possible to reference 'this' as the
// initializing 'object' aka 'e' and not 'foo' ?
// The easy part, currently because 'this' refers to 'foo',
// is returning 'this' aka 'foo' so that chaining can occur
return this;
},
other: function() {
return this;
}
};
Event.prototype.foo = foo;
}());
// usage
document.onmousemove = function(e) {
e.foo.bar().other();
};
How would I go about having access to this within the methods / props of foo but having this refer to the initial object aka e and not foo ?
The best that I have come up with is this
(function() {
var foo = function() {
var _foo = this.foo;
_foo._this = this; //recursive reference that I am VERY worried about
return _foo;
};
foo.bar = function() {
var _this = this._this; //_this refers to initial 'object', 'e'
return this; //return 'foo' aka 'this' for function chaining
};
foo.other = function() {
var _this = this._this;
return this;
};
Event.prototype.foo = foo;
}());
// usage
document.onmousemove = function(e) {
e.foo().bar().other();
};
What I have currently works but I am worried about a couple of things...
1. The recursive reference of assigning e to e.foo._this
and
2. The redundancy of assigning e to e.foo._this, if this could be accessed as e instead of foo it would make 'things' more performant, especially in regards to something like a mousemove event.
jsFiddle Here
Also, Im trying to avoid something like this...
document.onmousemove = function(e) {
e.foo.bar.call(e);
};
All suggestions are appreciated, Thanks for your time.
With a subtle change to what you have you can make things simpler:
(function() {
var foo = function() {
this.foo.event = this;
return this.foo;
};
foo.bar = function() {
/// the event can be found in this.event
return this;
};
foo.other = function() {
/// the event can be found in this.event
return this;
};
Event.prototype.foo = foo;
}());
// usage
document.onmousedown = function(e) {
e.foo().bar().other();
};
This however is making a change to the shared object foo, you may wish to rewrite things so that e.foo() returns a new instance of foo instead, and move your other methods to foo's prototype.
(function() {
var foo = function(event) {
this.event = event;
};
foo.prototype.bar = function() {
/// the event can be found in this.event
return this;
};
foo.prototype.other = function() {
/// the event can be found in this.event
return this;
};
Event.prototype.foo = function() {
return new foo(this);
};
}());
This way you are creating a new instance of foo each time, but it means your addition of the event property is localised to that instance; the prototyped methods will be shared across all instances so it's not too bad from an optimisational point of view.
Maybe that would work for you:
Use the apply method to change the this context in the called method and use this.foo to refer to foo:
(function () {
var foo = function () {
console.log(this);
return this.foo;
};
foo.bar = function () {
console.log(this);
return this.foo;
};
foo.other = function () {
console.log(this);
return this.foo;
};
Event.prototype.foo = foo;
}());
// usage
document.onclick = function (e) {
console.log(
e.foo.apply(e).bar.apply(e).other.apply(e)
);
};
FIDDLE
Maybe it would be simpler to bind your function to its object :
someElement.onEvent = myObject.myHandlerFunction.bind(myObject);
so when this function will be called, its 'this' will be myObject.
Then you can make use of e.target to access the element.
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 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();
};
},