Iskren
Iskren

Reputation: 1341

How to assign a function to a object method in javascript?

I'd like to 'proxy' (not sure if that's the term at all) a function inside a function object for easy calling.

Given the following code

function Soldier() {
    this.el = $("<div></div>").addClass('soldier');
    this.pos = this.el.position; // $(".soldier").position(), or so I thought
}

In the console:

s = new Soldier();
$("#gamemap").append(s.el); // Add the soldier to the game field
s.pos === s.el.position // this returns true
s.el.position() // Returns Object {top: 0, left: 0}
s.pos() // Returns 'undefined'

What am I doing wrong in this scenario and is there an easy way to achieve my goal (s.pos() to return the result of s.el.position()) ? I thought about s.pos = function() { return s.el.position(); } but looks a bit ugly and not apropriate. Also I'd like to add more similar functions and the library will become quite big to even load.

Upvotes: 1

Views: 74

Answers (3)

zlumer
zlumer

Reputation: 7004

When you're calling s.pos(), its this context is lost. You can simulate this behavior using call():

s.pos.call(s); // same as s.pos()
s.pos.call(s.el); // same as s.el.position()

This code is actually ok:

s.pos = function() { return s.el.position(); }

An alternative is using bind():

s.pos = s.el.position.bind(el);

You can use the prototype, that way the functions will not be created separately for every object:

Soldier.prototype.pos = function(){ return this.el.position(); }

Upvotes: 2

GillesC
GillesC

Reputation: 10874

It's because the context of execution for position method has changed. If you bind the method to work inside the element context it will work.

JS Fiddle

function Soldier() {
    this.el = $("<div></div>").addClass('soldier');
    this.pos = this.el.position.bind(this.el); 
}

var s = new Soldier();
$("#gamemap").append(s.el); 
console.log(s.pos()); 

Upvotes: 1

Bergi
Bergi

Reputation: 664548

I'd recommend to use the prototype:

Soldier.prototype.pos = function() { return this.el.position(); };

Not ugly at all, and quite performant actually.

If you want to directly assign it in the constructor, you'll need to notice that the this context of a s.pos() invocation would be wrong. You therefore would need to bind it:

    …
    this.pos = this.el.position.bind(this.el);

Upvotes: 1

Related Questions