Javascript 允许用户在上下文中修改导入的ES6模块功能

Javascript 允许用户在上下文中修改导入的ES6模块功能,javascript,ecmascript-6,module,es6-modules,Javascript,Ecmascript 6,Module,Es6 Modules,我对某事是否可能感到困惑 我创建了一个包含以下内容的模块: export function logText(){ console.log('some text'); } export class Example { constructor(){ logText(); } } 目的是让用户调用新示例启动模块逻辑 import { logText, Example } from 'example'; // Do some magic here to mo

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

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

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

export class Example {
    constructor(){
        logText();
    }
}
目的是让用户调用
新示例
启动模块逻辑

import { logText, Example } from 'example';

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

new Example();
最终用户是否可以修改日志文本?

有一种方法可以让用户做这样的事情,这是有道理的,否则他们必须将整个模块纳入自己的repo中,只是为了进行一些小的功能调整

我经常看到repo导出了很多功能,如果用户不需要手动重新生成几乎所有的功能,这些功能就没有用处,这使得它变得毫无意义。一个很好的例子是为什么他们甚至把导出的函数称为“API”。在那个例子中,这些是毫无意义的导出,更糟糕的是,如果有人试图将它们与主函数结合使用,就会导致问题。但是,如果您可以修改它们并让它们仍然运行,那么对我来说就有意义了

最终用户是否可以修改日志文本

不,这是不可能的,
import
绑定是不可变的,函数对象基本上是不可变的,不管它们包含什么代码

有一种方法可以让用户做这样的事情,这是有道理的,否则他们必须将整个模块纳入自己的repo中,只是为了进行一些小的功能调整

为什么不让log函数成为构造函数中的可选参数?通常,当某个东西是可变的时,它会变成一个参数

export class Example {
    constructor(log=logText){
        log();
    }
}
鉴于此:

import { logText, Example } from 'example';
最终用户是否可以修改日志文本

由于您对“修改日志文本”的含义不是很明确,我将介绍几个选项:

是否可以为变量
logText
重新分配一些其他函数

不,你不能那样做。使用
import
时,它会创建一个变量,该变量为
const
,无法分配给。即使它不是常量,也只是一个本地符号,不会影响其他模块对其
logText()
的使用。
导入
机制就是这样设计的。模块的加载器不应该能够替换模块的内部实现部分,这些内部实现部分不是专门设计用来替换的

能否从包含该函数的模块外部修改该函数内部的代码

不,你不能。模块中的代码位于其自身的功能范围内,这为其提供了隐私。您不能从模块外部修改该模块内的代码

您是否可以替换模块中的
logText()
函数,以便该类中的
Example
实现将使用您的
logText()
函数

不,您不能在模块外部执行此操作。您必须实际修改模块的代码本身,或者必须有人设计示例接口,使其具有示例对象使用的可替换或可修改的
logText()
函数

例如,
logText()

模块中未修改的代码:

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()
。但是,这根本不会影响示例的功能

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

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

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

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

我通常不建议这样做,因为它会使您在同一模块的多个用户之间产生使用冲突,其中每个用户都试图以相互冲突的方式全局修改该模块。子类化模型(如上所述)允许模块的每次使用都以自己的方式进行自定义,而不会与模块的其他用途发生冲突。

什么样的修改?功能之间的区别是“用户必须手动重新生成几乎所有的功能,使其变得毫无意义。”你的想法是
在这里做一些魔术来修改功能
?@vlaz修改一个导出函数和从头开始重建整个模块之间的区别。@FrankModica任何修改,这只是我能想到的最简单的例子。在该示例idk中,我希望发出警报,而不是控制台日志。但在一个现实世界的例子中,这取决于所讨论的函数,可能只是能够获取一个函数并执行完全相同的操作,然后触发一个事件。我能想到的唯一不同于@FelixKling的答案是在日志中构建“钩子”,如
onBeforeLog
onAfterLog
,或者让它提供关于什么样的日志记录的选项。你真的不想让人们彻底改变你的功能,对吗?您可能想定义它们可以以某种方式更改的内容。我不认为
import
s是不可变的,您肯定可以导入
对象
并更改其键/值,对吧?示例函数太基本了,无法用于实际解决方案,就像在实际使用中用于关键逻辑一样。为什么我看到这么多模块导出的函数在其他任何地方都不能工作,如果你不能用th做任何事情的话