搜索

首页  >  问答  >  正文

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
PHP中文网PHP中文网2816 天前475

全部回复(5)我来回复

  • 大家讲道理

    大家讲道理2017-04-10 14:30:42

    你只需要知道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

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-10 14:30:42

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


    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 巨巨的教导。

    回复
    0
  • ringa_lee

    ringa_lee2017-04-10 14:30:42

    前两个输出的 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 的工作机制》

    回复
    0
  • 迷茫

    迷茫2017-04-10 14:30:42

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

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

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

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-10 14:30:42

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

    回复
    0
  • 取消回复