Access to class member within closure - javascript

I have a class method and a closure within this method. How I can access to class member from closure?
Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
$('#myBtn').click( function() {
// how to access to this.x? the this reference points in another context
});
}
}

Use of Function.prototype.bind will help you here
Person = function(x) {
this.x = x;
}
Person.prototype.myMethod = function() {
$('#myBtn').click(function() {
this.x;
}.bind(this));
};
You can use some better separation of code here too
Person = function(x) {
this.x = x;
};
Person.prototype.myMethod = function {
$('#myBtn').click(this.clickHandler.bind(this));
};
Person.prototype.clickHandler = function(event) {
console.log(this.x);
};
Note if you want to support older browsers, check out es5-shim
EDIT
I'm revisiting this after ~6 months and I would probably write the above code differently. I like the private/public exposure here. Also, no need for any fanciful binds or anything like that ^.^
function Person(x, $button) {
// private api
function onClick(event) {
console.log(x);
}
function myMethod() {
$button.click();
}
// exports
this.x = x;
this.myMethod = myMethod;
// init
$button.click(onClick);
}
var b = $("#myBtn"),
p = new Person("foo", b);
p.x; // "foo"
p.myMethod(); // "foo"
btn.click(); // "foo"

Just assign this to some other variable, for example _this:
Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
var _this = this;
$('#myBtn').click( function() {
console.log(_this.x);
});
}
}

Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
var self = this;
$('#myBtn').click( function() {
// Access to self.x
});
}
}

