【问题标题】:How does the "this" keyword in Javascript act within an object literal? [duplicate]Javascript 中的“this”关键字如何在对象文字中起作用? [复制]
【发布时间】:2012-11-06 15:17:54
【问题描述】:

我见过How does "this" keyword work within a function?,但我没有看到它回答了以下问题。

鉴于此代码:

var MyDate = function(date) {
    this.date = date;
};

var obj1 = {
    foo: new Date(),
    bar: new MyDate(this.foo)  //  this.foo is undefined
};

var obj2 = {};
obj2.foo = new Date();
obj2.bar = new MyDate(this.foo);  //  this.foo is undefined

var obj3 = {
    foo: new Date(),
    bar: new MyDate(obj3.foo)
};

var obj4 = {};
obj4.foo = new Date();
obj4.bar = new MyDate(obj4.foo);

为什么前两次尝试失败,但最后两次成功?如果this 没有绑定到当前对象字面量,它绑定到什么?

【问题讨论】:

  • 您不能在 javascript 对象中使用 this 关键字。
  • @minitech - 是的,我怀疑它依赖于实现,但我没有查看规范来确认。也许它应该这样工作。
  • #3 有效,因为它只是一个常规的闭包。
  • @MarkReed:不,它没有,我没有检查我的页面是否有以前定义的a :D
  • @MarkReed:它不依赖于实现。它根本行不通。

标签: javascript


【解决方案1】:

Javascript 是一种后期绑定语言。事实上,它是很晚的绑定。 this 不仅在编译期间没有绑定,甚至在运行时也没有绑定(就像大多数其他后期绑定语言一样)。在 javascript 中,this 在调用期间被绑定。

绑定规则与大多数其他 OO 语言完全不同,这就是为什么它似乎让很多不熟悉 javascript 的人感到困惑。

基本上,您在代码中使用this 的方式和位置不会影响this 的行为方式(不管它是独立函数、对象文字等),决定this 值的因素是如何调用函数。

规则是:

1 - 当函数作为构造函数调用时,会创建一个新对象并将this 绑定到该对象。例如:

function Foo () {
    this.bar = 1; // when called with the new keyword
                  // this refers to the object just created
}
new Foo().bar;

2 - 当作为对象方法调用时,this 指的是该方法所属的对象。基本上是最后一个点之前的名称。例如:

foo.bar = 1;
foo.baz = function () {
    alert(this.bar); // this refers to foo when called as foo.baz()
}
foo.baz();

3 - 如果在任何函数之外使用,或者如果函数没有作为方法调用,this 指的是全局对象。 javascript 规范没有给全局对象命名,只是说存在一个,但对于浏览器,它传统上称为window。例如:

bar = 1;
alert(this.bar); // this refers to the global object
foo = {
    bar: this.bar // also global object
}
function foofoo () {
    alert(this.bar); // also refers to the global object
}
foofoo();

4 - 在事件处理程序中(例如 onclick 等)this 指的是触发事件的 DOM 元素。或者对于与 DOM 无关的事件,例如 setTimeout 或 XMLHTTPRequest,this 指的是全局对象。例如:

foo.bar = 1;
foo.baz = function () {
    alert(this.bar); // this would normally be foo but if this
                     // function is assigned to an event it would
                     // point to the element that triggered the event
}
somediv.bar = 2;
somediv.onclick = foo.baz; // clicking on somedive alerts 2 instead of 1

5 - 最后,当使用call() 或apply() 方法调用函数时,this 可以重新分配给任何东西(谷歌“mdn function.prototype.call”) .这样,javascript中的任何对象都可以借用/窃取另一个对象的方法。例如:

cat = {
    type: "cat",
    explain: function () {
        return "I am a " + this.type;
    }
}
dog = {
    type: "dog"
}
cat.explain.call(dog); // returns "I am a dog"

在现代 javascript 实现中使用Function.bind(),我们现在有了另一条规则:

