2017-11-22 18 views
0

나는 polyfill을 사용하여 자바 스크립트에서 맞춤 요소를 구현하고 있습니다. 그러나 을 먼저 호출하지 않는 한 self 변수는 내 방법 내에서 Window을 참조합니다.CustomElement 내부의 자체 (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

자바 스크립트에서 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