一种在 JS 中启用默认 this 范围的方法,不需要绑定 this 或前缀类成员

问题描述 投票:0回答:1

我有以下模块类,为了使其与非模块函数式 javascript 类似,我必须将所有函数绑定到正确的

this
范围,并明确使用
this
作为类成员。

上一个 JavaScript:

var globalVariable = 10;
var button = document.getElementById("button");
button.addEventListener("click", buttonClicked); 
function buttonClicked(event) {
    var newValue = globalVariable + globalVariable;
    alert("Hello world");
}

模块类中的相同内容如下:

export App class {
    classVariable = 10;
    button = null;

    constructor() {

      try {
         this.bindProperties(App);
         this.button = document.getElementById("button");
         this.button.addEventListener("click", this.buttonClicked);
      }
      catch(error) {
         this.log(error);
      }
   }

   buttonClicked(event) {
      var newValue = this.globalVariable + this.globalVariable;
      alert("Hello world");
   }

   bindProperties(mainClass) {
      var properties = Object.getOwnPropertyNames(mainClass.prototype);
      for (var key in properties) {
         var property = properties[key]
         if (property!=="constructor") {
            this[property] = this[property].bind(this);
         }
      }
   }
}

我想知道是否有一个设置允许这样做:

export App class {
    classVariable = 10;
    button = null;

    constructor() {

      try {
         button = document.getElementById("button");
         button.addEventListener("click", buttonClicked);
      }
      catch(error) {
         console.log(error);
      }
   }

   buttonClicked(event) {
      var newValue = globalVariable + globalVariable;
      alert("Hello world");
   }
}

基本上,是否有一个选项可以消除添加

this
和绑定
this
类成员的需要。

我正在使用它知道的打字稿,或者默认情况下将

this
添加到代码完整的任何类成员中。如果没有它,它会标记它。

对于新手来说,令人困惑的部分可能是需要将

this
绑定到类模块上。但也许我错过了一些东西。

另外,注意一下,可能是因为上面的绑定方法,如果扩展了子类方法,超类成员不会调用子类成员。

因此,如果调用 baseclass.log() 并且应用程序类扩展了基类,则调用基类方法而不是扩展它的类方法。但这是另一个问题(但相关)。

javascript typescript ecmascript-6 ecmascript-next
1个回答
0
投票

基本上有两种技术方法,它们都会带来期望的行为。

首先,作为处理程序的箭头函数利用保留封闭词法上下文的

this
值,因此
App
实例化时间为
this

// `App` module scope

// a single function statement for handling any `App` instance's
// button-click, based on event and app instance references which
// both get forwarded by an anonymous arrow function expression
// which retains the `this` value of the enclosing lexical context
// at `App` instantiation time.

function handleAppButtonClick(appInstance, evt) {
  const computedValue = 2 * appInstance.publicProperty;

  console.log({
    computedValue, appInstance, button: evt.currentTarget,
  });
}

/* export */class App {

  #privateButton;
  publicProperty;

  constructor(buttonSelector = '#button', value = 10) {
    value = parseInt(value, 10);

    this.publicProperty = isFinite(value) ? value : 10;

    this.#privateButton =
      document.querySelector(buttonSelector);

    this.#privateButton.addEventListener(

      // - an arrow function as handler makes use of retaining
      //   the `this` value of the enclosing lexical context,
      //   hence the `App` instantiation time's `this`.

      "click", evt => handleAppButtonClick(this, evt)
    );
  }
  // no need for any prototypal implemented event handler.
}
// end ... App module scope


// other module's scope
// import App from '...'

new App('button:first-child');
new App('button:nth-child(2)', 20);
.as-console-wrapper { max-height: 90%!important; }
<button type="button">1st test logs ... 20</button>
<button type="button">2nd test logs ... 40</button>

其次,用于处理任何

App
实例的按钮单击的单个函数语句。它是创建处理程序函数的基础,该函数显式地将
App
实例绑定为创建的处理程序的
this
上下文。

// `App` module scope

// a single function statement for handling any App-instance's
// button-click. It is the base for creating handler-functions
// which explicitly do bind an `App` instance as the created
// handler's `this` context.

function handleButtonClickOfBoundAppInstance(evt) {
  const computedValue = 2 * this.publicProperty;

  console.log({
    computedValue, appInstance: this, button: evt.currentTarget,
  });
}

/* export */class App {

  #privateButton;
  publicProperty;

  constructor(buttonSelector = '#button', value = 10) {
    value = parseInt(value, 10);

    this.publicProperty = isFinite(value) ? value : 10;

    this.#privateButton =
      document.querySelector(buttonSelector);

    this.#privateButton.addEventListener(

      // - explicitly bind an `App` instance as
      //   the created handler's `this` context.

      "click", handleButtonClickOfBoundAppInstance.bind(this)
    );
  }
  // no need for any prototypal implemented event handler.
}
// end ... App module scope


// other module's scope
// import App from '...'

new App('button:first-child');
new App('button:nth-child(2)', 20);
.as-console-wrapper { max-height: 90%!important; }
<button type="button">1st test logs ... 20</button>
<button type="button">2nd test logs ... 40</button>

© www.soinside.com 2019 - 2024. All rights reserved.