2017-11-22 20 views
0

私はこのpolyfillを使ってJavaScriptでカスタム要素を実装しています。しかし、私がconst self = thisを最初に呼び出さない限り、self変数は私の方法の中でWindowを参照します。CustomElement内のself(this)への参照

私はそれがなぜ私のものであるのかを親切に説明し、おそらくメソッド内のカスタム要素インスタンスにアクセスするより良い方法を提案できますか?

class DocumentPreview extends HTMLElement { 
    constructor(self, documents) { 
    self = super(self); 
    self.documents = documents || []; 
    self.innerHTML = Handlebars.templates['document_preview'](); 
    } 

    connectedCallback() { 
    // if I don't do this first ... 
    const self = this; // <<---------------------------------- 
    console.log("connected now"); 
    document.addEventListener('mqttsub', function(event) { 
     // ... onMessage is undefined here: 
     self.onMessage(event.detail); 
    }); 
    } 

    disconnectedCallback() { 
    console.log("disconnected"); 
    } 

    onMessage(message) { 
    // Same story ... 
    const self = this; // <<---------------------------------- 
    Promise.resolve(true) 
    .then(json("/documents/")) 
    .then(ds => ds 
     .filter(x => x.name==message.payload) 
     .reduce((x, y) => y, undefined) 
    ) 
    .then(d => json(sprintf("/document/%d/", d.id))()) 
    // ... here: 
    .then(d => self.renderDocuments(d)) 
    .catch(console.log); 
    } 

    renderDocuments(d) { 
    console.log('render', d); 
    } 
} 
+0

コンストラクタの 'self'パラメータは他のメソッドからアクセスできませんが、それは基本的な範囲の問題です。 'onMessage()'のようにarrow関数を使用している場合、 'self'変数は必要ありません。' this'を直接使うことができます。あなたのイベントリスナーのコールバックのような非矢印関数の場合、あなたが表示したことをするか、そのコールバックで '.bind(this)'を使い、コールバックの中で 'self'ではなく' this'を使います。 – nnnnnn

答えて

2

this.methodName = this.methodName.bind(this)のようbind()を使用して、コンストラクタのメソッドonMessage()renderDocuments()を結合してみます。これで、thisでプロパティとメソッドにアクセスできます。

class DocumentPreview extends HTMLElement { 
    constructor(documents) { 
    super(); 

    this.documents = documents || []; 
    this.innerHTML = Handlebars.templates['document_preview'](); 

    this.onMessage = this.onMessage.bind(this); 
    this.renderDocuments = this.renderDocuments.bind(this); 
    } 

    connectedCallback() { 
    document.addEventListener('mqttsub', this.onMessage); 
    } 

    disconnectedCallback() { 
    console.log("disconnected"); 
    } 

    onMessage(event) { 
    const { detail: message } = event; 

    Promise.resolve(true) 
     .then(json("/documents/")) 
     .then(ds => ds 
     .filter(x => x.name==message.payload) 
     .reduce((x, y) => y, undefined) 
    ) 
     .then(d => json(sprintf("/document/%d/", d.id))()) 
     // ... here: 
     .then(d => this.renderDocuments(d)) 
     .catch(console.log); 
    } 

    renderDocuments(d) { 
    console.log('render', d); 
    } 
} 

うまくいけば助けてください!

+0

偉大な、そして上にそれは大幅に読みやすさを向上させた。クイックワン:JSでこの構造を何と呼ぶのですか? 'const {detail:message} = event;'このようなパターンマッチングには特別な名前がありますか? –

+0

OPの質問は、それぞれのメソッド内の変数に 'this 'を割り当てる必要がない基本レベルを取り巻いていました。 'bind()'アプローチは、クラスメソッドが確実に目的のスコープを持つようにすることでこれを助けます。 –

+0

@沖原ハーベストこれはES6で利用可能な[デストラクタリング割り当て](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)と呼ばれています。この場合、キー 'detail'で変数をアンパックし、' message'のエイリアス/名前を割り当てます。ありがとう! –

1

JavaScriptでは、thisキーワードは、現在の関数のコンテキストを参照します。

document.addEventListener('mqttsub', function(event) { 
    // this here corresponds to your function(event) {...} context 
    this.onMessage(event.detail); // Will fail 
}); 

これを修正する簡単な方法は、矢印機能を使用することです。矢印関数は、デフォルトで外側のコンテキストを使用します。

document.addEventListener('mqttsub', (event) => { 
    // this here corresponds to the outer context = your class 
    this.onMessage(event.detail); 
}); 

そうでなければ、あなたもコンテキストをバインドすることができ

document.addEventListener('mqttsub', (function(event) { 
    this.onMessage(event.detail); 
}).bind(this)); // Set the function context to be the class context 
関連する問題