首页 > 谁能来解释下javascript this的问题?

谁能来解释下javascript this的问题?

var x = 10;

一下四个输出第一个和第二个勉强能看懂,第三个和第四个真是理解不了,不明白什么意思

一直听说this指向的是它的所有者,在这个地方套用了下感觉也不太成立

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

console.log(foo.bar()); // 20

console.log((foo.bar)()); // 20

console.log((foo.bar = foo.bar)()); // 10

console.log((foo.bar, foo.bar)()); // 10

好像被题主引用了呢,尝试重新解释一下吧。。


JavaScript中其实也是分值类型引用类型的。

一般来说,取引用的值直接取值的含义是一样的:
比如说在foo = { bar: 233 }的前提下

console.log(foo.bar)

console.log(233)

的含义是一样的。

但是有三个运算符是例外的:
- 赋值号:foo.bar = 874233 = 874意义是不一样的(后者不符合语法)
- deletedelete foo.bardelete 233意义是不一样的(后者不符合语法)
- 函数调用:即this的问题,题主很清楚的

当我们对引用类型进行操作之后,(在把结果赋给新的引用之前)会自动将引用类型转换为值类型。
这里的操作包括使用函数调用(实参转换为形参的过程),也包括使用运算符(对于原gist就是赋值运算符=和逗号运算符,),也包括

再举一个函数调用将引用类型转换为值类型的例子:

var x = 10
var foo = {
  x: 20,
  bar: function () {
    console.log(this.x)
  }
}

function execute(func) {
  func();
}

foo.bar() // => 20
execute(foo.bar) // => 10

可以看出,foo.bar这个函数对象当经过函数调用(实参foo.bar转换为形参func)之后,引用类型被转换为值类型,this对象发生变化。

感谢微博上的 @寒冬winter 巨巨的教导。


感觉这不应该是js的正确写法,模糊不清。

相对还是喜欢Ruby一些,比较清楚。

各种刁钻的写法没必要过分关注吧。


你只需要知道this总是指向调用对象的就可以了,然后我们来分别理解下面的代码:

1. 不多做解释
2. 就相当于foo.bar(),此时的调用对象是foo,那么this.x=foo.x=20
3. (foo.bar = foo.bar)()因为先有一个符号运算,所以相当于如下代码:var fuc = (foo.bar = foo.bar); fuc();而根据 ECMA手册 所述:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let rref be the result of evaluating AssignmentExpression.
  3. Let rval be GetValue(rref).
  4. Throw a SyntaxError exception if the following conditions are all true:
    • Type(lref) is Reference is true
    • IsStrictReference(lref) is true
    • Type(GetBase(lref)) is Environment Record
    • GetReferencedName(lref) is either "eval" or "arguments"
  1. Call PutValue(lref, rval).
  2. Return rval.

我们知道赋值运算总返回右边的值。此时的fuc = function () { x = 30; return this.x; }。运行fuc()就相当于普通的定义一个函数执行,调用的是全局对象window,那么此时的this.x = window.x = 10

关于等号赋值的文章还可以看看这篇:http://cmc3.cn/n/217.html

4.(foo.bar, foo.bar)()同样先有一个符号运算,所以相当于如下代码:var fuc = (foo.bar, foo.bar); fuc();而根据 MDN手册 所述:

The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.

我们知道了逗号运算总是返回最后一个的值。此时的fuc和第三个是一样的fuc = function () { x = 30; return this.x; },所以结果和第三个是一样的。

关于逗号运算的文章还可以看看这篇:http://www.feeldesignstudio.com/2013/09/javascript-comma-operator


this具体指向谁,是在这个函数执行时动态确定的,而不是在函数定义时确定的。
同样,Function.apply和Function.call方法均可以动态绑定this。


前两个输出的 this 指向当前对象,所以输出 20,且题主已理解,所以不多解释。
而第三个和第四个,(foo.bar = foo.bar)()(foo.bar, foo.bar)() 实际上就是

(function () {
    var x = 30;
    return this.x;
})() 

由于这里的 x 前使用 var,所以匿名函数内部的 x 与 外部变量 x 不同,立即执行函数中的 this 此时指向全局对象,所以 this.x 的值为 10。如果 foo 定义为:

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

此时第三个和第四个例子的输出应为 30

this 总共五种情形,建议题主阅读我译的博文:

《细说 Javascript 函数篇(二) : this 的工作机制》

【热门文章】
【热门文章】