Skip to content

以下代码输出什么

javascript
({}+{}).length
([]+[]).length
(function(){}).length

{}.toString => "[object Object]" 所以第一个是30

[].toSting => "" 所以第二个是0 ( [1,2,3].toString() => "1,2,3" )

函数的长度是形参的个数,所以是0

扩展(function(){})+{} => 'function(){}[object Object]'


模块化

CommonJS

服务端解决方案,加载速度快(模块文件一般存在本地硬盘) Commonjs规定,每一个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性是对外的接口(module.exports),加载某个模块,就是加载这个exports属性

  • 每一个文件是一个模块,有自己的作用域。在文件内定义的变量、函数等都是私有的,对其他文件不可见
  • 运行时加载,只能在运行时确定一些东西
  • 同步加载,只有加载完成才能执行后序操作
  • 导出时都是值拷贝,即使导出的值变了,导入的值也不会变,如果要更新导入的值,需要重新导入
  • 模块在首次执行后会缓存,再次加载只返回缓存结果,若想再次执行,可清除缓存
  • 模块加载的顺序是代码出现的顺序

基本语法:
暴露模块:module.exports = value或exports.xxx = value
引入模块:require(xxx)

因为nodejs主要用于服务器编程,模块文件一般已经存在在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式 。如果是浏览器环境,要从服务器加载模块,使用commonJS需要等到所有模块都下载完并运行后才能使用,阻塞后面代码的运行。所以浏览器需要采用非同步的方式。

AMD

会编译成require/exports来执行(RequireJS)

使用异步方式加载模块,模块的加载不影响后面代码的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数

定义暴露模块

// 定义没有依赖的模块

define(function () {
    return 模块
})

// 定义有依赖的模块
define(['module1', 'module2'], function(m1, m2)) {
    return 模块
}

引用模块

require(['module1', 'module2'], function(m1, m2) {
    // 使用m1,m2
})
CMD

专门用于浏览器端,异步加载模块,使用模块时才会加载执行,整合了CommonJS和AMD的特点

定义暴露模块

// 定义没有依赖的模块
define(function(require, exports, module) {
    exports.xxx = value
    module.exports = value
})

// 定义有依赖的模块
define(function(require, exports, module) {
    // 引入依赖的模块 - 同步
    var module2 = require('./module2')
    
    // 引入依赖模块 - 异步
    require.async('./module3', function(m3) {
    })
    
    // 暴露模块
    exports.xxx = value
})

引入使用模块


define(function (require) {
    var m1 = require('./module1')
    var m2 = require('./module2')
    
    m1.show()
    m2.show()
    
})
ES6

使用import和export形式导入和导出模块,
异步导入
导入和导出的值都指向一个内存地址,导入值会随导出值变化
会编译成require/exports执行。
编译阶段,import会被提到头部,首先执行
允许动态加载模块import()函数

import('/modules/myModule.mjs').then((module) => {
    // 模块已经导入
})
对比

ES6输出值的引用,CommonJS输出值的拷贝
ES6模块编译时输出接口,CommonJS运行时加载
ES6异步加载模块,CommonJS同步加载模块