前端模块化学习:CommonJS规范、AMD规范、CMD规范、ES6规范

模块化

视频学习(讲的非常好): https://www.bilibili.com/video/BV18s411E7Tj/?spm_id_from=333.337.search-card.all.click

概述

概念

概念:

  1. 将一个复杂的程序序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起
  2. 内部数据与实现是私有的,只是向外部暴露一些接口(方法)与外部其它模块通信


IIFE(Immediately Invoked Function Expression): 立即调用函数表达式;自执行匿名函数 == 其实就是闭包

(function (version) {
    console.log('当前版本号:', version?version:'v1.0.0')
})('v1.1.1');

在这里插入图片描述

发展进程
发展1:全局function模块
  1. 全局function模块: 把不同的功能函数封装成不同的全局函数
function getName() {
}

function getYear() {
}
发展2:命名空间



2. 命名空间模块: 基于简单的对象封装

问题:数据不安全,外部可以直接修改内容模块的数据;所有模块成员直接暴露在外

//简单模式
let obj = {
    name: '',
    getName() {},
    getYear() {}
}

//外部直接修改,实例内容变量
obj.name = 'lrc'




发展3:IFFE:立即执行函数(闭包)- 绑定到window上

变量直接全部变私有

//复杂模式:IIFE:匿名函数自执行方式(闭包)
(function (win) {

    //变量直接变方法内私有,外部不可通过myUtils进行改变
    let version = '1.1.0';

    win.myUtils = {


        getVersion() {
            return version;
        },

        /**
         * 字符串是否不为空
         * @param content 字符串内容
         */
        strIsNotEmpty(content) {
            let result = content && content.length > 0;
            if ((typeof result) === 'string') {
                return result.length > 0;
            } else {
                return result ? true : false;
            }
        },

        /**
         * 字符串是否为空
         * @param content 字符串内容
         */
        strIsEmpty(content) {
            return !this.strIsNotEmpty(content);
        }

    }





})(window)


console.log(myUtils.getVersion())
console.log(myUtils.strIsEmpty(''))

在这里插入图片描述

发展4(现代):IFFE升级版直接返回对象不绑window变量上,外面由对象接收
let myUtils = (function (win) {

    //变量直接变方法内私有,外部不可通过myUtils进行改变
    let version = '1.1.0';
    return {
        getVersion() {
            return version;
        },
        /**
         * 字符串是否不为空
         * @param content 字符串内容
         */
        strIsNotEmpty(content) {
            let result = content && content.length > 0;
            if ((typeof result) === 'string') {
                return result.length > 0;
            } else {
                return result ? true : false;
            }
        },
        /**
         * 字符串是否为空
         * @param content 字符串内容
         */
        strIsEmpty(content) {
            return !this.strIsNotEmpty(content);
        }
    }
})()
console.log(myUtils.getVersion())
console.log(myUtils.strIsEmpty(''))

在这里插入图片描述

工具

本节源码: https://gitee.com/changenen/module-study

CommonJS规范 - (需使用工具编译打包)
概述

官网: https://commonjs.org/

维基百科: https://wiki.commonjs.org/wiki/Modules/1.1

特点: 需要编译打包后才能在浏览器使用