6 - 函数还可以使用bind() 方法将this 显式绑定到对象。 bind 方法返回函数的一个新实例,其中this 绑定到传递给bind 的参数。例如:

function explain () {
    return "I am a " + this.type;
}
dog = {
    type: "dog"
}
var dog_explain = explain.bind(dog);
dog_explain(); // returns "I am a dog"

ECMAscript 5 引入了严格模式,它改变了函数中 this 的含义,这些函数不是作为方法调用或通过 call 或 apply 调用的,因此我们必须添加一个新规则:

7 - 在严格模式下,this 不允许引用全局对象(浏览器中的窗口)。因此,当一个函数未被作为方法调用或this 未通过call 或apply 或bind 手动绑定到任何东西时,this 将变为undefined:

"use strict";
function foo () {
    return this;
}
foo(); // returns undefined instead of the global object

ECMAscript 6 引入了箭头函数。箭头函数通过提前绑定来改变 this 的行为方式。

8 - 在箭头函数中,this 在函数声明时被绑定。所以this在下面的代码中:

var x = () => {return this};

就好像函数声明如下代码:

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

请注意,由于箭头函数中的this 在声明函数时已绑定如果要使用继承,则不能使用箭头函数。这是因为函数中的this 将始终 指向父对象,而永远不会指向子对象。这意味着使用箭头函数进行继承的唯一方法是覆盖父对象中的所有箭头函数。

【讨论】:

  • 修改后的答案,忘记了this在函数外使用的情况。
  • this 仅在 IE 浏览器的事件处理程序中引用 window。在所有其他浏览器中,this 指的是事件的目标。
  • @lanzz:啊忘了。实际上,即使在 IE 上,它通常也是指目标
  • 在第5项中,你能解释一下this在return "I am a " + this.type;中的绑定是从哪里来的吗?
  • @SébastienGarcia-Roméo:那么答案取决于情况。仔细阅读上面的答案。在这种情况下,您如何编写this 或如何声明您的函数都无关紧要。重要的是你如何调用你的函数。 asyncFunction(obj1.obj2.fn) 和 this 将是全局对象或在严格模式下未定义。 asyncFunction(function(){obj1.obj2.fn()}) 然后this 将是obj2。 asyncFunction(obj1.obj2.fn.bind(mango)) 然后this 将是mango
【解决方案2】:

我认为您可能遗漏了函数和对象字面量之间的关键区别:

在调用函数之前,不会计算函数的主体。

这意味着this 的值取决于如何函数被调用。如果它作为对象上的方法调用(例如someObj.someFunc()),则this 将指向函数体内的该对象。如果它被称为独立函数 (someFunc())。它们主体中的代码将继承调用者环境中的任何this。但无论哪种方式,函数定义时this的值都无关紧要。

而对象字面量只是一个表达式;如果 this 出现,并且它不在包含在文字中的函数体中,那么它只是代码中出现该表达式的位置处的 this 的值。

【讨论】:

    【解决方案3】:

    在 Javascript 中,只有函数调用会建立新的 this 上下文。当您调用foo.bar() 时,在bar 函数内,this 将绑定到foo;当您调用foo() 时,其中的this 将绑定到window。对象字面量构造函数不是方法调用,因此它不会以任何方式影响this;它仍然会引用它在对象字面量之外引用的任何内容。

    【讨论】:

      【解决方案4】:

      this.foo 未定义,因为在所有示例中,this 指的是全局 window 对象。此外,即使您尝试了obj1.foo,它仍然会返回 undefined,因为在评估整个表达式之前尚未创建该属性。试试这个:

      var obj1 = {
          foo: new Date(),
          bar: function() {
              return new MyDate( this.foo ); // will work
          }
      };
      

      它之所以有效,是因为当您调用obj1.bar() 时,该对象将在那时创建;因为你在一个函数中,this 对象将引用当前对象。

      【讨论】:

        猜你喜欢
        • 2018-01-30
        • 1970-01-01
        • 1970-01-01
        • 2013-06-16
        • 1970-01-01
        • 2023-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多