导出原始类型

通过兼容性处理的几个例子,我们可以观察到 es6 module 和 commonjs 的导出值其实是不同的。
esmodule 和 commonjs 导出值的区别

  • esmodule 引用导出
  • commonjs 值导出

我们拿个具体的例子来说事,代码我拷贝过来了。

  1. /** ./src/index.js **/
  2. let title = require('./title');
  3. console.log(title.default);
  4. console.log(title.age);
  1. /** ./src/title.js **/
  2. export default 'title_name';
  3. export const age = 'title_age';
  1. ;(()=>{
  2. var modules = {
  3. './src/title.js':(module, exports, require)=>{
  4. require.r(exports);
  5. require.d(exports, {
  6. default: () => DEFAULT_EXPORT,
  7. age: () => age
  8. });
  9. const DEFAULT_EXPORT = 'title_name';
  10. const age = 'title_age';
  11. }
  12. }
  13. var cache = {};
  14. function require(moduleId){
  15. if(cache[moduleId]){
  16. return cache[moduleId].exports
  17. }
  18. var module = cache[moduleId] = {
  19. exports: {}
  20. };
  21. modules[moduleId](module, module.exports, require);
  22. return module.exports;
  23. }
  24. require.r = (exports) => {
  25. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  26. Object.defineProperty(exports, '__esModule', { value: true })
  27. }
  28. require.d = (exports, definition) => {
  29. for(var key in definition){
  30. Object.defineProperty(exports, key, { get: definition[key] })
  31. }
  32. }
  33. let title = require('./src/title.js');
  34. console.log(title.default);
  35. console.log(title.age);
  36. })()

ES6 Module 引用导出

在这个例子中 title.js 是一个 ES6 Module,所以他是一个引用导出。
我们修改一下代码,把 DEFAULT_EXPORT 和 age 的标识改成 var 方便后面修改值。用 setTimeout 延迟 1s 设置 age 的值为 new_title_age, 然后再 3s 后再打印结果

  1. ;(()=>{
  2. var modules = {
  3. './src/title.js':(module, exports, require)=>{
  4. require.r(exports);
  5. require.d(exports, {
  6. default: () => DEFAULT_EXPORT,
  7. age: () => age
  8. });
  9. // 将标识改成 var 方便后面修改
  10. var DEFAULT_EXPORT = 'title_name';
  11. var age = 'title_age';
  12. // 在 1s 之后改变 age 的值
  13. setTimeout(()=>{
  14. age = "new_title_age";
  15. }, 1000)
  16. }
  17. }
  18. var cache = {};
  19. function require(moduleId){
  20. if(cache[moduleId]){
  21. return cache[moduleId].exports
  22. }
  23. var module = cache[moduleId] = {
  24. exports: {}
  25. };
  26. modules[moduleId](module, module.exports, require);
  27. return module.exports;
  28. }
  29. require.r = (exports) => {
  30. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  31. Object.defineProperty(exports, '__esModule', { value: true })
  32. }
  33. require.d = (exports, definition) => {
  34. for(var key in definition){
  35. Object.defineProperty(exports, key, { get: definition[key] })
  36. }
  37. }
  38. let title = require('./src/title.js');
  39. console.log(title.default);
  40. // 在 3s 后打印 age
  41. setTimeout(()=>{
  42. console.log(title.age);
  43. }, 3000)
  44. })()

结果如下:
image.png
发现打印的变成了 new_title_age。说明 ES6 Module 中导出值之后,只要引用的那个变量变了,仍然会导致在引用这个模块的模块中值发生变化。

commonjs 值导出

我们再来看一下值导出是怎么样的。
我们为了方便,直接在 模块定义中加一个模块

;(()=>{
  var modules = {
    './src/title.js':(module, exports, require)=>{
      require.r(exports);
      require.d(exports, {
        default: () => DEFAULT_EXPORT,
        age: () => age
      });
      var DEFAULT_EXPORT = 'title_name';
      var age = 'title_age';

      setTimeout(()=>{
        age = "new_title_age";
      }, 1000)
    },
    // 新增一个 commonjs 模块
    './src/common.js':(module, exports, require) => {
      var age = 'title_age';
      exports.age = age;
      // 在 1s 之后改变 age 的值
      setTimeout(()=>{
        age = "new_title_age";
      }, 1000);
    }
  }

  var cache = {};
  function require(moduleId){
    if(cache[moduleId]){
      return cache[moduleId].exports
    }
    var module = cache[moduleId] = {
      exports: {}
    };
    modules[moduleId](module, module.exports, require);
    return module.exports;
  }

  require.r = (exports) => {
    Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    Object.defineProperty(exports, '__esModule', { value: true })
  }

  require.d = (exports, definition) => {
    for(var key in definition){
      Object.defineProperty(exports, key, { get: definition[key] })
    }
  }

  let title = require('./src/common.js');

  // 在 3s 后打印 age
  setTimeout(()=>{
    console.log(title.age);
  }, 3000)
})()

结果如下:
image.png
我们发现即使在 1s 后改变了导出的值,但是在引入模块中返回的值并没有改变,还是 title_age。这就是值引用。

导出引用类型

commonjs 导出引用地址:

  • 地址变了,无影响。
  • 如果地址对应的属性变了,有影响。
    //....
    var modules = {
      './src/common.js':(module, exports, require) => {
        var age = { x: 1 };
        exports.age = age;
        // 在 1s 之后改变 age 的值
        setTimeout(()=>{
          //age = { x: 2 }; 无影响 最终打印的还是 { x: 1 }
          age.x = 2; // 有影响 最终打印的就变成了 { x: 2 }
        }, 1000);
      }
    }
    //...