说明
1. 每个文件都可当作一个模块
2. 在服务器端:模块的加载是运行时同步加载的
3. 在浏览器端:模块需要提前编译打包处理
一个模块文件仅能写一次多写,后面会覆盖前面
一个模块文件能写多次
npm install 包名
基本语法
暴露模块
module.exports = 暴露的东西
exports.暴露的东西名字 = 暴露东西
引入模块
require(xxx)
第三方模块:模块名
自定义模块:模块文件路径
实现
服务端实现:nodejs(https://nodejs.org/en/)
浏览器端实现:browserify(https://browserify.org/)
规范实现(服务端):node

在这里插入图片描述

//package.json == 当前项目信息
npm init

//package-lock.json == 当前项目的依赖包信息、以及项目信息
//node_modules == 第三方依赖包
npm install 依赖包


module1.js

module.exports = {
    msg: 'module1',
    foo: function () {
        return this.msg;
    },
}


module2.js

module.exports = function () {
    return 'module2'
}


module3.js

exports.foo = function () {
    return 'foo() module3 invoked'
}

exports.bar = function () {
    return 'bar() module3 invoked'
}


app.js

//等价 let module1 = require('./module/module1')
let module1 = require('./module/module1.js')
let module2 = require('./module/module2.js')
let module3 = require('./module/module3.js')

// npm install uniq
//等价 let uniqMethod = require('uniq/uniq')
//等价 let uniqMethod = require('uniq')
let uniqMethod = require('uniq/uniq.js')


let moduleFooResult = module1.foo();
console.log(moduleFooResult)

let module2Result = module2();
console.log(module2Result)


let module3FooResult = module3.foo()
console.log(module3FooResult)

let module3BarResult = module3.bar()
console.log(module3BarResult)



let uniqResult = uniqMethod([1,2,3,4,3,2])
console.log(uniqResult)


# node服务端执行app.js代码
node app.js

在这里插入图片描述

规范实现(浏览器端):browserify
//打包工具
npm install -g browserify

//将require语法转成前端直接可用的语法
npm reuqire语法的js文件名  -o 转换成功后前端可直接引用的js文件名

在这里插入图片描述


module1.js

module.exports = {
    msg: 'module1',
    foo: function () {
        return this.msg;
    },
}


module2.js

module.exports = function () {
    return 'module2'
}


module3.js

exports.foo = function () {
    return 'foo() module3 invoked'
}

exports.bar = function () {
    return 'bar() module3 invoked'
}


app.js

//等价 let module1 = require('./module/module1')
let module1 = require('./module/module1.js')
let module2 = require('./module/module2.js')
let module3 = require('./module/module3.js')

// npm install uniq
//等价 let uniqMethod = require('uniq/uniq')
//等价 let uniqMethod = require('uniq')
let uniqMethod = require('uniq/uniq.js')


let moduleFooResult = module1.foo();
console.log(moduleFooResult)

let module2Result = module2();
console.log(module2Result)


let module3FooResult = module3.foo()
console.log(module3FooResult)

let module3BarResult = module3.bar()
console.log(module3BarResult)



let uniqResult = uniqMethod([1,2,3,4,3,2])
console.log(uniqResult)


文件转换

browserify js/src/app.js -o js/dist/bundle.js

在这里插入图片描述


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<!-- 直接引用app.js会报错,因为浏览器不支持require语法 -->
<!-- <script src="js/src/app.js"></script> -->
<!-- 使用browserify将app.js中的require语法转成浏览器可识别的语法 -->
<script src="js/dist/bundle.js"></script>

</html>

在这里插入图片描述

AMD规范 - (无需使用工具编译打包)
概述

AMD(Asynchronous Module Definition): 异步模块定义

作用: 专门用于浏览器端,模块的异步加载

文档:https://github.com/amdjs/amdjs-api/wiki/AMD

特点: 不需要编译打包方可直接在浏览器使用

无依赖的模块
有依赖的模块
基本语法
暴露模块
define(function(){ return 模块})
define(['module1','module2'],function(m1,m2){ reutrn 模块})
引入模块
require(['module1','module2'], function(m1,m2){})
规范实现(浏览器端):require.js

官网: https://requirejs.org/

Github: https://github.com/requirejs/requirejs

API

官网: https://requirejs.org/docs/api.html



定义模块(define)

//定义模块:不需要外部依赖
define(function() {
    return 当前模块暴露的模块东西
})


//写法1 定义模块:需要外部依赖
define(['依赖的模块名1','依赖的模块名2'], function(依赖的模块名1,依赖的模块名2) {
    return 当前模块暴露的模块东西
})
//写法2 定义模块:需要外部依赖
define(['require','依赖的模块名1', '依赖的模块名2'], function(require) {
    let moduleObj = require('依赖的模块名1')
    let moduleObj2 = require('依赖的模块名2')
    return 当前模块暴露的模块东西
})
//写法3 定义模块:需要外部依赖
define(function(require) {
    let moduleObj = require('依赖的模块名1')
    let moduleObj2 = require('依赖的模块名2')
    return 当前模块暴露的模块东西
})
//写法4 定义模块:需要外部依赖 类私commonjs的语法
define(function(require) {
    let moduleObj = require('依赖的模块名1')
    let moduleObj2 = require('依赖的模块名2')
    let exports
    
    exports.模块暴露的东西名字 = 当前模块暴露的模块东西

})



//特别注意:上述两种模块定义,配置、使用模块时,模块名可随意定义
//下面两种写法是等价的
//require.config({
requirejs.config({
    paths: {
        模块名1: '模块文件路径',
        模块名2: '模块文件路径',
    }
});


//==============================================

//定义模块:命名模块
define("当前模块名", ['依赖的模块名1','依赖的模块名2'], function(依赖的模块名1,依赖的模块名2) {
    return 当前模块暴露的模块东西
})

//特别注意:上述模块定义,配置、使用模块时,必须跟你define模块名一致,否则报错
//下面两种写法是等价的
//require.config({
requirejs.config({
    paths: {
        当前模块名: '模块文件路径',
    }
});



使用模块(require、requirejs)

(function (){

    //定义系统中使用的模块文件路劲,别加js后缀
    // requirejs.config({
    require.config({
        paths: {
            //不用加后缀js,否则会报错
            hasRelyModule: './module/hasRelyModule',
            noRelyModule: './module/noRelyModule',
            noRelyModuleObj: './module/noRelyModule',
            hasNameModule: './module/hasNameModule',
        }
    });


    //使用模块
    // requirejs(["hasRelyModule", "hasNameModule"], function (hasRelyModule,hasNameModule) {
    require(["hasRelyModule", "hasNameModule"], function (hasRelyModule,hasNameModule) {
        console.log(hasRelyModule.getCurrentModuleInfo())

        console.log(hasNameModule.getInfo())
    })

})();


加载定义非AMD规范暴露的包
ordinaryJs.js

var ordinaryJs = (function() {
    let moudleName = "ordinaryJs"
    let verison = "1.4.1"

    return {
        getMoudleInfo() {
            return `${moudleName}:${verison}`
        }
    }
})()


main.js

(function (){

    //定义系统中使用的模块信息
    // requirejs.config({
    require.config({
        paths: {
            notAmdSpecificationOrdinaryJs: './module/ordinaryJs'
        },
        shim: {
            notAmdSpecificationOrdinaryJs: {
                deps: [],
                exports: "ordinaryJs"
            },
        }
    });


    //使用模块
    // requirejs(["hasRelyModule", "hasNameModule"], function (hasRelyModule,hasNameModule) {
    require(['notAmdSpecificationOrdinaryJs'], function (notAmdSpecificationOrdinaryJs) {

        console.log("")
        console.log(notAmdSpecificationOrdinaryJs)
        console.log(notAmdSpecificationOrdinaryJs.getMoudleInfo())

    })

})();


main.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script data-main="js/main.js" src="js/lib/require2.3.6.js"></script>
</head>
<body>
</body>
</html>

在这里插入图片描述

使用

在这里插入图片描述

noRelyModule.js

//定义、暴露模块
define(function () {

    let version = 'v1.1.0'
    let moduleName = 'noRelyModule'

    function getModuleInfo() {
        return `${moduleName}:${version}`
    }


    return {
        getModuleInfo:getModuleInfo
    }
})


hasRelyModule.js

//定义、暴露模块
define(['noRelyModuleObj'], function (noRelyModuleObj) {

    let version = 'v1.2.1';
    let moduleName = 'hasRelyModule'

    function getCurrentModuleInfo() {
        return `${moduleName}:${version} === 使用到的依赖模块信息为:${noRelyModuleObj.getModuleInfo()}`
    }

    return {
        getCurrentModuleInfo: getCurrentModuleInfo
    }
})


main.js

(function (){

    //定义系统中使用的模块信息
    requirejs.config({
        paths: {
            //不用加后缀js,否则会报错
            hasRelyModule: './module/hasRelyModule',
            noRelyModule: './module/noRelyModule',
            noRelyModuleObj: './module/noRelyModule',
        }
    });


    //使用模块
    requirejs(["hasRelyModule"], function (hasRelyModule) {
        console.log(hasRelyModule.getCurrentModuleInfo())
    })

})();


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script data-main="js/main.js" src="js/lib/require2.3.6.js"></script>
</head>
<body>
</body>



</html>

在这里插入图片描述

CMD规范(Commonjs、AMD规范结合体) - (无需使用工具编译打包)
概念

CMD(Common Module Definition): 通用模块定义;模块需要时才会加载

特点: 不需要编译打包方可直接在浏览器使用

无依赖的模块
有依赖的模块
基本语法
暴露模块
define(function(require, exports, module){ exports.xx = 暴露的东西;module.exports = 暴露的东西;})
define(function(require,exports,module){require('./module2');require.async('./module3',function(n){}),exports.xxx=value});
引入模块
define(function(require){var m1=require('./module1');var m4=require('./module4');m1.show();m4.show();})
//定义有依赖的模块
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 m4=require('./module4');
    m1.show();
    m4.show();
})
规范实现(浏览器端):sea.js

