为什么 arguments[0]() 这个输出的是 undefined ?

哪位大神帮我看看,为什么arguments[0]() 这个输出的是 undefined ?
fn()这个会输出10,为什么 arguments[0]() 就是 undefined 呢?

    var len = 10;
    var obj1 = {
        len:6,
        method:function(){
            console.log(this.len);
        }
    };
    var obj2 = {
        len:5,
        method:function(fn){
            fn();// 这里输出10
            arguments[0](); // 这里为什么输出undefined
        }
    };

    obj2.method(obj1.method,obj2.method);
阅读 7.2k
10 个回答

arguments[0](); 的 this 绑定的是 arguments。

window['1'] = 'a';
var obj = {
   '1' : 'b',
    fun : function(){
        return this[1];
    }
}

function test1(fun, arg){
    console.log(fun());    //a,this == undefined, this = window
    console.log(arguments[0]());    //c,this = <Object>arguments
}

test1(obj.fun, 'c');

为了避免歧义,再更新一下:

为什么 arguments[0] 和 <参数>fun 指向的函数都一样,结果却不同呢?
这个和 arguments 和 fun 没有关系,因为 arguments 是一个数组,数组也是一个 Object。

({ len:6, method: function(){console.log(this.len);}}).method(); //6

同为 Object 的 Array,this 同样也是指向自身的。

[function(){console.log(this[1]);}, 6][0](); //6

this和定义无关,和函数的调用方式有关。把函数当成参数传入,调用的时候直接调用,里面的this就是全局对象。

var arr = [function(){console.log(this)}];
arr[0]()
[function]

好神奇,这中方式调用this居然是arr自身。


再更新一次

var obj = {method : function(){console.log(this)}}
obj.method()
obj['method']()

对于这么一个对象,下面两个方法调用this应该都是指向obj本身,只不过对arguments对象而言,这个对应上面调用方式的method恰好是个数字0,把上面代码重写一下:

var obj = {0: function(){console.log(this)}}
obj[0]()

这不就和arguments[0]()调用方式不是一样吗?this必然是arguments对象了。

不好意思,楼上(或楼下,这里的楼会跳来跳去)回错了。

为何arguments[0]()输出是undefined,fn()是输出是10。

注: 开了严格模式后fn()的this是undefined,结果也是undefined。如果没开fn()的thiswindow物件,fn()的结果是10。

问题是在console.log(this.len);而不是return值的问题,这问题不干return的事,都是console.log()

你把obj.method代入到obj2.method里,应该有看到在主控台中fn的长像,arguments[0]也是一样的,像下面这样:

function(){
   console.log(this.len);
}

然后你就直觉的认定,这个this.len就是你的obj1中的那个定义好的this.len是吧?

实情不然,因为呼叫时this并不代表obj1(也不是obj2),this.len当然也不是obj1中的this.len

回到本质的问题,this是什么,this是函数呼叫时,代表谁(对象/物件)呼叫了它。我指的是"呼叫"(或调用),不是函式定义值的传递,obj1.method这叫函式定义的值传递,obj1.method()这样叫函式的呼叫(或调用)。

因此,只有像obj1.method()这样的呼叫(或调用),this才会指向obj1。以你的代码来说,你可以在后面加上以下这两行语句,看是不是如我加注的结果:

obj1.method(); //6
obj1.method.call(obj2); //5

第1行的obj1.method()呼叫时,method里的this指向obj1,所以this.len相当于obj1.len。所以是6。

第2行的obj1.method.call(obj2);用了函数中的call方法,用来转向上下文,也就是this转向到obj2去。所以虽然是用的是obj1.method里的代码,但this是指向obj2this.len相当于obj2.len,所以是5。

对照一下我上面说的,原来的代码中的arguments[0]()fn()的呼叫(调用)时,其中的this是arguments[0]()指向自身,fn()指向window物件(一般情况下),输出this.len的结果就不是预期的5或6。


上面回答的不好,采纳的答案中写的是正确的。下面再补充一下。

因为我忘了数组中的this是自动指向自身这件事,所以只有靠函式本身的call、bind、apply才能转换this
如同下面的例子这样:

var obj = {foo:1};

function a(fn){
    fn.call(obj); //1
    arguments[0].call(obj); //1
}

function b(){
    console.log(this.foo);
}

a(b);

关于数组中的函数成员值的this会指向自己本身,是因为数组是对象类型,使用var a = []相等var a = new Array(),是用建构式样式来建立实例。但如果是用对象文字字面定义的对象中函数成员并不会指向自己。从下面的例子可以测试:

var func = function(){
      console.log(this);
    console.log(this[1]);
};
  
var arr = new Array();
arr.push(func);
arr.push(3);
arr[0]();

var arr2 = []
arr2.push(func);
arr2.push(55);
arr2[0]();

注: arguments并不是个数组,而是个类数组(array-like)的对象,数组本身也是个对象,对象的特性也是同上例,因为也是用new关键字产生实例的。不过关于arguments的好与坏又是另一个议题了,离题不作讨论。

以上,供参考。

因为fn定义在arguments里时,this指的是arguments这个类数组对象,而arguments里没有len这个属性,所以undefined;你是在之前说上一个arguments["len"]="aaa",那么就是打印出"aaa"而不是undefined了

新手上路,请多包涵

因为arguments[0]()调用的是obj1.method, 而obj1.method的function你没有return值。 函数没有写return时,默认返回undefined. 给obj1.method return个值arguments[0]();就不会是undefined了

还是不太明白,fn() 其实就是在全局作用域下调用 obj1.method。arguments[0]()这样的调用和 fn()不一样吗?我最开始认为都会输出 10, 结果不是。

数组调用了函数,所以this指向了数组

新手上路,请多包涵

arguments并不是一个数组,只是一个具有length属性的对象,楼主别搞错了。

arguments[0]()还是
执行的function(){

        console.log(this.len);
    }

现在this指向的arguments这个对象,他是个类数组,里面有length这个属性,但是,没有len这个属性,所以得到的是undefined。
如果console.log(this.length);他会是实参集合的长度,就你写的这段代码,会在控制台输出2.

我感觉 arguments[0]()输出 undefined 这个更容易理解,因为arguments是一个对象,并不是一个正常的数组,但是有length属性,所以可以读取 [0],js语言精粹里面对于函数有说:当一个函数被保存为对象的属性时候,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。 所以arguments[0]作为一个方法被调用的时候,this对象指向 arguments,所以是undefined
前面的fn(),这个情况书里也有说明:当一个函数并非一个对象的属性时,那么它被当作一个函数来调用,此时,this被绑定到全局对象。 fn()这里在传参过程中并没有使用bind绑定作用域,已经是一个独立的函数,类似于

var fn = obj1.method 

fn被调用的时候是作为一个函数调用,所以this指向window。
这个相对应该更难理解一些,因为这个其实是语言设计上的一个错误,如果语言设计正确,内部函数被调用,this应该仍然绑定到外部函数的this变量。但是已经成事实了。

不过我们有办法可以修改作用域,调用fn时候 fn.call(this);这里的this指向obj2

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题