Well, if you are programming in JavaScript for a while, you are familiar with the arguments ‘array’ which gives you access to function arguments by index, without the need of argument names. And if you are programming JavaScript for a bit longer while, you will know that arguments is not even a normal array. It does not have any methods of an array. You can just use it to access items by index and also access it’s length property. That’s all. What if you want to make a copy of the array? What if you want to push or pop items? Well… you have some work to do… OR …

Or do something smart. Like call the slice method from Array.prototype on the arguments, something like:

//this makes a copy of the arguments and returns a true array
Array.prototype.slice.call(arguments, 0) 

//pushes the value '5' in the arguments
Array.prototype.push(arguments, 5) 
//this is not valid: arguments.push(5)

Well, maybe most of you expert JavaScript programmers have thought about this, and this is not a news. But, let’s share from our experience to the more novice/newcomers to JavaScript and show them the beauty of this language!

JavaScript is a great language! It’s expressive! It’s powerful! That’s why we love JavaScript.

You should make use of the scope config option in components

.

  • in Ajax calls
    var MyPanel = Ext.extend(Ext.Panel, {
        doSave: function(){
    	Ext.Ajax.request({
    	    url: 'your_url',
    	    params: ....
    	    success: function(response){
    		response = Ext.decode(response.responseText);
    		this.onSuccess(response)
    	    },
    	    scope: this //the scope in which the success callback is called
    	})
        },
        onSuccess: function(){ .... }
    }

    In this example, specifying the scope is very useful. By default, the success callback on Ajax calls is executed with the scope being the browser ‘window’ object, which is not very useful. In the code above, we execute the success callback in the ‘this’ scope, ‘this’ being the instance of MyPanel which executes the doSave method. This is why we can safely call this.onSuccess(response), as ‘this’ is a MyPanel object, which has the onSuccess method.
    I find the scope config property very useful, so even though specifying the scope of a function is very natural in JavaScript, the fact that ExtJS made it so natural and easy deserves being noted. Well done ExtJS!

  • in Buttons
    {
        xtype: 'button',
        text: 'Save',
        handler: function(){
    	//do something on pressing the button
        },
        scope: myScope //scope of the handler
    }
  • with Stores
    new Ext.data.Store({
        //...other config options
        autoLoad: {
    	callback: function(){ ... },
    	scope: aScope //for the callback function after loading the store
        }
    })
  • in listeners
    new Ext.Panel({
        listeners: {
    	scope: window, //the scope of all listeners in this config
    	show: function(){ ... },
    	afterrender: function(){ ...this is 'window' }
        }
    })
  • in actions

What is really fascinating about JavaScript is it’s dynamic nature. You can dynamically change the behaviour of the code… even not your code. While this is really powerful, it can be also a pain if not used with care.

Well, let’s do something practical now. I want to intercept every log message in my js application. As people usually use Firebug (and if you’re not using it… well, you should, so start right here), the javascript code is populated with console.log or console.warn messages. Say we want to execute a function before and after console.log is called. Test the following code within firebug.

var backup = console.log;

function beforeLog(){
    backup('before log:',arguments);
}

function afterLog(){
    backup('after log:',arguments);
}

console.log = function(){
    beforeLog.apply(this,arguments);
    backup.apply(this,arguments);
    afterLog.apply(this,arguments);
}

console.log('hello','world');

In the first place, make a backup to the function we want to intercept.

Second, just redefine the function… and we usually want to execute the old function (so here is where we need the backup) and perform some additional things as well. Placing the code at the beginning of your coolest app changes the behaviour of all the log messages you have.

I found this useful when going from a development environment to a live environment. The best choice would be to use a build system to comment out (or even better, delete) all the console.log() calls. But a quick fix when going live is the following:

if (!window.console){
   /*
    * for users who do not have firebug installed, 
    * just define a "mock" console object
    */
    window.console = {};
}
window.console.log = function(){};
console.log('hello world'); // call to an empty function

This is just a simple use of dynamically changing the behaviour of existing code. What about you? How do you intercept function calls? Waiting for some nice suggestions.