【问题标题】:Declare global constants in function javascript on DOMContentLoaded在 DOMContentLoaded 上的函数 javascript 中声明全局常量
【发布时间】:2020-03-13 11:43:57
【问题描述】:

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

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

【问题讨论】:

  • 不,但你可以改为 Promise
  • 按钮的作用域仅限于事件监听器的块,改为在外面添加声明,然后在DOMContentLoaded事件中赋值
  • @KhushrajRathod 你可以在回调中使用 someObject.on("EventThatWillOnlyOccurAfterDOMContentLoads", () => { console.log(button.innerHTML) // ReferenceError })?
  • 如果您担心button 变量不应更改,请使用Object.freeze()?

标签: javascript ecmascript-6 scope constants domcontentloaded


【解决方案1】:

如果问题是:“有什么办法可以声明一个没有值的常量变量,然后再赋值给它?”,那么答案是没有 .

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

如果您能够创建这样的变量,那将不会是真正的常量。看这个例子:

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 的异步结构,所谓的承诺。

通过使用它们,您的代码可以等待给定事件(在您的情况下为 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 元素收集到一个对象中,并用它来解决您的承诺:

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)
    })
})

【讨论】:

  • 谢谢。所有代码都在事件侦听器中的嵌套方法对我有用。
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 2020-06-27
  • 1970-01-01
相关资源
最近更新 更多