A proxy would be very useful here.
Right now, you're assigning an anonymous function to the click event. By default the context will be the event's and separate from your object.
With a proxy you can assign a particular context to a (callback) function. Thus, when the event fires, you're dealing with your person object.
Assign the event handler in a separate function like initialize(), and have myMethod() be the handler.
Use a JQuery.proxy() to assign the object`s context to the event handler.
Person.prototype = {
initialize: function() {
$('#myBtn').click($.proxy(this.myMethod, this));
},
myMethod: function(event) {
...
console.log(this); // Person object
}
}
Just to elicit the difference between my and #naomik's solution:
JQuery.proxy() is a temporary or narrow assignment to a context.
Function.prototype.bind() is a strong context assignment. The method will be "forever" bound to the context you give it.

Related

How can I use a method from inherited class

I have the inheritance chain Vehicle -> Motorized -> Car implemented:
function Vehicle()
{
var m_name;
this.setName = function(pName) {
m_name = pName;
};
this.getName = function() {
return m_name;
};
}
function Motorized()
{
var m_started = false;
this.start = function() {
m_started = true;
console.log(getName() + " started");
};
}
function Car()
{ }
//set up the inheritance chain
Motorized.prototype = new Vehicle();
Car.prototype = new Motorized();
// use
var lCar = new Car;
lCar.setName("Focus");
console.log(lCar.getName()); // Focus
lCar.start(); // ReferenceError: getName is not defined
When I invoke lCar.start() (defined in function Motorized), I get an ReferenceError: getName is not defined. How can I use the inherted method getName() in my subclass Motorized?
Because Javascript doesn't know where to look for your getName() method. You can clarify the syntax declaring a self variable that always points to the right object, like this:
function Vehicle()
{
var self = this; // Vehicle
var m_name;
this.setName = function(pName) {
self.m_name = pName;
};
this.getName = function() {
return self.m_name;
};
}
function Motorized()
{
var self = this; // Motorized
var m_started = false;
this.start = function() {
/*
`self` is Motorized, with proto Vehicle, so
has a getName() method.
`this` instead is the object where you call
start() from, i.e. Car, in the example down below.
*/
self.m_started = true;
console.log(self.getName() + " started");
};
}
function Car()
{ }
//set up the inheritance chain
Motorized.prototype = new Vehicle();
Car.prototype = new Motorized();
// use
var lCar = new Car;
lCar.setName("Focus");
console.log(lCar.getName()); // Focus
lCar.start(); // Focus started
Note that in this case, using the keyword this instead of self throughout the code would have worked as well, but you definitely cannot omit it before getName(). Also, if you are planning to add more code later on, such as event handlers in jQuery, having a clear reference to the class you're coding in can be useful, as this can become easily ambiguous, at least from the human point of view.
Anyway, whether using self is a bad coding pattern or not is the topic of this question; the point in your example is that you need to call self.getName() or this.getName().

Less verbose way of binding prototype functions to this

I use the following paradigm of declaring classes:
var myNamespace = myNamespace || {};
(function () {
myNamespace.MyClass = function () {
if (!(this instanceof myNamespace.MyClass)) {
return new myNamespace.MyClass();
}
this.field = 17;
this.foo = this.foo.bind(this);
this.bar = this.bar.bind(this);
};
myNamespace.MyClass.prototype.foo = function(){
console.log(this.field + 1);
};
myNamespace.MyClass.prototype.bar = function(){
console.log(this.field + 2);
};
})();
I use prototype to avoid redeclaring the object methods on every instantiation, and to make the code a bit cleaner - separating the class fields from its logic.
I call bind on every method, to avoid nasty bugs where this points the wrong way inside the methods.
It works, but it is error prone - I have to remember to call bind on each method, and it is too verbose, especially when there are more than two methods.
Is there a cleaner* way to declare these kind of functions (bound to their type's this, and declared on the prototype)?
*I know "clean" is not well defined - A simple metric would be code length.
You shouldn't be binding your methods like that - you're creating new functions on every instance, when you really should just have the methods on the prototype to save memory. If you create 100 instances, you are making 200 new functions! A simple pattern like this is more common and will work fine:
var myNamespace = myNamespace || {};
myNamespace.MyClass = (function() {
function MyClass() {
this.field = 17;
}
MyClass.prototype = {
constructor: MyClass,
foo: function() {
console.log(this.field + 1);
},
bar: function(){
console.log(this.field + 2);
}
};
return MyClass;
}());
Attach to your namespace after declaring your class:
var myNamespace = myNamespace || {};
(function () {
var MyClass = function () {
this.field = 17;
};
MyClass.prototype.foo = function(){
console.log(this.field + 1);
};
MyClass.prototype.bar = function(){
console.log(this.field + 2);
};
this.MyClass = MyClass;
}).call(myNamespace);
By calling the IIFE with the namespace as scope you can keep the module clean by exposing the class on the this object.
You can compact some of the prototype definitions in a single assignment and pass your namespace into function call.
var myNamespace = myNamespace || {};
(function () {
function MyClass() {
this.field = 17;
};
MyClass.prototype = {
foo: function () {
console.log(this.field + 1);
},
bar: function () {
console.log(this.field + 2);
}
};
})(myNamespace);

Run additional action after constructor

Is it possible to change a constructor so that some extra action is run after an object is created. I tried something like:
var origFoo = Foo
Foo = function() {
origFoo.apply(this, arguments);
/* extra actions */
}
Foo.prototype = new origFoo();
but this has several problems like the constructor being run twice or changing the prototype chain.
You are very close. You should assign the Foo.prototype to the origFoo.prototype in order to get the same prototype chain. Everything else is spot on!
Example:
var Foo = function () {
console.log('OriginalFoo');
};
Foo.prototype.method1 = function () {
console.log('Method1');
};
OriginalFoo = Foo;
Foo = function () {
OriginalFoo.apply(this, arguments);
console.log('NewFoo');
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.method2 = function () {
console.log('Method2');
};
var x = new Foo();
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/1/edit?js,console,output
PS: There still is the problem of static-like properties (Foo.prop), but i'm afraid i don't have a solution for that other than copying them one at a time.
EDIT: Solution for special constructors.
Indeed there are constructors which don't like to be called as functions ex: Image. To get over it, you can do the more awkard solution below. You take advantage of the fact that you can return an object from the constructor and it takes the place of the one created with new. In the overridden constructor you must always use this new object when calling methods instead of this.
var Foo = function(a,b,c) {
console.log('OriginalFoo',a,b,c);
};
Foo.prototype.prop1 = 'Property1';
Foo.prototype.method1 = function() {
console.log('Method1', this.prop1);
};
OriginalFoo = Foo;
Foo = function(a,b,c) {
var obj = new OriginalFoo(a,b,c);
obj.init('Changed...'); // or this.init.call(obj,'Changed!');
this.init('Not Changed'); // applies to a discarded object, has no effect
console.log('NewFoo');
return obj;
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.prop2 = 'Property2';
Foo.prototype.method2 = function() {
console.log('Method2', this.prop2);
};
Foo.prototype.init = function(param) {
this.prop2 = param;
};
var x = new Foo('1','2','3');
console.log(x.prop1);
console.log(x.prop2);
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/2/edit?js,console,output

Extending inheritance of `this` to methods / properties of an `object`

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.

avoid needing to declare 'var me = this' for javascript prototype functions

Currently, I create objects in javascript by declaring a construction (regular function) then add methods to the prototype like so
function Test(){
}
Test.prototype.test1 = function(){
var me = this;
}
However, I would like to avoid having to declare var me = this at the top of every function. The following seems to work, but seems like it would be very inefficient:
$(document).ready(function(){
var n = 0;
(function(){
function createTest(){
var me;
function Test(){
this.n = n;
this.testArr = [1, 2, 3, 4];
n++;
}
Test.prototype.test1 = function(){
me.test2();
};
Test.prototype.test2 = function(){
alert(me.n);
$.getJSON('test.php', {}, function(reply)
//want to be able to use 'me' here
me.newField = reply;
});
};
var t = new Test();
me = t;
return t;
}
window['createTest'] = createTest;
})();
var t = createTest();
t.test1();
var t2 = createTest();
t2.test1();
t.test1();
});
This code outputs the expected, but is it actually as inefficient as it looks (the Test object being re-declared every time you call createTest())?
Anyhoo, this would seem a bit hacky... is there a completely different way to do this that is better?
EDIT: The real reason I would like to do this is so that callbacks like the one in test2 will have references to the correct this.
What you can do is bind the current this value to a function and store a copy somewhere. (For the sake of efficiency.)
if (!Function.prototype.bind) {
// Most modern browsers will have this built-in but just in case.
Function.prototype.bind = function (obj) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () { },
bound = function () {
return self.apply(this instanceof nop ? this : (obj || {}),
args.concat(slice.call(arguments)));
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
function Test(n) {
this.n = n;
this.callback = (function () {
alert(this.n);
}).bind(this)
}
Test.prototype.test1 = function () {
this.test2();
}
Test.prototype.test2 = function () {
doSomething(this.callback);
}
function doSomething(callback) {
callback();
}
var t = new Test(2);
t.test1();
I realize your question was not tagged with jQuery, but you are using it in your example, so my solution also utilizes jQuery.
I sometimes use the $.proxy function to avoid callback context. Look at this simple jsfiddle example. Source below.
function Test(){
this.bind();
}
Test.prototype.bind = function(){
$('input').bind('change', $.proxy(this.change, this));
// you could use $.proxy on anonymous functions also (as in your $.getJSON example)
}
Test.prototype.change = function(event){
// currentField must be set from e.target
// because this is `Test` instance
console.log(this instanceof Test); // true
console.log(event.target == $('input')[0]); // true
this.currentField = event.target; // set new field
};
function createTest(){
return new Test();
}
$(function(){ // ready callback calls test factory
var t1 = createTest();
});
Most of the time, I just declare a local variable that references this, wherever I need a reference to this in a callback:
function Foo() {
}
Foo.prototype.bar = function() {
var that=this;
setTimeout(function() {
that.something="This goes to the right object";
}, 5000);
}
Alternatively, you can use bind() like this:
Function Foo() {
this.bar = this.bar.bind(this);
// ... repeated for each function ...
}
Foo.prototype.bar = function() {
}
What this gives you is that every time you create a new Foo instance, the methods are bound to the current instance, so you can use them as callback functions for setTimeout() et al.

Categories

Resources