javascript - 在 DOMContentLoaded 上的 javascript 函数中声明全局常量

标签 javascript ecmascript-6 scope constants domcontentloaded

有没有办法在 DOMContentLoaded 事件触发时声明可在外部访问的常量?

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

最佳答案

如果问题是:“有没有办法声明一个没有值的常量变量,并稍后为其赋值?”,那么答案是 .

再想一想:声明后,常变量的值必须始终相同;这就是创建常量的重点。

如果您能够创建这样的变量,那么它实际上就不是恒定的。看这个例子:

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

window.addEventListener('DOMContentLoaded', () => {
    button = document.getElementById("button")
})
someObject.on('EventThatMayOccurEitherBeforeOrAfterDOMContentLoaded', () => {

    //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 的异步结构,即所谓的 Promises。

通过使用它们,您的代码可以等待给定的事件(在您的情况下,DOMContentLoaded),而无需将该代码移至其监听器内,并且即使发出第二个事件也能正常工作多次:

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

这种方法可能看起来更复杂,但是当代码变得异步时,到处使用 Promise 可以简化您的生活。

另请注意,这种方法有其局限性,例如,您不能嵌套其中两个 promise (如果您尝试这样做,您会发现自己处于您所询问的场景中):

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 元素收集到一个对象中,并用它来解决您的 promise :

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('EventThatMayOccurEitherBeforeOrAfterDOMContentLoaded', () => {
    //Destructure button:
    button.then(({button}) => {
        console.log(button.innerHTML)
    })
})

关于javascript - 在 DOMContentLoaded 上的 javascript 函数中声明全局常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60669871/

相关文章:

javascript - 仅使用 JavaScript 进行表格排序

javascript - Ember - 如何为 CollectionView 中的每个项目设置 Controller

javascript - 是否有与 Object.prototype.hasOwnProperty 对应的对象?

javascript - 通过 Promise 链传递变量

c++ - 如何使指针显示对象的字符串变量?

c - 编译器如何区分名称相同的项目

javascript - HTML5 websockets 与可访问性标准的兼容性如何?

javascript - JS中的类和函数?

JavaScript 在带有回调的循环中异步

c++ - 通过 id 访问 QML 槽中的嵌套对象(从 C++ 调用)