Jump to content

JavaScript Execution Context


yusufaytas

Recommended Posts

I would disagree that experienced Javascript developers don't understand Javascript's scope and execution contexts, but this may be helpful to some of the beginners, as W3Schools doesn't make it entirely clear.

Link to comment
Share on other sites

The only thing I find somewhat confusing is that 'this' is often passed as a parameter but it seems to be available within the scope of an event handler function while the event object is passed as a parameter and must be received as a parameter.

Link to comment
Share on other sites

this always refers to the execution scope. It's an object like any other object, which means you can pass it as a parameter. But just passing this as a parameter doesn't change the value of this inside the function you pass it to. You see that with things like inline event handlers, where it passes this to the handler. In that case, for an event handler like a click event, it's passing the element that was clicked on. The reason for that is because in inline event code, this refers to the element that the event is for. So in that inline code using this is an easy generic way to pass the element that you're working with regardless of what the element actually is. But inside the actual event handler function, this doesn't refer to the element, it's running in a different scope (it's usually set to the window object, which is the default scope). That's something like this:

<a onclick="alert('the scope inside this code is the element that was clicked on'); do_click(this);">test</a><script>function do_click(el){  // el is set to the element that was passed, and this is set to the window object}</script>

There are a couple ways to change the scope though, to change the value of this that a particular function uses. One way is the Function.call method, and another is the Function.apply method.

 

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

 

Using one of those, you can tell it what scope to execute the function under. So you can write a function which uses this and expects it to be set to something like an element, and then call that function with different scopes. e.g.:

function add_child(text){  var node = document.createTextNode(text);  this.appendChild(node);} // add text nodes to various elementsadd_child.call(document.getElementById('el1'), 'text for el1');add_child.call(document.getElementById('el2'), 'text for el2');

You see that a lot with jQuery code, where this typically gets set to an element that you're working on. jQuery does that by using Function.call or Function.apply to set the scope of the code you write to the elements that you're trying to work with. For example:

// loop through each link and attach a click handler$('ul.nav-tabs li a').each(function() {  // inside this function, this is set to each element that the previous selector matched   $(this).bind('click', function() {    // inside this function, this is set to the element to which the click handler is being attached     // loop through each link to reset the font color    $('ul.nav-tabs li a').each(function() {      // inside this function, this is set to each element that the previous selector matched       $(this).css('color', '#000');    });     // set the color of the selected link    $(this).css('color', '#0088cc');    // get the inner HTML    var html = $(this).html();    // add the checkmark icon if it's not already there    if (html.indexOf('icon-ok') == -1) {      $(this).html('<i class="icon-ok" style="vertical-align:middle"> </i>  ' + html);    }    // hide all definitions    $('#defHolder').children().each(function(){      // inside this function, this is set to each child of the defHolder element       $(this).css('display', 'none');    });     // get the ID to show and show this definition    var id_part = this.id.substr(4); // everything after "btn_"    $('#' + id_part).css('display', 'block');  });});
Link to comment
Share on other sites

I avoid using inline code but occasionally use something like this...

<!DOCTYPE html><html><head><title>this and event</title><script>var out;window.onload = function() {document.getElementById('btn1').onclick = fn1;out = document.getElementById('out');}function fn1(e) {out.innerHTML = out.innerHTML +' '+ this.id +'@('+ e.clientX +','+ e.clientY +')';}</script></head><body><input type="button" id="btn1" value="Button"/><div id="out"></div></body></html>

The scope of variables, at least in Firefox, seems to be very forgiving. In the case above even if I declare the 'out' variable inside another function the fn1 function will find it.

Edited by davej
Link to comment
Share on other sites

As you are using it above, out is simply a global variable. If you use it in a function without also declaring it with the var keyword (as you do in fn1) it will retain the global context. Any changes you make to it in fn1 will affect out globally. If you use the out identifier in a function and do declare it with the var keyword, it is a whole new variable, local to that function, and global out is left alone.

 

I would not call that forgiving. It is entirely to be expected.

Edited by Deirdre's Dad
Link to comment
Share on other sites

I would not do this, but Firefox 21 executes the following with no errors...

<!DOCTYPE html><html><head><title>this and event</title><script>window.onload = function() {init();}function init(){document.getElementById('btn1').onclick = fn1;var out = document.getElementById('out');}function fn1(e) {out.innerHTML = out.innerHTML +' '+ this.id +'@('+ e.clientX +','+ e.clientY +')';}</script></head><body><input type="button" id="btn1" value="Button1"/><div id="out"></div></body></html>
Link to comment
Share on other sites

It's not quite what you think. Try this:

 

<!DOCTYPE html><html><head><title>this and event</title><script type="text/javascript">window.onload = function () {alert(out.innerHTML);}</script></head><body><div id="out">Hi</div></body></html>

I believe that's legacy stuff, and I don't like it at all. :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...