首页 > 解决方案 > 允许用户在上下文中修改导入的 ES6 模块函数

问题描述

我对某件事是否可能感到困惑。

我创建了一个包含以下内容的模块:

export function logText(){
    console.log('some text');
}

export class Example {
    constructor(){
        logText();
    }
}

目的是让用户调用new Example以启动模块逻辑。

import { logText, Example } from 'example';

// Do some magic here to modify the functionality of logText

new Example();

最终用户是否可以修改 logText?

有一种方法让用户做这样的事情是有意义的,或者他们必须将整个模块放入他们自己的存储库中,只是为了进行小的功能调整。

我经常看到 repos 导出了许多无用的功能,而用户不必手动重新制作几乎所有功能,这使得这样做毫无意义。一个很好的例子是这个 repo,他们甚至将导出的函数称为他们的“API”。在那个例子中,这些是相当无意义的导出,更糟糕的是,如果有人试图将它们与 main 函数结合使用,只会导致问题。但是,如果您可以修改它们并让它们仍然运行,那么这对我来说很有意义。

标签: javascriptecmascript-6modulees6-modules

解决方案


鉴于这种:

import { logText, Example } from 'example';

最终用户是否可以修改 logText?

由于您对“修改 logText”的含义不是很具体,因此我将介绍几个选项:

您可以将其他一些功能重新分配给变量logText吗?

不,你不能那样做。当您使用时,它会创建一个已分配且无法分配import的变量。const即使它不是 const,它也只是一个本地符号,无论如何都不会影响其他模块对其的使用logText()。该import机制是故意这样设计的。模块的加载器不应该能够替换不是专门设计用于替换的模块的内部实现部分。

logText您可以从包含它的模块外部修改函数内部的代码吗?

你不能。模块中的代码存在于它自己的函数范围内,这给了它隐私。您不能从模块外部修改该模块内的代码。

您可以替换logText()模块内的函数,Example以便该类内部的实现将使用您的logText()函数吗?

不,您不能从模块外部执行此操作。您必须实际修改模块的代码本身,否则必须设计 Example 接口以具有logText()Example 对象使用的可替换或可修改的功能。

例如,logText()可以在 Example 上创建一个方法,然后您可以用您自己的实现覆盖它,这将导致 Example 的实现使用您的覆盖。

您未修改的模块中的代码:

export class Example {
    constructor(){
        this.logText();
    }
    logText() {
        console.log('some text');
    }
}

执行导入的代码:

import { Example } from 'example';

class MyExample extends Example {
    constructor() {
        super();
    }
    logText() {
        console.log("my own text");
    }
}

let o = new MyExample();    

您可以创建自己的版本logText并在本地使用吗?

当然,你可以这样做。

function myLogText() {
    do your own thing
}

而且,您甚至可以不导入 logText,以便您可以根据需要在logText()本地使用符号名称。但是,这根本不会影响 Example 的作用。

有没有办法设计示例模块,以便logText()可以轻松替换。

是的,有很多方法可以做到这一点。我在上面展示了一个logText可以重写的方法。它也可以作为可选参数传递给Example构造函数。

甚至可能有一个导出的对象,允许调用者替换该对象的属性。例如:

export const api = {
    logText: function logText(){
        console.log('some text');
    }
};

export class Example {
    constructor(){
        api.logText();
    }
}

然后,像这样使用它:

import { api, Example } from 'example';

api.logText = function() {
    console.log('my Text');
};

我通常不建议这样做,因为它会为同一模块的多个用户之间的使用冲突设置你,每个用户都试图以相互冲突的方式全局修改它。子类化模型(上面提到过)让模块的每个使用都以自己的方式自定义,而不会与模块的其他用法发生冲突。


推荐阅读