1

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.

1
  • 1
    I think you have to bind this to your method explicitly. JavaScript is quirky in how it deals with that variable: s.pos = this.el.position.bind(this.el). Commented Jun 7, 2015 at 22:49

3 Answers 3

2

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(); }
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! Accepted answer due to being most extensive, easy to understand explanation and link to docs.
1

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);

1 Comment

Thanks, upvote for the performant solution as well as doc links.
1

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()); 

1 Comment

Thank you, upvote for fiddle, working code and explanation of the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.