Page 1 of 1

Where is my Object gone? Function Scope change in JavaScript Rate Topic: -----

#1 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3485
  • View blog
  • Posts: 10,044
  • Joined: 08-June 10

Posted 25 June 2010 - 05:14 AM

Where is my Object gone?

prerequisites:
you need to know about Scope

recommended reading:
http://blog.morrisjo...or_dummies.html
http://www.jibbering...notes/closures/

Today I’ll continue my talk about Scope related issues within Javascript. Last time I said that the this keyword references the object providing the current scope and I mentioned, that this can mess up, if you’re using object methods instead of functions.

function ForumMember(Name)
{
	this.name = Name;
}
ForumMember.prototype.introduce = function ()
{
	alert("Hi, my name is " + this.name);
}

// instantiate object
var d = new ForumMember("Dormilich");

// call normally
d.introduce(); // Hi, my name is Dormilich

// call from an event
document.dic.introduction.onclick = d.introduce; // Hi, my name is introduction



Why this happens should be easy to understand. Event handlers set this to the current HTML element and they don’t differentiate between global functions and object methods (btw. if you’re strict, there is no difference between them).

Then why do we use objects, if they are that disadvantageous? Because the advantages are far greater (data encapsulation, code re-use) and a fix is quickly done. It is not an option to replace this in the object itself (the prototyped methods can only reference the object’s other properties/methods* via this and not prototyping methods (if you can) is hilarious). The only option we have is to somehow fixate the this, so that is is not re-assigned. For this purpose we can make use of Closures, a powerful construct not only known in Javascript.

Definition:

Quote

A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).


With this in mind, we can thus shift the level of the method code out of the event handler’s reach.

document.dic.introduction.onclick = function (evt) { d.introduce(); );



The closured variable is d, the evt parameter is declared for convenience, since this is the parameter that is always passed to the function, when the event handler executes.

Soon enough, poeple got tired from writing that again and again and they thought of a more convenient way to apply (no pun intended) the closure. Again, object oriented programming came to aid. Since the Event Handler had to be a function, what’s easier than extending the Function object?

// closuring "this" in an out-of-scope call (Events)
Function.prototype.bind = function (obj)
{
	var fn = this;
	return function () {
		return fn.apply(obj, arguments);
	}
}



To explain that code a bit. "Function" is the interface all Javascript functions adhere to. this stands for the function that calls the .bind() method and fn and obj are the closured variables. arguments is a "magic" variable of the function object, holding the list** of passed parameters. calling the .bind() method produces a function with fixated variables (see snippet below).

// fn & obj are fixated through a closure
function () {
	return fn.apply(obj, arguments);
}
// it does look like our previous solution …



With that tool in hand, you can closure your object variables very comfortably***.

document.dic.introduction.onclick = d.introduce.bind(d);



What’s even more useful is that all parameters passed to the function initially, are passed further to the closured function (something you’d have to do manually in the previous example). This might not be of interest in our example case, but in cases where you use an object’s method that does work with the Event object.

In this talk I’m merely scratching the topic of Closures, which is a powerful coding technique, you should definitely add to your tool box.

* – strictly speaking, in Javascript there is no difference between properties and methods (a common trap in the for … in loop).
** – this is not an Array
*** – you could even "misuse" it to pass down a parameter in an Event Handler, although currying is better suited for that.
function add5()
{
	alert(5 + this);
}
document.dic.plus5.onclick = add5.bind(7);



Is This A Good Question/Topic? 4
  • +

Replies To: Where is my Object gone?

#2 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3485
  • View blog
  • Posts: 10,044
  • Joined: 08-June 10

Posted 09 July 2011 - 01:46 AM

Note:

As of Javascript 1.8.5 / ECMAScript 262 5th edition, bind() is a native method of the Function Interface.

That is, all major & modern browsers should support it.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1