模块化开发与规范化标准

1 篇文章 0 订阅
1 篇文章 0 订阅

模块化开发与规范化标准

一.模块化规范

1.1 Nodejs中的**CommonJS**规范:

1.一个文件就是一个模块

2.每个模块都有单独的作用域

3.通过module.exports导出成员

4.通过require函数载入模块

5.以同步模式加载模块

1.2 浏览器中的**AMD**规范(require.js)

1.用define定义模块

2.用require加载模块

AMD使用起来相对复杂,模块JS文件请求频繁

define('conor',['Module1', ‘Module2’], function (Module1, Module2) {
  function foo () {
    Module1.test();
  }
  return {foo: foo}
});
require(['conor'], function (math) {
  math.add(2, 3);
});
1.3 浏览器中的**CMD**规范(淘宝推出的seaJs)

1.CMD和AMD是同期出现的,使用也类似. 不过CMD语法上更贴近CommonJS

2.对于依赖的模块AMD是提前执行CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过)。

3.AMD推崇依赖前置(在定义模块的时候就要声明其依赖的模块),CMD推崇依赖就近(只有在用到某个模块的时候再去require——按需加载)。

define(function (requie, exports, module) {
    //依赖可以就近书写
    var a = require('./a');
    a.test();
    //软依赖
    if (status) {
        var b = requie('./b');
        b.test();
    }
});
1.4 ES6中的推出的**ESModule**规范

目前最主流的前端模块化方案,也是接下来主要学习的

二.ESModule语法特性

基本特性:

