问题描述
我正在努力产生一个有效的JavaScript层次结构。基本示例如下:
'use strict';
const personFactory = (name) => ({
talk() {
console.log(`${name} says hello`);
}
});
'use strict';
const mammal = {
isvertebrae: true
};
import * as mammal from './mammal.js';
import * as personFactory from './personFactory.js';
'use strict';
const personMammalFactory = (name) => (
Object.assign(
{},mammal,personFactory(name)
)
);
<script type="module" src="~/js/modules/personMammalFactory.js"></script>
<script>
var factory = personMammalFactory('Brian');
factory.personFactory.talk();
</script>
personMammalFactory('Brian')引发引用错误:未捕获的ReferenceError:未定义personMammalFactory
请注意,所有三个对象都在一个单独的文件中(personFactory.js,哺乳动物.js和personMammalFactory.js)。
我似乎无法正确地将personMammalFactory调用到HTML文档中。您能给我指导我可能做错了什么吗?
解决方法
FWIW,您要构建的不是层次结构,而是一组混合(很好!)。这不是问题,这只是术语。 :-)
有两个问题:
-
所有内容都直接位于对象上,而不是附加在其上的子对象上,因此它不是
factory.personFactory.talk();
,而是factory.talk();
(除了personMammalFactory
返回的内容之外)不是工厂,所以我可以称之为personMammal
)。 -
由于文件是模块,因此它们不会创建任何全局变量;尝试使用
personMammalfactory
的脚本代码显示为简单的脚本,而不是模块,因此,如果不从模块中导入,它将无法访问模块中的任何内容(除非它们执行了类似非模块的操作,例如故意创建全局变量,但没有必要)。另外,进出口方面存在一些问题,我们将在稍后解决。
...然后要注意一点:模块始终处于严格模式,因此不需要"use strict"
。 (在您确实使用"use strict";
的文件中,它必须是文件中的第一个非空格,非注释。)
下面是用一个脚本中显示的所有代码修复#1的示例:
'use strict';
const personFactory = (name) => ({
talk() {
console.log(`${name} says hello`);
}
});
const mammal = {
isVertebrate: true
// ^−−−−−− (added missing t)
};
const personMammalFactory = (name) => (
Object.assign(
{},mammal,personFactory(name)
)
);
const personMammal = personMammalFactory('Brian'); // "Brian says hello"
personMammal.talk();
console.log(personMammal.isVertebrate); // true
要修复#2,您需要:
- 导出
personMammalFactory
。 - 导出
mammal
- 将
mammal
和personfactory
正确地导入personMammalFactory.js
- 删除
script
的{{1}}标记(不需要) - 将要使用的脚本放在一个可以导入
personMammalFactory.js
的模块中,而不仅仅是一个简单的脚本。
做所有这些事情给我们:
personMammalFactory
:
personFactory.js
export const personFactory = (name) => ({ // *** Added `export`
talk() {
console.log(`${name} says hello`);
}
});
:
mammal.js
export const mammal = { // *** Added `export`
isVertebrate: true
// ^−−−−−− *** added missing t,FWIW
};
:
personMammalFactory.js
主模块脚本(键入import { mammal } from "./mammal.js"; // *** Added/modified
import { personFactory } from "./personFactory.js"; // *** Added/modified
export const personMammalFactory = (name) => ( // *** Added `export`
Object.assign(
{},personFactory(name)
)
);
const personMammal = personMammalFactory('Brian'); // "Brian says hello"
personMammal.talk();
console.log(personMammal.isVertebrate); // true
):
type
浏览器知道要从服务器读取的其他文件,因为它知道模块的层次结构,并且导入文件告诉它在哪里可以找到文件。
如果愿意,可以使用默认导出而不是命名导出。 (我强烈喜欢命名出口。)
<script type="module">
import { personMammalFactory } from "./personMammalFactory.js";
const factory = personMammalFactory('Brian');
factory.talk();
</script>
:
personFactory.js
export default const personFactory = (name) => ({ // *** Added `export default`
talk() {
console.log(`${name} says hello`);
}
});
:
mammal.js
export default const mammal = { // *** Added `export default`
isVertebrate: true
// ^−−−−−− *** added missing t,FWIW
};
:
personMammalFactory.js
主模块脚本(键入import mammal from "./mammal.js"; // *** Added/modified
import personFactory from "./personFactory.js"; // *** Added/modified
export default const personMammalFactory = (name) => ( // *** Added `export`
Object.assign(
{},personFactory(name)
)
);
const personMammal = personMammalFactory('Brian'); // "Brian says hello"
personMammal.talk();
console.log(personMammal.isVertebrate); // true
):
type
如果您想要建立层次结构,那么在JavaScript中,这些是通过原型链直接或通过构造函数间接完成的。以您的示例为例,我怀疑您会更直接地这样做。为此,您将使用<script type="module">
import personMammalFactory from "./personMammalFactory.js";
const factory = personMammalFactory('Brian');
factory.talk();
</script>
并传递应该是原型的对象;返回值是一个使用您作为原型传递的对象的对象:
Object.create
例如,这是一个const object = Object.create(prototyepObject);
,它创建使用personMammalFactory
作为其原型的对象:
mammal
(上面有一个“陷阱”:如果您在"use strict";
const personFactory = (name) => ({
talk() {
console.log(`${name} says hello`);
}
});
const mammal = {
isVertebrate: true
// ^−−−−−− (added missing t)
};
const personMammalFactory = (name) => (
Object.assign(
Object.create(mammal),// *** The key difference
personFactory(name)
)
);
const personMammal = personMammalFactory("Brian");
personMammal.talk(); // "Brian says hello"
console.log(personMammal.isVertebrate); // true
中使用了super
,它将引用talk
,而不是Object.prototype
。以上我可能会避免通过使用mammal
或其他东西而不是talk
来使talk: () => { /*...*/ }
成为实际方法,因此它无法访问talk() { /* ... */ }
。)
或者,如果您愿意,可以沿构造函数的方向走,最方便的方法是使用super
语法。但这看起来并不适合您的工作。
T.J Crowder为我提供了解决此问题的基本信息。问题似乎是FireFox如何解释进出口。导出和导入的处理方式因浏览器而异。
通常,此修补程序很简单,但很难找到:必须在定义基础对象的 const 之后使用导出默认值{nameObject} em>。如果将 export 放在 const 之前,则Firefox会产生MIME类型错误,而不会提示导致问题的原因(请参见代码图1.0)。第二个问题是在 import 中正确使用JavaScript的相对路径语法。如“ Relative paths from the root in javascript” 中所述,使用反斜杠(请参见代码图1.3)将获得相对根路径。但是,我没有在JS文件中使用相对位置,而仅在HTML文件导入中使用了相对位置(请参见代码图1.2)。
注意:每个对象都是一个单独的文件(mammal.js,personFactory.js和personMammalFactory.js)。
错误的导出方法: 1.0
export default const mammal = {
isVertebrae: true
};
正确的导出方法: 1.1
const mammal = {
isVertebrae: true
};
export default { mammal };
正确的导入继承结构: 1.2
import mammal from './mammal.js';
import personFactory from './personFactory.js';
export const personMammalFactory = (name) => (
Object.assign(
{},personFactory(name)
)
);
HTML文件导入: 1.3
// Declare this script a module.
<script type="module">
// Note the relative path using the backslash and the use of brackets. By using this this is not need for and src include.
import { personMammalFactory } from '/js/modules/personMammalFactory.js';
// Inheritance is now happy :-)
const factory = personMammalFactory('Brian');
console.log(factory);
factory.talk();
</scrip>