官网: https://seajs.github.io/seajs/docs/#intro

Github: https://github.com/seajs/seajs

使用

在这里插入图片描述

在这里插入图片描述


module1.js

define(function(require,exports,module) {

    let moduleName = "module1"
    let version = '1.1.1'

    exports.getModuleInfo = function () {
        return `${moduleName}:${version}`
    }
})


module2.js

define(function(require,exports,module) {

    let moduleName = "module2"
    let version = '1.1.2'

    module.exports = {
        getModuleInfo: function () {
            return `${moduleName}:${version}`
        }
    }
})


module3.js

define(function(require,exports,module) {

    let module1 = require('./module1')
    let module2 = require('./module2')

    let moduleName = "module1"
    let version = '1.1.1'

    exports.getModuleInfo = function () {
        return `${moduleName}:${version} ===》 依赖${module1.getModuleInfo()}${module2.getModuleInfo()}`
    }
})


main.js

define(function(require) {
    
    //同步加载
    let module3 = require('./module/module3')
    console.log("")
    console.log(module3)
    console.log(module3.getModuleInfo())

    //异步加载
    let module2 = require.async('./module/module2', function (module2) {
        console.log("")
        console.log(module2)
        console.log(module2.getModuleInfo())
    })
})


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<script src="./lib/sea.js"></script>
<body>