1.ESM默认是严格模式忽略'use strict',严格模式下this指向undefined`

2.ESM的每个模块都有单独的私有作用域

3.ESM是通过cors的方式请求外部JS模块的

4.ESM会延迟执行脚本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- 通过给script添加type="module",就可以用ESModule的标准执行其中的JS代码了 -->
    <script type="module">
        console.log('ESModule语法特性');
    </script>

    <!-- ESM默认是严格模式忽略'use strict',严格模式下this指向undefined -->
    <script type="module">
        var foo = '123'
        console.log(foo);
        console.log(this);
    </script>

    <!-- 非严格模式this指向window -->
    <script>
        console.log(this);
    </script>
    
    <!-- ESM的每个模块都有单独的私有作用域 -->
    <script type="module">
        console.log(foo);//报错
    </script>

    <!-- ESM是通过cors的方式请求外部JS模块的 -->
    <script type="module" src="https://code.jquery.com/jquery-3.0.0.min.js"></script>

    <!-- 正常情况下的script代码会阻塞p标签的渲染,ESM会延迟执行脚本 -->
    <script>
        alert('123')
    </script>
    
    <script type="module">
        alert('123')
    </script>
    
    <p>需要显示的内容</p>
</body>
</html>

2.1 ES Modules导入导出

用export导出,import导入.共有以下几种方式

2.1.1 export 单个导出
//模块导出文件
export var name = 'foo module'
export function hello () {
    console.log('hello')
}
export class Person {}
//模块导入文件
//import {name,hello,Person} from './module' 		//报错
//import {name,hello,Person} from 'module.js'   //报错,以字母开头会被认为是第三方模块
//模块引入必须是完整的./开头的相对路径  or /开头的觉得路径 or 一个cdn链接
import {name,hello,Person} from './module.js' 
console.log(name)
console.log(hello)
console.log(Person)

//或者
import * as mod from './module.js' 
console.log(mod.name)
console.log(mod.hello)
console.log(mod.Person)
2.1.2 export 统一导出
//模块导出文件
var name = 'foo module'
function hello () {
    console.log('hello Boy')
}
class Person {}

// as重命名,如果是default的话导入的时候就必须重命名
// 注意:这里导出的花括符不是对象的字面量,import的引入也不是对象的解构.而是ESM的一种固有的写法.
// 如果真的要导出一个对象的话可以用export default
export{name as default,hello as helloBoy,Person}
//模块导入文件
import {default as fooName,helloBoy,Person} from './module.js' 
console.log(fooName)
console.log(helloBoy)
console.log(Person)
2.1.3 默认导出
// 模块导出文件
var name = 'foo module'
var obj = {name}
// 这样写的话,可以用任意名接收这个对象
export default obj
//模块导入文件
//注意:这里导入的nameobj不是被拷贝的值而是一个地址,它会随着导出模块中变量的变化而变化.且这个值无法修改.
import nameobj from './module.js' 
console.log(nameobj.name)
2.1.4 只执行模块而不导入
//模块导入文件
import {} from './module.js' 
//或者
import './module.js' 
2.1.5 运行时按需使用模块
var modulePath = './module.js'
import {name} from modulePath; //报错

if(true){
	import {name} from './module.js'; //报错
}

import ('./module.js').then((res)=>{
	console.log()
})
2.1.6 默认导出和正常导出一起使用
//模块导出文件
var name = 'foo module'
function hello () {
    console.log('hello Boy')
}
class Person {}
export{hello as helloBoy,Person}
export default name
//模块导入文件
import {helloBoy,Person,default as name} from './module.js' 
//或者
import name,{helloBoy,Person} from './module.js' 
console.log(name)
console.log(Person)
2.1.7 导出导入成员
//模块导入文件
export {helloBoy,Person,default as name} from './module.js' 
//这里就访问不到helloBoy,Person,name

三. ES Modules兼容性

将浏览器中不识别的esmodule代码去交给babel转换,然后对那些import下来的文件去进行ajax请求把请求下来的文件再去进行转换从而支持esm .

但是这样子的话在那些支持的环境中就会运行两次代码. 这个问题可以通过添加nomodule属性解决 .

这种方式效率很低下,只适合在开发环境中.在生产环境中还是要预先把代码都编译好再部署 .

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script>
    <script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script>
    <script nomodule src="https://unpkg.com/promise-polyfill@8.1.3/dist/polyfill.min.js"></script>
    <script type="module">
        import {foo} from './module.js';
        console.log(foo);
    </script>
</body>
</html>

四.在node中使用ES Modules

在node中如果要使用ESM,js文件名后缀需要用.mjs

在node12.10.0版本中可以在package.json中写入一个type:"module"字段这样ESM的后缀可以正常的用.js但是CommonJS的话要用.cjs后缀

ESM中可以导入CommonJS模块类但不能在commonjs中require载入ESM

CommonJS模块类始终导出一个默认成员,所以接收的时候不能用{}

node的内置模块兼容了ESM的提取成员方式

运行node --experimental-modules app.mjs

//node中使用ESM

import {foo,hello,Person} from './module.mjs';
console.log(foo);

import fs from 'fs';
fs.writeFileSync('./foo.txt','es module working!');

// 内置模块兼容了ESM的提取成员方式
import {writeFileSync} from 'fs';
writeFileSync('./bar.txt','es module working!');

import _ from 'lodash';
console.log(_.camelCase('SSssSS'))

//不支持,因为第三方模块都是导出默认成员
// import { camelCase } from 'lodash'
// console.log(camelCase('ES Modules'))

// ESM中可以导入CommonJS模块类
// import mod from './commonjs.js'
// console.log(mod)

//不能直接提取
// import {foo} from './commonjs.js'
// console.log(foo) //报错

export const foo = 'es module export value'
//node中使用ESM

// module.exports = {
//     foo:'commonjs exports value'
// }

// 不能在node的commonjs中通过require载入ESM,但是在webpack中可以
// const mod = require('./index.mjs')
// console.log(mod)

//CommonJS始终导出一个默认成员,所以接收的时候不能用{}
exports.off="commonjs exports value"
//ESM中使用node

//加载模块函数:require
//模块对象:module
//导出对象别名:exports
//当前文件的绝对路径:__filename
//当前文件所在目录:__dirname

//ESM中没有CommonJS中的以上这些模块全局成员,前三种可以用import和export代替
//__filename和__dirname可以通过 import.meta.url
console.log(import.meta.url)
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
console.log(__filename)

//__dirname
import {dirname} from 'path';
const __dirname = dirname(__filename);
console.log(__dirname)

五.在node中使用ES Modules兼容性问题

在node低版本中ESM同样需要转译,这里可以使用babel去处理.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值