this对象的输出问题

var name = "this window";
var object = {
    name: "my object",
    getNameFun: function(){
        // return function(){
            return this.name;
        // }
    }
}
console.log((object.getNameFun = object.getNameFun)()); //输出“this window”
console.log(object.getNameFun());//输出my object

上例中object.getNameFun = object.getNameFun)()是何意?为什么会输出this window?

var test;
var test1 = function test(){
    var name = "test";
    return function(){
            var name = "test1";
        return function(){
            console.log(name);
        }
    }
}
console.log(test);  //输出为undefined
console.log(test1); //输出为test函数

为什么上述代码中不能正确输出test,而是显示undefined,但是输出test1的时候却又正常输出test的呢?
一开始以为是test1替代了test,指向了这个函数结构,test指针所以为undefined,但是却发现输出test1不是匿名函数,而是test()函数?
求教~

阅读 4k
7 个回答

搞懂这个问题当然要看ES规范,单纯考猜测和看一些书是不行的。

这个问题有两个关键点:

  • 赋值表达式

  • (命名的)函数表达式

我们分别来看一下:

第一个问题:

(object.getNameFun = object.getNameFun)();

首先是一个赋值表达式,然后是一个函数调用表达式。

首先看赋值表达式,根据规范:

https://es5.github.io/#x11.13.1

赋值表达式一共六个步骤,其他的不管,关键看第六步:表达式的结果就是rval

这个rval是第三步得到的也就GetValue(rref)。这个操作将一个引用类型取值了。相当于把object.getNameFun中的object.信息丢掉了,只返回了它的真实值,也就是那个函数对象。

最终相当于:

(function() {
    return this.name;
})();

结果很明显了。

第二个问题:

实际上定义了一个命名的函数表达式

见:https://es5.github.io/#x13 中的第三种形式。而且规范里专门说了:

带identifier的函数表达式,它的名字(也就是identifier)只能在函数体内可见。

所以,test在外部是undefined也非常明显了。不信你在函数体内打印一下。

  1. (object.getNameFun = object.getNameFun)()其中object.getNameFun = object.getNameFun是废话,自己赋值给自己,也就是说这句话的意思其实就是object.getNameFun(), 但是调用链却变成了全局对象中的方法被调用

  2. this是关键字,是当前对象的引用值,什么是引用值?看看基础语法吧。

  3. 输出undefined的原因是你没有给test变量赋值。

  4. var test1 = function test(){},你已经都给test1赋值为test函数的引用了。

  5. var test1 = function () {},这才是匿名函数。

多看看基础语法书吧...

先回答第一个问题,在getNameFun里面加入console.log(this)后,重新执行你的方法

clipboard.png

可以看到,第一次执行时,这里应该是一个自执行函数,实际this指向的是Window全局对象,而第二次执行时,实际this指向的是object这个方法
这里是我理解错误了,这里应该可以理解为讲obejct.getNameFun赋值给obejct.getNameFun,然后执行,这是它的作用域就是指的window对象,而第二次是调用了object的getNameFun方法,它的作用域就是object对象

关于第二个问题,你可以看看这个:

函数声明与表达式

clipboard.png

新手上路,请多包涵

1.(object.getNameFun = object.getNameFun)()的作用是把函数赋给一个变量的同时执行此函数(也就是说,是单纯的执行一个函数,而不是到对象object里去执行getNameFun函数),在此时上下文环境是Window,而不是object。
为避免引起歧义,应该尽量不使用这种方式。

2.test是未赋值的变量,test1是函数,虽然函数名虽然是test但是在定义之初就赋值给了test1,所以函数test是没有生效的,test还是原先定义的变量

第1段代码:

var name = "this window";
var object = {
    name: "my object",
    getNameFun: function(){
        // return function(){
            return this.name;
        // }
    }
}
console.log((object.getNameFun = object.getNameFun)()); //输出“this window”
console.log(object.getNameFun());//输出my object

(object.getNameFun = object.getNameFun)()
我们先看一个括号运算符(object.getNameFun = object.getNameFun)object.getNameFun绑定的函数对象赋值给object的getNameFun,这个没什么,关键点在于赋值运算符是否返回值得。这个赋值运算结束后返回的结果为object.getNameFun指向的函数对象;后面的括号,就是这个函数的调用运算符。
和下面的代码等价

var someFun=object.getNameFun = object.getNameFun;
(someFun)();

此时someFun调用时其this对象是全局对象,故输出结果为'''this window'''
这个和(object.getNameFun)();调用是有区别的;
(object.getNameFun)()等同于object.getNameFun()

第2段代码:

var test;
var test1 = function test(){
    var name = "test";
    return function(){
            var name = "test1";
        return function(){
            console.log(name);
        }
    }
}
console.log(test);  //输出为undefined
console.log(test1); //输出为test函数
var test1 = function test(){
    var name = "test";
    return function(){
            var name = "test1";
        return function(){
            console.log(name);
        }
    }
}

是一个函数声明方式-函数表达式方式,其中的函数名是可选的。一旦使用函数名,这个函数名只在当前函数作用域内有效。所以console.log(test); //输出为undefined,console.log(test1); //输出为test1的函数的字符串
把代码修改下能看的更清楚些

var test=function(){
    console.log('this outside test function');
};
test.myProp="outside test function";
var test1 = function test(){
    var name = "test";
    test.myProp="inner test function"
    console.log(test.myProp);//输出inner test function
    return function(){
        var name = "test1";
        return function(){
            console.log(name);
        }
    }
}
console.log(test());  //输出this outside test function
console.log(test.myProp);  //输出outside test function
console.log(test1()); //输出inner test function及test1函数返回的匿名函数的字符串表示

问题一:(object.getNameFun = object.getNameFun)()是何意?为什么会输出this window?

object.getNameFun = object.getNameFun这条表达式将object.getNameFun赋值给自身,结果是输出了一个匿名函数:function () { return this.name; }

(object.getNameFun = object.getNameFun)()意为直接调用这个匿名函数,由于前面没有指定调用对象,因此调用对象默认为全局对象window,this.name指向的是第一行定义的name,所以输出'this window'。

问题二:为什么test为undefined?

第一行var test;声明了test变量但未赋值,因此test默认为undefined。而下面的var test1 = function test() {...}是一个函数赋值表达式,其中的函数名test对外部是不可见的(详细原理可以参考JS的函数表达式机制),不会取代外部的test变量,因此test变量始终为undefined。

问题三:为什么test1输出的是函数test()?

正如上面所说,函数表达式中指定了函数名test,对外部不可见,但对内部是可见的。test1引用了该test()函数,因此test1输出的也是function test() {...}

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