</body>

<script>
    seajs.use("./main.js")
</script>

</html>

在这里插入图片描述

ES6规范(应用广泛、重要) - (需使用工具编译打包)
概念

文档: https://es6.ruanyifeng.com/#docs/module

特点: 需要编译打包后才能在浏览器使用

一个模块文件可写多次
一个模块文件仅能写一次
必须解构进行接收
基本语法
暴露模块
export
常规模块: export 函数定义/变量定义/对象定义
默认模块:export default 函数定义/对象定义
引入模块
import
常规模块、分别模块:import {} from '模块文件路径'
默认模块:import 自定义模块名 from '模块文件路径'
规范实现(浏览器端):Babel(转成ES5语法)、Browserify(编译打包成JS)

Babel官网: https://www.babeljs.cn/

特点: 需要编译打包后才能在浏览器使用

//将当前项目初始化成npm进行管理
npm init

//全局安装编译打包工具
npm install babel-cli browserify -g

//安装es6转es5语法工具
 npm install babel-preset-es2015 --save-dev
 
 //创建.babelrc文件 == 内容为下面的json
 {
  "presets": ["es2015"]
}
 
 
 //es6转成es5语法
 babel 源js文件目录 -d 转换后的文件输出目录
 
 //打包编译  browserify 主入口的js文件   -o  编译后浏览器可直接使用的js文件
 browserify .\js\es5\main.js -o .\js\dist\bundle.js

在这里插入图片描述

使用

在这里插入图片描述


module1.js

//分别暴露
export function foo1() {
    console.log("module1:foo1 invoked")
}


export function bar1() {
    console.log("module1:bar1 invoked")
}


export let info = 'module1'


module2.js

//统一暴露、常规暴露
function foo2() {
    console.log("module1:foo invoked")
}


function bar2() {
    console.log("module1:foo2 invoked")
}


let info = 'module2'


export {
    info,
    foo2,
    bar2
}


module3.js

//默认暴露 == 仅能写一次,不能写多个
export default () => {
    console.log("module3的箭头函数被调用")
}


module4.js

//默认暴露 == 仅能写一次,不能写多个
export  default {
    moduleName: 'module3',
    version: 'v1.1.0',
    getModuleInfo: function () {
        return `${this.moduleName}:${this.version}`
    }
}


main.js

//分别暴露、常规暴露使用的接收方式 == 解构获取
//语法1: import {模块暴露的东西名字} from '路径'

//默认暴露方式使用的接收方式
//语法2: import 接收的名字 from '路径'



import {foo1,bar1} from './module/module1'
import { foo2,bar2,info } from './module/module2'

import module3Content from './module/module3'

import module4Content from './module/module4'


console.log("")
foo1()
bar1()

console.log("")
foo2();
bar2();
console.log(info)

console.log("")
module3Content();


console.log("")
console.log(module4Content.getModuleInfo())


开始语法转换以及打包编译浏览器可运行的js文件

# 语法转换
babel .\js\src\ -d .\js\es5

# 打包编译
browserify .\js\es5\main.js -o .\js\dist\bundle.js

在这里插入图片描述


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="js/dist/bundle.js"></script>
</body>

</html>

在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值