1

我正在尝试对 javascipt 中的一组对象进行排序。排序顺序本身取决于两个因素:对象的属性和单个外部变量的值。我知道我可以使用 array.sort(sortFunction) 来注入自定义函数,但我需要根据外部变量(在排序期间固定)使用不同的函数。

我将排序减少到显示问题的最小测试用例并尝试注入“降序/升序”参数,尽管真正的问题要复杂得多。我知道我可以 reverse() 结果,但这不是问题。

这是代码:

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;
    }
}

这是输出(使用 Node.js)

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

看起来数组排序代码在排序时提取了父对象之外的函数。

任何想法为什么会发生这种情况以及正确的方法是什么?

更新:我确实找到了让它工作的方法:

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;
    }
}

这是一个好主意吗?还是有更好的东西?

4

3 回答 3

3

ns.sort正在失去它的调用上下文。换句话说,一旦你将它传递给.sort(),它就不再与ns对象有任何联系。

您可以让函数直接引用该对象,方法是让构造函数中的变量指向它,并让排序函数引用该变量。

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;
    }
}

或者,如果您在像 NodeJS 这样的现代环境中,您可以使用Function.prototype.bind()将调用上下文值永久附加到函数中。

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);
}
于 2012-10-27T20:28:52.017 回答
1

你需要使用bind. 请参阅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;
    }
}

简而言之,这就是说“使用排序函数ns.sort但调用它,以便该函数在内部ns用于表达式的值this

于 2012-10-27T20:31:41.143 回答
1

代替bind你也可以使用这个模式(使用闭包):

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 ]

只是为了好玩,这里有一个简化,更“功能”并避免调用上下文问题:

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 ]
于 2012-10-27T20:53:06.387 回答