admin管理员组

文章数量:1334133

I'm reading javascript the good parts, and the author gives an example that goes like so:

['d','c','b','a'].sort(function(a,b) {
  return a.localeCompare(b);
});

Which behaves as expected. Now I have tried to do something like this - which is the next logical step:

['d','c','b','a'].sort(String.prototype.localeCompare.call);

And that fails with an error:

TypeError: object is not a function

Now I left wondering why... Any ideas?

I'm reading javascript the good parts, and the author gives an example that goes like so:

['d','c','b','a'].sort(function(a,b) {
  return a.localeCompare(b);
});

Which behaves as expected. Now I have tried to do something like this - which is the next logical step:

['d','c','b','a'].sort(String.prototype.localeCompare.call);

And that fails with an error:

TypeError: object is not a function

Now I left wondering why... Any ideas?

Share Improve this question asked Dec 11, 2011 at 1:20 Leon FedotovLeon Fedotov 7,8715 gold badges31 silver badges33 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 6

call needs to be bound to localeCompare:

['d','c','b','a'].sort(Function.prototype.call.bind(String.prototype.localeCompare));

The reason you are having a problem is that you are passing sort Function.prototype.call. As you may know, when no this is otherwise provided, it will be the global object (window in browser environments). Thus, when sort tries to call the function passed to it, it will be calling call with this set to the global object, which in most (all?) cases is not a function. Therefore, you must bind call so this is always localeCompare.

The reason it doesn't work is that String.prototype.localeCompare.call returns a reference to Function.prototype.call not to String.prototype.localeCompare as you might think.

You're passing a reference to the call function without retaining any relationship to the localeCompare method you intend it to be called upon. So sort will invoke the function referenced byString.prototype.localeCompare.call, but it will invoke it in the global context, not as the method of some function object.

As @icktoofay pointed out, you need to bind the call function to localeCompare. Here's a much oversimplified demonstration of how this is done without the bind method:

function simpleBind(fn, _this) {
    return function() {
        return fn.apply(_this, arguments);
    }
}

['d','c','b','a'].sort(simpleBind(Function.prototype.call, 
                                  String.prototype.localeCompare));

Ok, solved it! this does the trick:

['d','x','z','a'].sort(String.prototype.localeCompare.call.bind(String.prototype.localeCompare))

Cause when you think about it the sort function actually calls apply on call so it needs to be bound to the string object in order to execute in scope. ^_^

本文标签: javascriptWhy does call does not work as A sort functionStack Overflow