0

Так alert работает:

class Test {
    #shown;
constructor() {
    this.#shown = 'hello';
    this.showMessage.bind(this);
}

showMessage() {
    alert(this.#shown);
}

}

var test = new Test;

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div class="container">
            <button class="element" onclick="test.showMessage();">кнопка</button>
        </div>
        <script src="test.js"></script>
    </body>
</html>

А так alert не работает:

class Test {
    #shown;
constructor() {
    this.#shown = 'hello';
    this.showMessage.bind(this);
}

showMessage() {
    alert(this.#shown);
}

}

var test = new Test;

document.addEventListener('DOMContentLoaded', function() { let element = this.querySelector('.element'); element.addEventListener('click', test.showMessage); })

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div class="container">
            <button class="element">кнопка</button>
        </div>
        <script src="test.js"></script>
    </body>
</html>

Почему во втором случае alert() не страбатывает, если в обоих случаях я привязываю событие на один и тот же элемент и в обоих случаях использую bind() чтобы this всегда было в контексте класса Test?

Arbery
  • 2,441
  • 1
    В обоих случаях вы просто выбрасываете результат работы bind в никуда, поэтому он тут ни на что не влияет. Ну и во втором случае теряется this, потому что addEventListener подсовывает туда свой собственный this – andreymal Nov 06 '23 at 18:17
  • 1
    Потому что Js даже сами разрабы уже не понимают :DD и тут придётся костылить в виде element.addEventListener('click', () => { test.showMessage() }); и пр. .... А вообще andreymal прав – Алексей Шиманский Nov 06 '23 at 18:19
  • 1
    В первом случае явно вызывается метод объекта... В втором случае выполняется т.н. "заимствование" метода, потому и теряется контекст его выполнения. – ksa Nov 06 '23 at 19:39

1 Answers1

1

Во 2м примере проблемы связаны с контекстом, в функции, используемой в addEventListener, это не объект test, а кнопка element, у которой нужных методов и свойств нет.

Решить можно, например, такими 2мя способами:

В конструкторе так привязать контекст к функции:

this.showMessage = this.showMessage.bind(this);

Или как в комментарии к вопросу - измените функцию на стрелочную, которая использует контекст выше:

element.addEventListener('click', () => { test.showMessage() });

class Test {
    constructor() {
        this.shown = 'hello';
        this.showMessage = this.showMessage.bind(this);
    }
showMessage() {
    alert(this.shown);
}

}

var test = new Test;

document.addEventListener('DOMContentLoaded', function() { let element = this.querySelector('.element'); element.addEventListener('click', test.showMessage); })

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div class="container">
            <button class="element">кнопка</button>
        </div>
        <script src="test.js"></script>
    </body>
</html>
Arbery
  • 2,441