Injecting object instead of function for Javascript array sort

I'm trying to sort an array of objects in javascipt. Sort order itself depends on two factors: object's properties and a value of a single external variable. I know that I can use array.sort(sortFunction) to inject custom function, but I need to use a different function depending on the external variable (which is fixed during sorting).

I reduced the sorting to minimal test case which shows the problem and trying to inject "descending/ascending" parameter, although the real prolem is much more complex. I know I can reverse() the result, but that's not an issue here.

Here's the code:

var ar = [ 10, 3, 5, 17 ];
var ns = new nsort();
ar.sort(ns.sort);
console.log(ar);

function nsort()
{
    this.desc = true;
    this.sort = function(a,b) {
        console.log(this.desc);
        if (this.desc)
            return b-a;
        else
            return a-b;
    }
}

and here's the output (using Node.js)

undefined
undefined
undefined
undefined
[ 3, 5, 10, 17 ]

It looks like array sorting code extracts the function outside of parent object while sorting.

Any ideas why is this happening and what would be the proper way to do it?

Update: I did find a way to make it work:

var ar = [ 10, 3, 5, 17 ];
var ns = new nsort(true);
ar.sort(ns.sort);
console.log(ar);

function nsort(desc)
{
    this.sort = function(a,b) {
        if (desc)
            return b-a;
        else
            return a-b;
    }
}

Is this a good idea? Or is there something better?

Your ns.sort is losing its calling context. In other words, once you pass it to .sort(), it no longer has any connection to the ns object.

You can have the function reference the object directly by making a variable in the constructor point to it, and having the sort function reference the variable.

function nsort()
{
    this.desc = true;
    var self = this;
    this.sort = function(a,b) {
        console.log(self.desc);
        if (self.desc)
            return b-a;
        else
            return a-b;
    }
}

Or if you're in a modern environment like NodeJS, you can use Function.prototype.bind() to permanently affix the calling context value to the function.

function nsort()
{
    this.desc = true;
    this.sort = function(a,b) {
        console.log(this.desc);
        if (this.desc)
            return b-a;
        else
            return a-b;
    }.bind(this);
}

You need to use bind. See http://jsfiddle.net/fub49/.

var ar = [ 10, 3, 5, 17 ];
var ns = new nsort();
ar.sort(ns.sort.bind(ns));
console.log(ar);

function nsort() {
    this.desc = true;
    this.sort = function(a,b) {
        console.log(this.desc);
        if (this.desc)
            return b-a;
        else
            return a-b;
    }
}

In a nutshell this says "use the sorting function ns.sort but call it so that internally that function uses ns for the value of the this expression.

In stead of bind you could also use this pattern (using a closure):

function nsort(desc)
{
   desc = desc || false;
   this.setDesc = function(val){desc = val; return this;}
   this.sort = function(a,b) {
        return desc ? b-a : a-b;
   }
}
var ar = [ 10, 3, 5, 17 ]
   ,ns = new nsort();
ar.sort(ns.sort);
console.log(ar); //=> [ 3, 5, 10, 17 ]
ar.sort(ns.setDesc(true).sort);
console.log(ar); //=> [ 17, 10, 5, 3 ]

Just for fun, here's a simplification, more 'functional' and avoiding the calling context problem:

function nsort(desc)
{
  return function(a,b){
       return desc ? b-a : a-b;
  };
}
var ar = [ 10, 3, 5, 17 ];
console.log( ar.sort(nsort()) );     //=> [ 3, 5, 10, 17 ]
console.log( ar.sort(nsort(true)) ); //=> [ 17, 10, 5, 3 ]