Javascript 模块化 Export 命名子句导出 的一些想法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
haishiwuyuehao
V2EX    问与答

Javascript 模块化 Export 命名子句导出 的一些想法

  •  
  •   haishiwuyuehao 2020-10-31 23:20:10 +08:00 1533 次点击
    这是一个创建于 1836 天前的主题,其中的信息可能已经有所发展或是发生改变。

    export 常见有几种导出方式:命名行内导出,命名子句导出,默认导出

    命名子句导出是通过在大括号内指定导出的变量。

    const foo = 'foo'; const bar = 'bar'; export {foo}; export {bar as baz, foo}; export {foo, bar}; 
    在这里我想到,在 Javascript 中 {} 是一个块。每个块都有其作用域 因此子句导出是创建了一个单独的作用域,在该作用域内指定要导出的变量,但是这么想的话 在指定的作用域中又不能创建方法并返回 例如做到这样:export { hi(){} } 当我通过命名行导出和默认导出方法时: export function hi(){}; export default function(){}; 对于该 export 语句 1,创建了 hi 方法 并 2,返回 hi 方法的引用 给 export 3,export 创建 default 4,创建 匿名方法 5,返回匿名方法的引用给 default 从 1-2,3-5 来看,对于方法都是创建了一个作用域块的引用给到 export 。而在 Javascript 中 {} 也是简写对象的一种形式,在这里并不是为 export 创建一个对象,返回该对象的引用。 那么我的问题来了,如果对于 export “{}”并不是一个作用域块,不能在其中声明方法,初始变量等。也不是对象简写,那么 子句块的作用就只限于用 as 进行别命名了。真的有这个必要么?在导出命名行进行 as 不是更好吗?? 
    7 条回复    2020-11-01 11:40:56 +08:00
    yafoo
        1
    yafoo  
       2020-10-31 23:40:51 +08:00 via Android
    一直都记不清 export 有几种写法,也不知道为啥搞这么多写法
    noe132
        2
    noe132  
       2020-10-31 23:54:40 +08:00
    啥叫作用域块的引用?
    只有值才有引用,作用域块怎么说都不像是一种值吧?

    不要把 对象字面量语法和语句块语法 和这个大括号搞混在一起,这 3 个都不是 1 个东西,不是所有的大括号都是对象或者语句块,就比如模板字符串 `${a}`,建议把基本的语法学习一下

    你只需要知道 每个模块有自己的 namespace,export 只是单纯的在这个 namespace 上添加对应的绑定而已。
    export let a = 1
    export function b() { a += 1}
    export default 'c'
    export { a as d }
    这 4 个语句都是一样的,在 namespace 上添加绑定。通常 namespace 是一个对象,这个 namespace log 出来大致长这样
    { a: 1, b: function b(){ a += 1 }, _default: 'c', d: 1 }
    但不要把 namespace 看作简单的对象,首先它是不可修改的,其次所有的 export 都是对对应变量的绑定,而不是简单的把值导出来。比如如果你在模块内 修改 a = 2,那么 d 的值也会变成 2,因为 d 只是到 a 变量的一个绑定。
    import { a, b, d } from 'module'
    console.log(a, d) // 1, 1
    b()
    console.log(a, d) // 2, 2

    具体这个绑定是怎么实现的,通常你不需要关心,不同的运行环境或者编译器有不同的处理方式。
    noe132
        3
    noe132  
       2020-11-01 00:00:17 +08:00
    至于为啥不在定义变量的时候 as,设计的时候就是这么设计的,而且正好和 import 的 as 保持一致。如果硬要在变量定义时 as,我觉得这样的语法怎么设计都不会好看
    aaronlam
        4
    aaronlam  
       2020-11-01 00:37:11 +08:00
    据我所知,export {}; 这种 export 方法是方便你一股脑的把需要 named export 的塞进去 export,而不用每次都

    export const foo = 'bar'
    export const foo1 = 'bar1'
    export function func() {}
    haishiwuyuehao
        5
    haishiwuyuehao  
    OP
       2020-11-01 07:52:28 +08:00
    @noe132 我不理解你的 namespace 指的是什么。如果 export * from './myModule.js' ,按照你说的那么此刻 namespace 是怎么样的,在这里 再 export 与 myModule 模块相同的值,就会发生覆盖。此刻的 namespace 又是怎么样的。

    但是在 export 子句并非是一个对象,也不是一个作用域块。

    我理解,对于一个 module 来说,每个对 module 的引用都是在访同一个 module 。在该 module 的 export 里,每个 export 具体指向会被引用在被引用的对象中

    ```Javascript
    myModule.js

    export const foo = 'foo', bar = 'baz';
    export default class{
    constructor(baz){
    this.baz = baz || bar;
    console.log(this.baz);
    }
    }


    other.js

    import Baz, * as myModule from './myModule.js';
    let bax = new Baz();

    let bax2 = new myModule.default(myModule.foo);
    ```

    上面的代码就变成
    var myModule = (function(moduleConfig){
    moduleConfig.foo = 'foo';
    moduleConfig.bar = 'bar';
    return moduleConfig;
    })(myModule || {});

    var myModule = (function(moduleConfig){
    moduleConfig.default = class { ... }
    return moduleConfig;
    })(myModule || {});

    同样的,other.js 就变成这样
    var other= (function(moduleConfig){
    const Baz = myModule.default;
    const myModule = myModule;
    //操作 1
    let bax = new Baz();
    //操作 2
    let bax2 = new myModule.default(myModule.foo);
    })(other);

    只有这样才能解释的通,为什么修改在一个模块修改 myModule.js 的 foo = 'abc',其它模块访问到的 foo 是 abc 而不是 foo

    每个模块都是 IIFE,最终都将返回一个对象的引用给其它所有模块,以此同步所有模块访问到的是同一个模块。

    我的问题 还是 {},在 ecmascript 中,不管是 if(condition){} 还是 function(){} 都是表示一个块,都能在块中定义 function,命名变量。但是在 export 里 却不是这样,为什么,export 的子句要设置的如此奇特。export 子句未来是怎么样的
    noe132
        6
    noe132  
       2020-11-01 11:03:53 +08:00 via Android
    你的理解是错误的。你看到的 iife 只是 transpiler 对 esmodule 的一种实现。实际上可能根本没有 iife 。
    试想
    // a.js
    export const a = 1

    // b.js
    import { a } from 'a'
    console.log(a)

    transpiler 完全可以编译成
    const a = 1
    console.log(a)

    事实上 webpack 开启 concatenation plugin 后就是这样的结果。
    为啥总是要认为 export 是一个块?这不就是一个类似对象的语法么,和 import 语句是一样的,只是一种语法,和作用域块没有一点关系。这就不是一个语句块。如果这是个语句块,那你觉得写出来到底 export 了哪些东西?难道 export 了整个语句块?难道 import 语句的括号内我也要可以定义变量么?

    export 是完全静态的,export 只能存在模块顶部,不能在任何语句块内。export 只有标记的作用。要求能在代码不运行的情况分析所有的 import export 。如果按你的说法,export {} 里还能定义变量,写语句,那就不符合静态分析这一要求了。

    esmodule 只是一个规范,并不是具体的实现,并且规定了 export 不能变,那就不可能有 export 会有语句块这种问题。不要把 iife 的 module 实现直接和 esmodule 划等号

    至于 esmodule 是怎么实现的,那是 transpiler 或者 runtime 具体的事情。你不能因为某一种实现就认为所有的实现都有一样的特性,因为可能某些实现有 bug 或者限制
    haishiwuyuehao
        7
    haishiwuyuehao  
    OP
       2020-11-01 11:40:56 +08:00
    @noe132 没说过 export 子句是块。我问的是为什么不是块。变成块不好么。不过你说对,我还是在再解下
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4983 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 03:54 PVG 11:54 LAX 19:54 JFK 22:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86