在空数组上调用Array.prototype.reverse()?

时间:2014-02-24 04:08:44

标签: javascript

注意:此问题中的代码是在Chrome控制台中运行的。

我在做JS-puzzler问题21时遇到了这个问题(好吧......虽然没有给出排序)。问题是关于结果:

var x = [].reverse; x();

,答案是window。正如答案所述:

  

[] .reverse将返回此值,并且在没有显式接收器对象的情况下调用时,它将默认为默认的此AKA窗口。

基于这种理解,我写了一些代码来测试:

function Bar(){
  var x = [].reverse;
  console.log(x());
}
new Bar();

猜猜是什么..这段代码引发了错误:

  

TypeError:在null或undefined

上调用Array.prototype.reverse

我想问为什么new Bar中调用的x()没有显示this对象,而是提出异常?

3 个答案:

答案 0 :(得分:5)

当您在x()中调用函数时,this指针将设置为windowundefined(在严格模式下)。调用函数的方法是确定this的值。

让您控制this的值的调用方法是:

x.call(xxx)
x.apply(xxx)
foo.x()

呼叫为:

x()

会将this设置为普通JS模式下的window或严格模式下的undefined的默认值。

您可能想要了解的另一件事是,一旦您这样做:

var x = [].reverse;

然后,x仅保留对reverse()函数的引用。与您最初使用的[]完全没有关联。因此,当您调用x()时,您只是调用没有对象关联的reverse()函数,因此this被设置为普通JS中的window的默认值模式或JS严格模式下的undefined

答案 1 :(得分:1)

这是因为您在没有执行范围的情况下获得了函数引用。 reverse函数在其源代码中引用this。如果你正确地调用了一个函数:

var obj = {
    run: function() { console.log(this) }
};

obj.run(); // this will be obj, as expected

但如果你这样称呼它:

var broken = obj.run;
broken(); // this will be the global object

这就是javascript执行在范围方面的工作方式。在对象上调用带点符号的函数将使this成为它所在的对象。

如果您使用的是现代浏览器,则可以bind this的价值{/ 1}}:

var arr = [1,2,3];
var boundReverse = arr.reverse.bind( arr );

boundReverse() // [3, 2, 1]

答案 2 :(得分:0)

原始问题是关于以下代码的输出。

var x = [].reverse;
x();

但上面代码段的输出是

Uncaught TypeError: Array.prototype.reverse called on null or undefined

实际上,等效的调用给出了同样的错误:

Array.prototype.reverse.call();

所以,关于JavaScript Puzzler的问题的答案是不正确的。虽然Array.prototype.reverse返回this,但代码段仍然会因缺少关联对象而引发错误。

如果测试人员通过var了解了函数定义,则可以使用此问题进行测试,其中var仅保存方法并删除关联对象。

解决方案:(通过调用绑定关联对象)

// An associated object can be bound as below.
   var x = [].reverse;
   x.bind([1,2,3])();
// output : [3,2,1]
// equivalent to 
   Array.prototype.reverse.call([1,2,3]);