Page 1 of 1

this is it better programming with "this" Rate Topic: -----

#1 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3494
  • View blog
  • Posts: 10,072
  • Joined: 08-June 10

Posted 25 June 2010 - 05:03 AM

this is it!

Ever heard of Scope? No? Then this article might be just for you.

Scope is defined as the context, wherein a variable can be accessed. What does that mean? If you define a variable inside a function, it can be accessed everywhere inside that function (even in other functions defined in that function) but not outside of it. The outmost possible scope is called "global scope", all subsequent scopes are called "local scopes".

var x = "global";
function test()
{
	var y = "local";
	var func = function ()
	{
		var z = "inner";
		alert(x); // global
		alert(y); // local
		alert(z); // inner
	}
	alert(x); // global
	alert(y); // local
	alert(z); // undefined
}
alert(x); // global
alert(y); // undefined
alert(z); // undefined



What has that to do with this ? this is the Javascript keyword for the current scope, the code/function is executed in. It is of utmost importance to differentiate between the scope, a function executes in and the scope, a function was defined in.

What do we need this this for then? We need it for creating objects and we need it when applying a function on another object.

Creating objects

Javascript, in constrast to most other programming languages (like PHP, C and Java), does not know the concept of classes and uses prototyping instead. So Javascript objects are created using Constructor functions.

function MyObject(txt)
{
	this.text = txt;
}



You see an ordinary function, except for that suspicious this. To create a new object, we use the (surprise!) new keyword*. When using the Constructor function to create an object, this points to the current object instance, we just created, in contrast for the pure function, where it points to the global object.

var x = new MyObject("doh");



This newly created object currently contains 1 (own) property: .text. From outside the object x, we refer to it as x.text, but from the inside, we have to use this.text. Thatís simply because we donít know the name of the variable. On the other hand side, the variable name is of no interest inside, because we donít want to refer to a specific (named) object, but the current object (whatever name it may have), so that our code is applicable in every instance (thatís one reason to use objects at allóapplying a piece of code multiple times (= Code Re-use)).

How does that affect this ? Letís find out:

// execute as object
var x = new MyObject("doh");
// show the property
alert(x.text);

// execute as another object
var y = new MyObject("blah");
alert(y.text);

// execute as function
MyObject("oink");
// where is the property? Here.
alert(text);



This simple demo shows that this is not a staticly defined variable, but depending on the context it executes in.

Calling functions in different contexts

And we can make good use of it. Since in Javascript nearly everything is an object (even HTML elements), we can make this point to any object we want. For that to happen, there are two possibilities:
- directly set this by Function.call() or Function.apply()
- implicitly set this by using an Event Handler or any other scope changing function

Possibility #1 only works on functions (yes, functions are objects too) and you use it, when you want to execute an objectís method in another context. e.g. you want to apply an Array method on a HTMLCollection:

// return an Array of checked boxes

// the NodeList (thatís not an Array) of checkboxes
var list = document.getElementsByName("something");

// our test function
function is_checked(item, index, arr)
{
	return item.checked;
}

// if list were an Array, it would look like
// var a = list.filter(is_checked);

// but since list is not an Array, we have to replace the
// "this" inside Array.filter() by our list manually
// which is done by Function.call()
var a = Array.prototype.filter.call(list, is_checked);
// "Array.prototype.filter" contains the function code of the 
// Array.filter() method (see Javascript inheritance)



Possibility #2 changes the scope automaticly.

In Javascript there are a couple of functions (e.g. setTimeout(), setInterval(), Element.addEventListener() and Event Listeners in general) that implicitly set the functionís scope to their context (i.e. setTimeout() would set this to window and .addEventListener() would set it to the element that is listening to the event).

<input id="test1" type="checkbox" value="itís me!">
<input id="test2" type="text">


// alert the fieldís value on click

function show()
{
	alert(this.value);
}

document.getElementById("test1").onclick  = show;
document.getElementById("test2").onchange = show;



Possibility #2 is interesting, because all HTML Elements conform to a common interface**óthe DOM API. That is, we can write a generic function, that will work on every HTML Element! This becomes especially useful, if we combine this technique with the power of DOM-2 Event handling (addEventListener()). We can write a couple of functions, that test a specific condition (like field is empty, field only contains numbers, field contains an email address, etc.) and addEventListener() lets us attach as many functions to a specific field, as we want.

We can even specify more detailed interfaces (DOM-3 defines 23 core interfaces, with 7 of particular interest for HTML (Node, NodeList, NamedNodeMap, CharacterData, Attr, Element, Text) and 56 further interfaces for HTML documents (e.g. HTMLInputElement for <input>).

To be fair, I should mention that this dynamic behaviour of this also provides a stumbling block. We can not only pass global functions to the scope changing functions, but also methods of instantiated objects.

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

var d = new ForumMember("Dormilich");
d.introduce();
document.forms[0].introduction.onclick = d.introduce;



You may guess what happens, the event handler re-assigns the this inside ForumMember.introduce to the button object and it alerts Hi, my name is introduction. To prevent this, you have to use a Closure to fixate the this in ForumMember.introduce to d.

document.forms[0].introduction.onclick = function () { d.introduce(); };
// or as of ECMAScript 262-5
document.forms[0].introduction.onclick = d.introduce.bind(d);



I hope I could shed some light on this complex matter, hoping your next script will profit of it.


* Ė another possibility incorporates the Object.create() method (as of ECMAScript 262-5)
** Ė an Interface is a set of properties/methods, which the object implementing the Interface must have. e.g. every <input> element has a .value property.

recommended reading:
http://www.digital-w..._in_javascript/

Is This A Good Question/Topic? 1
  • +

Page 1 of 1