什么叫this的值不能维持

最近在看《JavaScript》高级程序设计,有一段不是特别了解

  var name = 'The Window';
    
    var object = {
        name : 'My Object',
        getName : function(){
        return this.name;
        }
    }
    (object.getName = object.getName)();//输出The Window

书上说是因为这个表达式的值是函数本身,所以this的值得不到维持,结果就返回了'The Window'
我想请问一下为什么结果会是The Window?
书上这句话又是什么意思?
谢谢。

阅读 3.1k
3 个回答

this与调用方式的关系。。
1.作为函数调用
2.作为方法调用
3.构造函数与new的组合
4.call apply bind this的绑定
5.箭头表达式的
。。。你记住了五种情况,弄清楚了。。这题就明白了。

为什么这么书都喜欢发明一下乱七八糟的概念。

this的值主要是看如何调用这个函数。obj.fn() 里面的thisobj
(object.getName = object.getName)()相当于 var temp = object.getName = object.getName; temp(); 这样调用this当然是 window

详见 http://zonxin.github.io/post/...

下面内容出自 http://www.cnblogs.com/aaronj...

var x = 10;
var foo = {
    x: 20,
    bar: function () {
        var x = 30;
        return this.x;
    }
};

console.log(
    foo.bar(),             // 1.
    (foo.bar)(),           // 2.
    (foo.bar = foo.bar)(), // 3.
    (foo.bar, foo.bar)()   // 4.
);

我们一句一句的分解

foo.bar()

这个很简单,直接调用bar 方法,此时的上下文就是foo对象,所以this.x = 20 return 的结果也就是20了

(foo.bar)()

我们看看括号的定义 ECMA语言规范

11.1.6 The Grouping Operator

The production PrimaryExpression : ( Expression ) is evaluated as follows:

    1. Evaluate Expression. This may be of type Reference.
    2. Return Result(1).

NOTE 

This algorithm does not apply GetValue to Result(1). The principal 
motivation for this is so that operators such as delete and typeof 
may be applied to parenthesised expressions.

引用类型的值与函数上下文中的this值如何相关?——从最重要的意义上来说。 一个函数上下文中确定this值的通用规则如下:

在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。注:第5版的ECMAScript中,已经不强迫转换成全局变量了,而是赋值为undefined。

这是对组操作符的描述,说明得到的结果是一个 Reference 引用类型

alert( foo.bar === (foo.bar) )   //true

关于引用类型的解释,参考 http://dmitrysoshnikov.com/

(foo.bar = foo.bar)(),

查了查资料,我们先看看

var foo = { 
     bar: function () {    
              alert(this);    
              alert(this === foo); 
     }
};
 
foo.bar(); // foo, true

var exampleFunc = foo.bar;

alert(exampleFunc === foo.bar); // true

// 再一次,同一个function的不同的调用表达式,this是不同的
exampleFunc(); // global, false

可见将foo.bar的引用赋给一个变量,在执行的时候,这个this的指向就被改变了

重点(=)赋值是如何处理的?

不懂就翻规范呗,又去找找ECMA语言规范

11.13.1 Simple Assignment (= )
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

1. Evaluate LeftHandSideExpression.

2. Evaluate AssignmentExpression.

3.Call GetValue(Result(2)).

4.Call PutValue(Result(1), Result(3)).

5.Return Result(3).
8.7.2 PutValue(V, W)

1. If Type(V) is not Reference, throw a 
   ReferenceError exception.
2. Call GetBase(V).
3. If Result(2) is null, go to step 6.
4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) 
   for the property name and W for the value.
5. Return.
6. Call the [[Put]] method for the global object, passing 
   GetPropertyName(V) for the property name and W for the value.
7. Return.

我也没有看太明白, 还要慢慢消化,但是大体的定义

赋值运算符调用了GetValue方法。返回的结果是函数对象(但不是引用类型),这意味着this设为null,结果是global对象

语句返回的是 foo.bar 的函数值

因此,赋值操作符返回的是「值(Value)」而不是「引用(Reference)」。

因为函数体需要 this 值获取 x 属性的值,那么接下来我们考虑改函数时调用时的上下文作用域以及背后的具体流程。 尤其注意第七条规则

...
6. If Type(Result(1)) is Reference, Result(6) is GetBase( Result(1)). 
    Otherwise, Result(6) is null.
7. If Result(6) is an activation object, Result(7) is null. Otherwise,
    Result(7) is the same as Result(6).
8. Call the [[Call]] method on Result(3), providing Result(7) as 
    the this value and providing the list Result(2) as the 
    argument values.
…

那么在这种情况下,GetBase 操作实际上返回的是 null,因此此条语句函数执行的作用域为 global ,在浏览器中也就是 window 。

(foo.bar = foo.bar)()
那么,上面的语句中我们可以得知

Grouping Operator 中的赋值语句返回的是 foot.bar 的函数值(「Value」)
该函数执行的上下文作用域为 window
找了几篇相关文章具体参考:

http://www.w3.org/html/ig/zh/...

http://www.cnblogs.com/TomXu/...

(foo.bar, foo.bar)()

逗号运算符和逻辑运算符(OR)调用了GetValue 方法,相应地,我们失去了引用而得到了函数。并再次设为global。

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