竟然2个月没写文章了, 我堕落了………

这是一篇阅读笔记, 原文: https://www.airpair.com/javascript/posts/the-mind-boggling-universe-of-javascript-modules

很久没看到这么通透的文章了. 我要记笔记(不是翻译是因为我总想扩展, 并且水平渣渣, 信达雅, 连信都做不到).

  • js看上去是一种玩具语言, 本身的全局变量导致根本无法构建大型应用(本身只有var)

  • leverage encapsulation, 代码的外延要能够被封闭, node之前js木有这个能力.

  • 最原始的 ad hoc方式:

    //这个方式主要目的是实现链式调用.
    var Zoo = (function() { 
      var getBarkStyle = function(isHowler) {
        return isHowler? 'woooooow!': 'woof, woof!';
      }; 
      var Dog = function(name, breed) {
        this.bark = function() {
          return name + ': ' + getBarkStyle(breed === 'husky');
        };
      };
      var Wolf = function(name) {
        this.bark = function() {
          return name + ': ' + getBarkStyle(true);
        };
      };
      return {
        Dog: Dog,
        Wolf: Wolf
      };
    })();
      
    //这里是调用方式, 丑陋的new方式.
    var myDog = new Zoo.Dog('Sherlock', 'beagle');
    console.log(myDog.bark()); // Sherlock: woof, woof!
      
    var myWolf = new Zoo.Wolf('Werewolf');
    console.log(myWolf.bark()); // Werewolf: woooooow!
    
  • 全局代码 vs ad-hoc

    • 全局代码副作用强烈, 性能也很容易出问题, 阅读困难, 代码组织地狱级难度.
    • 全局代码暴露实现细节, 会引起各种错综复杂的问题, 不利于分治调优
    • 互相之间的依赖, 传递依赖, 用全局都不知道咋搞了.
    • 全局代码很容易出现全局依赖.
    • 区分模块之后, 也比较容易做出代码的内聚.
  • ad - hoc的问题

    • 依旧定义了zoo这个全局变量, 类似jquery的$.
    • 代码脆弱fragile, zoo依旧可以被任意的代码影响到. 很容易这里正常, 但是, 那里就不正常了. 因为, 某段代码对zoo做了扩展.
    • 不可扩展scalable, 如果你有100个module, 地狱降临, 你被迫逐个引入, 如果不想麻烦就是所有模块一次性, 同步引入, 这个必然有爆表的性能问题.
    • 适得其反, 其实比不用模块更糟糕, counter-productive, 你必须手工解决依赖问题, 换个场景用这100个模块时, 你必须记忆这100个模块的内在逻辑, 以及使用逻辑(甚至于这个使用还是有顺序的).
  • 那么一个包加载器应该咋样呢?

    • 模块的注册机制, 基于aliases
    • 解除依赖, 基于依赖分析
    • 实例化模块, 基于工厂模式
    • 其实简单的说就是读入一个js, 然后, 做好自己该处理的, 再把剩下的交给js解释器.
  • 大魔王出现了 commonJS or AMD?

    • commonJS是
      • module require语法
      • node官方的加载器.
      • 同步加载的.
      • 语法简单
      • 可以保证执行顺序
      • 本身不能在浏览器执行, 不过broweserify和webpack可以帮他.
      • 同步加载导致加载时间比较长.
      • 依赖膨胀的很厉害, 会导致你的代码很容易引入非常巨大数目的依赖包.
    • 此时我又重新去了解了一下闭包, 建议还是能不用就不用.
    • AMD
      • define require方案
      • 可以异步加载
      • 自然适用于浏览器
      • 懒加载很方便
      • 异步加载如果思考不清楚会出现冲突
      • 不保证加载顺序
      • 语法会难于理解
  • ES6自带了

    • export import语法
    • 其实我们可以认为这些内容属于framework, 并不是语言本身的核心语法, 但是, js和java的区别就在于, 语言层面就包含了这些framework, js并不允许framework竞争. js允许竞争的只有包lib, 没有framework

作者的个人网站, 严重推荐: https://tiagorg.com

有用的参考链接
  • https://stackoverflow.com/questions/37050932/commonjs-imports-vs-es6-imports
如果在浏览器环境使用 import和export

js:

//文件尾部
export default out;
//或者
export {out1, out2, out3};
浏览器端也是一堆坑, 坑死人了.
//引入端这么写:
<script type="module">
  import {images} from '/show/images.js'

//输出端这么写:
//export default out;
export {
    out as images
};
</script>
不要相信其他写法, 比如下面这种就怎么搞都不可以:
<script type="module" src="/show/images.js"></script>

If you export function xyz, you must import { xyz }

If you export default function xyz, you must import xyz or import { default as xyz }
type=module之后, 会导致html里面直接注册事件失败.
 <input type="file" id="input" onchange="handleFiles(this.files)">
  <script type="module">
    function handleFiles() {
      alert('success') //这里不会被执行.
    }
  </script>

我猜测原因是: 因为type=module之后就是异步加载的了, 所以input里面写的onchange就失效了, 因为函数定义并没有被提升上去.

据说是scope问题, 我再试试.

  window.handlefiles=handlefiles; //这样就解决了.

正解再这里: https://stackoverflow.com/questions/44590393/es6-modules-undefined-onclick-function-after-import

然后这个讲的很清楚: https://www.contentful.com/blog/2017/04/04/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling/