《前端JavaScript面试技巧》学习笔记(11) 模块化

知识点

1: 不使用模块化的情况
2:使用模块化
3: AMD
4: CommonJS


  • 不使用模块化的情况
    有三个文件util.js, a-util.js , a.js ; util.js 是最底层封装的, a-util.js是基于util.js进一步, a.js 直接调用 a-util.js
//util.js        getFormatDate函数
function getFormatDate(date,type){
  //type===1返回2017-07-17
  //type===2返回2017年7月17日
  //...
}

//a-util.js        aGetFormatDate函数 使用getFormatDate
function aGetFormatDate(date){
  //要求返回 2017年7月17日
  return getFormatDate(date,2)
}

//a.js 
var dt=new Date()
console.log(aGetFormatDate(dt));

使用

<script type="text/javascript" src="util.js"></script>
<script type="text/javascript" src="a-util.js"></script>
<script type="text/javascript" src="a.js"></script>
<!--1: 这些代码中的函数必须是全局变量,才能暴露给对方使用. 全局变量污染-->
<!--2: 知道要 a.js 引用 a-util.js,但是其他人知道还需要依赖于 util.js吗? -->

不使用模块化的问题:
1.js文件引入顺序必须遵循函数层级引用的顺序,最先引入util.js,然后a-util.js,以此类推
2.这些代码中的函数必须是全局变量,才能暴露给使用方,会有全局变量污染的问题
3.a.js知道要引用a-util.js,但是它并不知道还依赖于util.js,代码逻辑并不清晰,所以要使用模块化


  • 使用模块化
// 理想状态下的模块化的逻辑
//util.js
export{
getFormatDate:function(date,type){
  //type===1返回2017-07-17
  //type===2返回2017年7月17日
  //...
}
}

//a-util.js
var getFormatDate=require('util.js')
export{
aGetFormatDate:function(date){
  //要求返回 2017年7月17日
  return getFormatDate(date,2)
}
}

//a.js
var aGetFormatDate=require('a-util.js')
var dt = new Date()
console.log(aGetFormatDate(dt));

1.直接使用<script type="text/javascript" src="a.js"></script>即可,其它会根据依赖关系自动引用
2.在util.jsa-util.js中没有使用全局变量,不会带来污染和覆盖
3.以上代码只是理想中的效果,用于描述模块化的思想,和实际语法相比略有出入


  • AMD (异步模块定义)
    • A:异步 M:模块 D:定义
    • require.js requirejs.org
    • 全局define函数
    • 全局require函数 (只有 define 过的函数才能被 require)
    • 被依赖 JS会自动异步加载

使用requirejs完成刚才的例子

//util.js
define(function() {
    var util = {

        getFormatDate: function(date, type) {
            var date = new Date();
            var add = function(s) {
                if (s.toString().length === 1) {
                    s = "0" + s;
                }
                return s;
            }
            var year = date.getFullYear();
            var mounth = date.getMonth() + 1;
            var day = date.getDate();

            if (type === 1) {
                var time = add(year) + '-' + add(mounth) + '-' + add(day);
                return time
            }
            if (type === 2) {
                var time = year + '年' + mounth + '月' + day + '日';
                return time
            }
        }
    }
    return util
})
//a-util.js
define(['util.js'], function(util) {
    var aUtil = {
        aGetFormatDate: function(date) {
            return util.getFormatDate(date, 2)
        }
    }
    return aUtil
})
//a.js
define(['a-util.js'], function(aUtil) {
    var a = {
        printDate: function(date) {
            console.log(aUtil.aGetFormatDate(date))
        }
    }
    return a
})
//main.js
require(['a.js'], function(a) {
    var date = new Date()
    a.printDate(date)
})
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <p>AMD Test</p>
        <script src="require.js" data-main="main.js"></script>
    </body>
