【问题标题】:How does the "this" keyword work with objects in JavaScript? [duplicate]“this”关键字如何与 JavaScript 中的对象一起使用? [复制]
【发布时间】:2018-01-30 03:53:42
【问题描述】:

由于我试图掌握 JavaScript 中可迭代的概念,因此我使用以下代码构建了一个:

let range = {
  from: 0,
  to: 5
};

range[Symbol.iterator] = function() {
  return {
    current: this.from,
    last: this.to,

    next() {
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    }
  };
};

for (let num of range) {
  console.log(num);
}

Symbol.iterator 方法返回一个对象,该对象包含一个方法 (next) 和两个属性(currentfrom)。此对象中的属性等于对象range 中的属性。

由于current 等于this.fromlast 等于this.to,我假设我可以直接在方法next 中使用this.fromthis.to,如下所示:

let range = {
  from: 0,
  to: 5
};

range[Symbol.iterator] = function() {
  return {
    next() {
      if (this.from <= this.to) {
        return { done: false, value: this.from++ };
      } else {
        return { done: true };
      }
    }
  };
};

for (let num of range) {
  console.log(num);
}

但是,这样做会阻止迭代开始。观察到这一点,我有两个问题:

  1. 为什么可以属性currentlast 使用关键字this 并让它引用对象range 而方法next 不能? currentlastnext() 都是 same 对象的一部分,该对象由 Symbol.iterator 返回。

  2. 另外,鉴于Symbol.iterator() 返回一个单独 对象,该对象中的this 关键字不应该引用该对象本身吗?换句话说,属性currentlast not 是否应该能够使用关键字thisrange 访问属性? range 不是一个单独的对象吗?

【问题讨论】:

  • this 的一个用法在[Symbol.iterator] 方法中,另一个在.next 方法中。对象字面量无关紧要,它们没有自己的作用域。

标签: javascript oop iteration symbols


【解决方案1】:

this 众所周知是一件棘手的事情。以至于凯尔·辛普森(Kyle Simpson)几乎用一整本书来讨论这个话题(You Don't Know JS: this & Object Prototypes)。但是,在您的示例中,答案很简单 - 在第二个函数中,thisnext() 函数内,因此解析为该函数。

为了检查 this 的范围,我使用的是 Chrome 的调试工具。如果您在正确的行暂停,它会告诉您 this 解析为什么。

【讨论】:

  • 这是有道理的。但是,那么为什么currentlast 属性(它们的值都涉及this)解析为range 对象而不是它们自己的对象?
  • 闭包和原型继承。这说嘿我有点像这种闭包(函数/对象)
  • current: this.from 发生在range 对象中,因此this 指的是range。在第二个 sn-p 中,thisnext() 函数的范围内使用。
【解决方案2】:

关键字this 很复杂。当有更好的替代品时避免使用它是明智的,因为它有很多陷阱。

除此之外,答案如下:this 指的是调用其包含函数的激活对象(有时称为上下文对象)与。

什么是激活对象?它是函数被调用时附加到的对象。 console.log() 的激活对象是console

不过……

const x = {
    log : console.log
};
x.log();

...这里x.log()console.log()完全一样,只是激活对象是x而不是console

看起来很简单,对吧?它是,有点。但是还有更多的事情要知道。

  • 有一个默认上下文对象,在调用函数而不附加到对象时使用。它是全局对象,在浏览器中称为window,在Node.js 中称为global
  • 如果脚本在 strict mode 中运行,则没有默认的上下文对象,如果没有使用上下文显式调用,它将是 undefined
  • Arrow functions 使用词法作用域,它们的 this 值根本不是通常的上下文对象 - 它是其父函数的上下文对象,从定义箭头函数的地方开始

现在让我们将上述内容应用到您的代码中。最重要的是,如果在上下文为 range 对象的情况下调用您的 next() 方法,它将起作用。问题是,在引擎盖下,引擎基本上是这样做的......

const returnedObject = range[Symbol.iterator]();
returnedObject.next();

...所以next 被调用时使用returnedObject 作为其上下文,而不是range。但是返回对象 的函数是range 作为其上下文调用的。因此,this 在每个地方都是不同的。

您实际上可以通过使用箭头函数而不是速记方法来非常轻松地解决您的问题。

这将起作用:

let range = {
  from: 0,
  to: 5
};

range[Symbol.iterator] = function() {
  return {
    next : () => {
      if (this.from <= this.to) {
        return { done: false, value: this.from++ };
      } else {
        return { done: true };
      }
    }
  };
};

for (let num of range) {
  console.log(num);
}

【讨论】:

    猜你喜欢
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 1970-01-01
    • 2019-11-18
    相关资源
    最近更新 更多