Объявите глобальные константы в функции javascript в DOMContentLoaded - PullRequest
0 голосов
/ 13 марта 2020

Есть ли способ объявить константы, когда срабатывает событие DOMContentLoaded, которые доступны снаружи?

window.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById("button")
})
someObject.on("EventThatWillOnlyOccurAfterDOMContentLoads", () => {
    console.log(button.innerHTML) // ReferenceError
})

1 Ответ

1 голос
/ 14 марта 2020

Если вопрос звучит так: « Есть ли способ объявить постоянную переменную без значения и присвоить ее позже? », тогда ответ будет нет .

Подумайте еще раз: после объявления значение постоянной переменной всегда должно быть одинаковым; В этом смысл создания констант.

Если бы вы смогли создать такую ​​переменную, она не была бы действительно постоянной. Посмотрите на этот пример:

const button //This would throw a SyntaxError but assume it doesn't

window.addEventListener('DOMContentLoaded', () => {
    button = document.getElementById("button")
})
someObject.on('Event that may occur either before or after DOMContentLoaded', () => {

    //We are unsure what button is here: it might be a DOM node or undefined, or... what?
    console.log(button)
})

Итак, вы не можете создать константу в глобальной области видимости таким образом. Но почему вы вообще хотите объявить его в глобальной области видимости?

Если вы знаете, что второе событие не будет запущено до DOMContentLoaded, просто переместите его объявление внутрь, например так:

window.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById("button")

    someObject.on("EventThatWillOnlyOccurAfterDOMContentLoads", () => {
        console.log(button.innerHTML) // Works perfectly
    })
})

Этот подход по крайней мере так же хорош, как тот, который вы хотели, если не лучше:

Хранение всех переменных внутри слушателя событий:

  • Полностью избегает загрязнения глобальной области видимости (например, IIFE, которое некоторые используют)
  • Заставляет ваш код работать только после загрузки страницы, поэтому вам не нужно беспокоиться о недоступных элементах DOM.

Однако, если вы не можете переместить весь код в DOMContentLoaded (например, потому что хотите прослушать событие, которое запускается перед ним), у вас есть еще один вариант : используя асинхронные структуры ES6, так называемые Обещания.

Используя их, ваш код может ожидать данное событие (в вашем случае DOMContentLoaded), не перемещая этот код внутри своего слушатель, и будет работать, даже если т Второе событие отправляется несколько раз:

const button = new Promise(setButton => {
    window.addEventListener('DOMContentLoaded', () => {
        //Resolve the promise when we get the value:
        setButton(document.getElementById("button"))
    })
})
someObject.on('Event that may occur either before or after DOMContentLoaded', () => {
    //This will wait for the promise to resolve if it hasn't done so yet:
    button.then(button => {
        console.log(button.innerHTML)
    })
})

Этот подход может показаться более сложным, но повсеместное использование обещаний может упростить вашу жизнь, когда ваш код станет асинхронным.

Также обратите внимание, что этот подход имеет например, вы не можете вложить два из этих обещаний (если вы попытаетесь это сделать, вы окажетесь в сценарии, подобном тому, о котором вы спрашивали):

const button = new Promise(setButton => {
    //How to make this one global as well?
    const anotherButton = new Promise(setAnotherButton => {
        window.addEventListener('DOMContentLoaded', () => {
            setButton(document.getElementById("button"))
            setAnotherButton(document.getElementById("button2"))
        })
    })
})

Вместо этого вы можете собрать все элементы DOM в один объект и выполнить свое обещание с ним:

const DOMElements = new Promise(resolve => {
    window.addEventListener('DOMContentLoaded', () => {
        //Resolve the promise when we get the value:
        resolve(Object.freeze({
            button: document.getElementById("button"),
            anotherButton: document.getElementById("button2")
        }))
    })
})
someObject.on('Event that may occur either before or after DOMContentLoaded', () => {
    //Destructure button:
    button.then(({button}) => {
        console.log(button.innerHTML)
    })
})
...