</html>

  • CommonJS
  • CommonJS是 Nodejs模块化规范,现在被大量用前端
  • 前端开发依赖的插件和库,都可以从npm获取
    构建工具高度自动化,使npm成本非常低
  • CommonJS本身不会异步加载JS,而是一次性同步加载出来
  • module.exports = {aaa: ..., bbb: ...} 输出模块,require (xxx.js) 引用模块
    使用CommonJS
//util.js
//需要吐出的内容,直接exports
module.exports = {
    getFormatDate: function(date,type) {
        if (type === 1) {
            return '2017-09-23'
        }
        if (type === 2) {
            return '2017年9月23日'
        }
    }
}

//a-util.js
//需要获取什么东西,直接var一个变量赋值成require('xx.js')
var util = require('util.js')
module.exports = {
    aGetFormatDate: function(date) {
        return util.getFormatDate(date,2)
    }
}
  • AMD 和 CommonJS 的使用场景
  • 需要异步加载 JS, 使用 AMD
  • 使用了 npm 之后,建议使用 CommonJS

  • 用 Webpack 演示构建工具

  • 前提: 首先需要安装node.js, npm

  • npm介绍
    npm(node package manager)nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等)

使用npm安装插件:命令提示符执行`npm install <name> [-g] [--save-dev]`
-g:全局安装 ,全局安装可以通过命令行在任何地方调用它
--save:将保存配置信息至package.json;
-dev:保存至package.json的devDependencies节点,只在开发环境下依赖这个包,不指定-dev将保存至dependencies节点;dependence:依赖
为什么要保存至package.json?因为node插件包相对来说非常庞大,所以不加入版本管理,将配置信息写入package.json并将其加入版本管理,其他开发者对应下载即可(命令提示符执行npm install,则会根据package.json下载所有需要的包,npm install --production只下载dependencies节点的包)
使用npm卸载插件:npm uninstall <name> [-g] [--save-dev]  PS:不要直接删除本地插件包
使用npm更新插件:npm update <name> [-g] [--save-dev]
更新全部插件:npm update [--save-dev]
当前目录已安装插件:npm list
选装cnpm:由于访问国外服务器不稳定,可使用淘宝 npm 镜像,命令提示符执行`npm install cnpm -g --registry=https://registry.npm.taobao.org`
注:cnpm跟npm用法完全一致,只是在执行命令时将npm改为cnpm 即可

步骤:

1: 初始化包的配置

npm init  //把目录当成一个包
package name: (webpack) webpack-test
version: (1.0.0)
description: it's webpack test item
entry point: (index.js)
test command:
git repository:
keywords:
author: tangshuo24@163.com
license: (ISC)
//根据需求填写内容

2:安装 webpack:

  • npm install webpack --save-dev

3: 配置webpack
思路: 通过module.exports 输出一个东西,然后同过 require 去获取,获取之后再将它返回给一个变量,通过这个变量去执行函数

  • package.json文件(配置信息)
{
  "name": "webpack-test",
  "version": "1.0.0",
  "description": "it's webpack test item",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack"
  },
  "author": "tangshuo24@163.com",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.2.1"
  },
  "devDependencies": {
    "webpack": "^3.6.0"
  }
}
  • webpack.config.js
var path = require('path') //获取node.js 的path对象,不用理解它
var webpack = require('webpack') //获取刚才安装的webpack

//输出一个对象
module.exports = {
    context: path.resolve(__dirname, './src'), //找到src目录
    entry: { //入口,在src下
        app: './app.js'
    },
    output: { //打包后的文件存放的地方
        path: path.resolve(__dirname, './dist'), //输出至dist目录
        filename: 'bundle.js' //输出文件名
    },
    //压缩插件
    plugins:[
        new webpack.optimize.UglifyJsPlugin()
    ]
}
  • app.js
//app.js //调用npm安装的jQuery
var $ = require('jquery')
var $root = $('#root')
$root.html('<p>这是通过 jQuery 创建的文本</p>')

  • html
<body>
    <div>test</div>
    <div id="root"></div>
    <script src='dist/bundle.js'></script>
</body>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容