JavaScript继承:在HTML文档中调用原型对象-如何使用模块

问题描述

我正在努力产生一个有效的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,您要构建的不是层次结构,而是一组混合(很好!)。这不是问题,这只是术语。 :-)

有两个问题:

  1. 所有内容都直接位于对象上,而不是附加在其上的子对象上,因此它不是factory.personFactory.talk();,而是factory.talk();(除了personMammalFactory返回的内容之外)不是工厂,所以我可以称之为personMammal)。

  2. 由于文件是模块,因此它们不会创建任何全局变量;尝试使用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
  • mammalpersonfactory正确地导入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>

正确输出记录:1.4 enter image description here