【问题标题】:Javascript ES6 eliminate usage of 'this' keyword everywhere in classesJavascript ES6 消除了类中任何地方的“this”关键字的使用
【发布时间】:2015-03-20 00:45:52
【问题描述】:

我现在正在使用 Traceur 来编写一些未来的 javascript,这是我在某个类中拥有的一个函数

create() {
    this.game.physics.startSystem(Phaser.Physics.ARCADE);

    this.segmentcache = new SegmentCache(this.game);
    this.segments = new Segments(this.game);
    this.segments.cache = this.segmentcache;
    this.segments.seek(3);

    this.guy = new Guy(this.game, 140 + 8, 80);
    this.guy.anchor.set(0.5, 1.0);
    this.game.add.existing(this.guy);

    this.game.camera.x = 100;
    this.ticks = 0;
    this.cross = 0;
}

当然,与任何传统的 javascript 代码一样,它到处都被 this 关键字覆盖。来自 Java 之类的,当我不需要时,在引用类中的字段时必须指定它是非常不自然的。

有什么方法可以让 Traceur 像 Java 一样解释类? (即在未指定时自动插入等)

【问题讨论】:

  • 那将不再是有效的 JavaScript。 Traceur 没有定义新的语言,它坚持 ES6 规范。我认为您的处理方式不正确。如果您想编写 JavaScript 而不是这样做,并且不要试图将其视为 Java(因为无论如何它都非常不同)。对我来说,恰恰相反:我觉得你不必在 Java 中指定 this 非常令人困惑。我发现这种“隐含性”使遵循代码变得更加困难。
  • function() { with(this) { ... } } ;)
  • @JeremyBanks - 最后我差点错过了。不过会为他服务。
  • 更严重的是:这可能无法在像 JavaScript 这样动态的语言中有效地实现。有可能在提议的“SoundScript”子集中实现,但这是 ES6 之外的几个步骤。也许有一天。
  • 我认为这不是一个好主意。如果你想写Java,就写Java。也许将其编译为 Javascript。但不要强迫语言成为它不是的东西。

标签: javascript ecmascript-6 traceur


【解决方案1】:

AFAIK,不。

在 Java、C#、C++ 等中,这是编译器的一个特性,而不是执行。这意味着它是隐式完成的,编译器所做的是将正确的地址放入this 并以正确的方式引用变量。大多数编译器都有一条规则,如果您有一个同名的局部变量(在局部范围内),则它具有成员变量的优先级。

在 javascript 中,您可以通过 callapplybind 轻松替换 this,并让您的函数被调用一个作者不打算工作的对象with(即this 可能是具有不同结构的对象)。我认为这就是语言语法要求您始终明确指定您是指范围还是 this 的原因。

javascript 函数体中的更多内容实际上可以读取全局范围,因此如果您不使用显式 this,定义 window.member(如果在浏览器中)可能会改变函数的行为

【讨论】:

    【解决方案2】:

    据我所知,ES6 中没有这样的功能。

    这种类型的功能会因为 Javascript 允许在父范围内引用变量而变得复杂。因此,它必须以某种方式辨别一行代码是否像:

    ticks = 0;
    

    表示

    this.ticks = 0;
    

    或者是否意味着以ticks的名称引用当前或父范围内的变量。

    仅仅向对象添加属性可能会因为在属性引用和同名的局部变量或父范围变量之间产生冲突而弄乱以前运行良好的代码。那很可能是一团糟。现在,您必须为局部变量命名范围,以避免与属性名称发生冲突。而且,如果您必须限定局部变量的范围,那么您只是重新引入了一段您试图摆脱的额外语法。

    Java 可以容忍这种情况,因为编译器预先知道所有属性名称,因此如果发生冲突,它可以报告错误。 Javascript 允许动态添加属性(随时添加),因此解析器实际上并不知道在解析时任何给定对象上会或不会出现什么属性名称,因此它无法警告冲突。这只是语言在解析/编译和工作方式上的固有差异,因此会导致在表达代码时出现一些不同的功能或要求。

    可以使用with 结构来避免一些输入,但是with 正在从Javascript 中删除(在严格模式下不允许),原因详细here,没有增强,因此不推荐使用。

    【讨论】:

      【解决方案3】:

      如果您想避免在构造函数中(或任何地方)分配实例变量时必须键入this,您可以使用_.extend()

      // this, this, this
      this.a = true;
      this.b = 2;
      this.c = "three";
      
      // becomes...
      _.extend(this, {
        a: true,
        b: 2,
        c: "three"
      });
      

      【讨论】:

        【解决方案4】:

        作为可能的简单说明,您可以预处理您的类以插入 this. 以获得一组预定义的属性名称,例如通过每个类的自定义静态元配置,可用于gulp 构建文件。

        DEBUG ClassPreprocessor: buildSync [ 'logger',
          'context',
          'config',
          'startedComponents',
          'components',
          'requiredComponents' ] 
        regex ([^a-z\.'])(logger|context|config|startedComponents|components|requiredComponents)([^a-z:'])
        replaceWith $1this.$2$3
        

        从指定的道具名称中,现在我正在构建一个正则表达式来预处理类。不过,这非常脆弱,因为它不是基于令牌的。稍后,我想通过 AST 上的 Babel 转换器尝试类似的东西。

        【讨论】:

          猜你喜欢
          • 2018-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          • 2016-02-19
          • 2015-02-27
          • 1970-01-01
          • 2016-08-04
          相关资源
          最近更新 更多