gaa*_*kam 7 javascript scope ecmascript-6 custom-element es6-modules
这不起作用:
<!-- wtf.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
<script type="module" src="./wtf.js"></script>
</head>
<body>
<script>
const myElement = document.createElement('my-element')
document.body.appendChild(myElement)
myElement.callMe()
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
// wtf.js
customElements.define('my-element', class extends HTMLElement {
constructor() {
super()
}
callMe() {
window.alert('I am called!')
}
})
Run Code Online (Sandbox Code Playgroud)
Firefox使我感到讨厌myElement.callMe()。显然是“ myElement.callMe is not a function”。
我很困惑为什么会这样?据我了解,只要输入const myElement = document.createElement('my-element'),我就会收到一个对象,该对象的类型不是泛型,HTMLElement而是我编写的可扩展类的对象HTMLElement!并且这个类暴露了callMe。
我已经确认我对模块的使用似乎是罪魁祸首。此代码按预期工作:
<!-- wtf.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super()
}
callMe() {
window.alert('I am called!')
}
})
const myElement = document.createElement('my-element')
document.body.appendChild(myElement)
myElement.callMe()
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
是的,我知道模块中定义的内容仅限于此模块。但是,在我看来,这甚至还不是一个范围界定的问题。例如,如果我在模块中执行以下操作:
function callMe() {/*blah blah */}
window.callMe = callMe
Run Code Online (Sandbox Code Playgroud)
那么我无论如何都可以callMe 在模块外部使用,因为模块通过其他方式export(这次是通过将其分配给全局window对象)公开了此功能。
据我所知,在我的用例中应该发生同样的事情。即使我callMe在作用域范围内的类中进行了定义,该类方法也应该可以在模块外部访问,这是因为该方法是该类对象的一个属性,该属性通过调用公开document.createElement('my-element')。但是显然,这不会发生。
这对我来说真的很奇怪。似乎模块通过纠缠与类型无关的函数return(!!)来强制执行作用域-因此,在这种情况下,就像模块神奇地强制document.createElement将其返回的对象强制转换为继承层次结构(HTMLElement)?!?!这对我来说真是令人难以置信。
有人可以消除我的困惑吗?
(并且,如果我在模块内部定义了自定义元素,如何将其API暴露在此模块之外?)
问题是 a<script type="module"> 隐式具有deferattribute,因此它不会立即运行。
即使我在模块范围内的类中定义了 callMe,该类方法也应该可以在模块外部访问
是的。问题在于它是异步定义的:-) 要使用模块中的内容,您应该显式import该模块来声明依赖项,这确保它以正确的顺序进行评估。如果你的全局脚本以某种方式是红色的,它也会起作用defer。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
<script type="module" src="./wtf.js"></script>
</head>
<body>
<script type="module">
import './wtf.js';
// ^^^^^^^^^^^^^^^^^^
const myElement = document.createElement('my-element')
document.body.appendChild(myElement)
myElement.callMe()
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)