为什么代码中的“this”指向window对象?

4

我的代码是:

var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       fn();
       arguments[0]();
    }
}

o.e(fn);

输出结果是20,1,有谁能告诉我为什么?

请阅读有关 callapply 的相关内容。 - mu is too short
@muistooshort,您是在说fn()arguments[0](),一个调用了call,另一个调用了apply吗? - McGarnagle
1
在第一次调用中,您获得20个 this === window,在第二个中 this===arguments。 将console.log更改为 console.log(this.length, this); 并将其调用为 o.e(fn,'test'); 然后您会看到您得到的参数数组。 - some
1
@dbaseman:这些更多是关于使用显式的this来执行fn()arguments[0]()之所以表现出它的行为,是因为有一个隐藏的点,所以它有点像说arguments.0()(如果后者当然是有效的JavaScript)。 - mu is too short
2个回答

6
this关键字出现在函数内部时,其值取决于调用该函数的方式
在您的情况下,fn()被调用时没有提供this值,因此默认值为window。 使用arguments[0](),上下文是arguments对象,其长度为1
重点不在于函数被调用的位置,而在于函数被调用的方式
var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       fn(); // this will be the window.
       arguments[0](); // this will be arguments object.
    }
}

o.e(fn);

此外,如果您想要将this指向对象o,您可以使用callapply,或者先使用bind绑定一个对象。
var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       var fn2 = fn.bind(this);
       fn.call(this); // this in fn will be the object o.
       fn.apply(this); // this in fn will be the object o.
       fn2(); // this also will be the object o.
    }
}

o.e(fn);

this并不是上下文,它是执行上下文的一个组成部分(在ES5中称为词法环境)。你应该写成“在未提供this值的情况下调用了fn()函数”。将this称为上下文会让人产生困惑。 - RobG
哦,如果代码是在严格模式下,那么如果没有提供值(将为undefined),它将不会将“this”设置为“window”,并且会抛出类型错误。 - RobG
@RobG 是的,在严格模式下,当执行 fn(); 时,它将是未定义的。 - xdazz

2
让我们扩展一下你的代码:
var length = 20;
function fn() {
    console.log(this, this.length);
}

var o = {
    length: 10,
    e: function(fn) {
        fn();
        fn.call(this);
        arguments[0]();
    }
}

o.e(fn);​

演示: http://jsfiddle.net/ambiguous/Ckf2b/

现在我们可以看到,当调用fn时,this指的是什么(因此this.length来自哪里)。这给我以下输出:

DOMWindow 0
Object 10
[function fn() { console.log(this, this.length); }] 1

我们有三种调用函数fn的方式:
  1. fn(): 像任何普通函数一样直接调用。
  2. fn.call(this): 使用call来强制指定上下文(即this)。
  3. arguments[0](): 通过arguments对象调用fn
当你使用fn()时,视野中没有明确的this值,因此在浏览器中,您会得到window作为您的this。全局的window恰好有一个length属性

返回窗口中帧(frame)或 iframe 元素(frame 或 iframe元素)的数量。

这就是我的输出中的零(零可能会因您的window.length而异)。
我们使用e来调用o.e(fn),因此e内部的thiso,这就是o.e(...)的意思(除了绑定函数和相关复杂性)。因此,在fn.call(this)中的thiso,这使得fn.call(this)o.fn = fn; o.fn()大致相同,我们在控制台中获得了o10。注意那个点再次出现了吗?

fn.call(o)就像o.fn = fn; o.fn()

第三种方法arguments[0]()包含一个隐藏的点,因为p = 'm'; o[p](大致)等价于o.m,所以arguments[0]()就像fn = arguments[0]; arguments.fn = fn; arguments.fn()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接