JavaScript模块化的演变
自执行函数(IIFE):
作用:马上执行这个函数,自执行函数(IIFE),不易读
(function(x){console.log(x);})(3);
易读版本:
(function(x){
return x *x;
})(3);
闭包引申:
回顾:
function create_counter(initial){
var x = initial || 0; //如果initial没有值,那么采用后面的0
return {
//对象
inc:function(){
x+=1;
return x;
}
}
}
var c1 = create_counter();
console.log(c1.inc());
console.log(c1.inc());
console.log(c1.inc());
var c2 = create_counter(10);
console.log(c2.inc());
console.log(c2.inc());
console.log(c2.inc()); */
箭头函数:
function (x){
return x * x;
}
上述代码等价于下面:
x => x*x;
箭头函数的无参、单参、双参、多参的格式:
//无参
()=>3;
//单参
x =>{
if(x > 0){
return x*x;
}else{
return -x*x;
}
}
//双参
(x,y) => x*x+y*y;
//多参
(x,y,...rest)=>{
}
this指向的引入以及发展:
this的指向在有无use strict
会不同的,我们通过几段不同的代码段引入this以及this指向的发展。
'use strict';
//1版-->正常使用
var xiaoming = {
name:'小明',
birth:2000,
age:function(){
var y = new Date().getFullYear();
return y - this.birth;
}
};
console.log(xiaoming.age());
//2版:
'use strict';
/*
严格模式:
xiaoming.age() 可以得到结果,
getAge()显示报错--> Cannot read property 'birth' of undefined
*/
function getAge(){
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name:'小明',
birth:2000,
age:getAge
};
console.log(xiaoming.age());
console.log(getAge());
前两个版本暂时还是没有引出this以及指向,下面看第三个版本,这个版本会有较大的改变,在不在strict中的结果也会不一样。
'use strict';
/*
严格模式下:会报错,Cannot read property 'birth' of undefined
非严格模式下:NaN not a number,浏览器不会爆红,可能指向window
*/
var obj = {
birth:2000,
getAge:function(){
function GetAgeFormBirth(){
var y = new Date().getFullYear();
return y - this.birth;
}
return GetAgeFormBirth();
}
};
console.log(obj.getAge());
这是js的遗留问题,为了解决这个问题,我们可以使用变量保存this的指向,如版本四:
'use strict';
var obj = {
birth:2000,
getAge:function(){
//保存thisz指向
var that = this;
function GetAgeFormBirth(){
var y = new Date().getFullYear();
return y - that.birth;
}
return GetAgeFormBirth();
}
};
console.log(obj.getAge());
但是这种表述方式比较麻烦,代码量也有些多,我们可以采用箭头函数来实现:
//这是个对象
'use strict';
var obj = {
birth:2000,
getAge:function(){
var b = this.birth;
var fn = ()=> new Date().getFullYear()-this.birth;
return fn();
}
};
console.log(obj.getAge());
模块化演变:
模块化演变是为了初学者一步一步实现和解决代码的冗余、复用性、命名污染问题。
模块演变1:
缺点已在代码块中标明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- html --》"" -->
<!-- js --》'' -->
<!-- 使用内嵌脚本 -->
<!--
缺点:
复用性 很低
1.缺乏依赖解析
2.全局命名空间污染的问题
-->
<h1>
the answer is <span id="answer"></span>
</h1>
<script>
function add(a,b){
return a+b;
}
function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
for(index =0;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
function sum(arr){
return reduce(arr,add);
}
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
</script>
</body>
</html>
模块演变2:
add.js
function add(a,b){
return a+b;
}
reduce.js
function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
for(index =0;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
sum.js
function sum(arr){
return reduce(arr,add);
}
main.js
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<!-- script标签引入JavaScript -->
<!-- 缺点:
必须保证js的引用顺序正确
同样缺乏依赖解析
同样有命名冲突的问题
-->
<script src = "./add.js"></script>
<script src = "./reduce.js"></script>
<script src="./sum.js"></script>
<script src = "./main.js"></script>
</body>
</html>
模块演变3:
myApp.js
// 空对象
var myApp = {
};
add.js
// 立即执行函数
(function (){
// 将add放入myApp中
myApp.add = function(a,b){
return a+b;
}
})();
reduce.js
// 立即执行函数IIFE
(function (){
// 将reduce放入myApp中
myApp.reduce = function(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
})();
sum.js
// 立即执行函数
(function (){
// 将sum放入myApp中
myApp.sum = function(arr){
return myApp.reduce(arr,myApp.add);
}
})();
main.js
/**
* @description:
* @param {*}
* @return {*}
*/
/* (function(){
var values = [1,2,3,4,5,6,7,8,9];
var answer = myApp.sum(values);
document.getElementById("answer").innerHTML = answer;
}); */
(function(app){
var values = [1,2,3,4,5,6,7,8,9];
var answer = myApp.sum(values);
document.getElementById("answer").innerHTML = answer;
})(myApp);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<script src="./myapp.js"></script>
<script src="./reducec.js"></script>
<script src="./sum.js"></script>
<script src="./add.js"></script>
<script src="./main.js"></script>
</body>
</html>
模块演变4:
采用require.js来实现。
为什么要使用require.js来实现:
在正式开发的项目中,随着js的外部引用文件越来越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序,依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
在开发中,有一个网页三秒原则
;
网页三秒原则:
当用户的在请求一个网站的时候,响应时间超过三秒钟,大部分用户将关闭或者重新刷新网页,用户体验很不爽。
所以require.js就解决上述问题:
实现js文件的异步加载,避免网页失去响应;
管理模块之间的依赖性,便于代码的编写和维护。
require.js的AMD格式规范:
// main.js
define(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
define()函数接受的参数。
第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块;
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中
如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,且指明该模块的依赖性。
define()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
以下是模块演变4的实现代码:
index.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<!-- 入口点是main -->
<!-- require加载了main.js的依赖,也会加载它依赖的依赖 -->
<!-- 带来的问题:
1. 降低一些性能
-->
<script data-main="main" src = "require.js"></script>
</body>
</html>
data-main属性的作用是,指定网页程序的主模块
main.js
define(['sum'],function(sum){
var value = [1,2,3,4,5,6,7,8,9];
var answer = sum(value);
document.getElementById('answer').innerHTML = answer;
})
sum.js
define([
'add',
'reduce'
], function(add, reduce) {
var sum = function(arr){
return reduce(arr,add);
}
return sum;
});
reduce.js
define([], function(arr,iteratee){
var reduce = function(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
return reduce;
});
add.js
define([],function(){
var add = function(a,b){
return a+b;
}
return add;
})
分析上述代码的执行流程:
- 先加载index.html以及require.js文件,找到模块的主入口(main.js)
- 加载main.js,由于main中依赖sum.js
- 再加载sum.js,sum中依赖add.js以及reduce.js
- 再加载add.js以及reduce.js
- 最后全部依赖执行完成后,回调得到的结果
执行效果以及文件加载顺序的观察:
模块演变5:
基于commonJS规范以及browserify浏览器端的模块演变
什么是browserify:
browserify是专注于解决按照CommonJS规范书写的模块能够在浏览器中使用问题的构建工具。
CommonJS规范:
- 每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见
- 每个模块内部,
module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。
下载方式:
npm install -g browserify
代码如下:
index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>
The Answer is <span id="answer"></span>
</h1>
<!-- browserify .\main.js -o bundle.js 打包-->
<script src="bundle.js"></script>
</body>
</html>
注意点:引用的js的文件是与我们打包命令时 -o后面名字对应的。
main.js
var sum = require('./sum');
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
sum.js
var reduce = require('./reduce');
var add = require('./add');
module.exports = function(arr){
return reduce(arr,add);
};
reduce.js
module.exports = function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
};
add.js
module.exports = function add(a,b){
return a+b;
};
打包方式:
browserify .\main.js -o bundle.js //window中
效果图:
运行查看加载信息:
可以与require.js的加载方式做对比,理解两者的不同以及相同的地方。
扩展:
require.js VS browserify
- require.js是模块加载器;browserify是预编译工具
- require.js遵循的是AMD规范;browserify遵循的是CommonJS规范
- require.js是在浏览器端运行期分析依赖;browserify在服务器端编译期就进行了依赖分析,通过每个模块的外部接口获取信息
结束:
如果你看到这里或者正好对你有所帮助,希望能点个关注或者推荐,感谢;
有错误的地方,欢迎在评论指出,作者看到会进行修改。
JavaScript模块化的演变的更多相关文章
- JavaScript模块化演变 CommonJs,AMD, CMD, UMD(一)
原文链接:https://www.jianshu.com/p/33d53cce8237 原文系列2链接:https://www.jianshu.com/p/ad427d8879cb 前端完全手册: h ...
- Javascript模块化规范
Javascript模块化规范 一.前端js模块化由来与演变 CommonJS 原来叫 ServerJS,推出 Modules/1.0 规范后,在 Node.js 等环境下取得了很不错的实践.09年下 ...
- JavaScript 模块化
当项目越来越大时,会遇到一些问题: 1.命名冲突 2.文件依赖 所有就有了javascript模块化开发概念. 模块化开发的演变: 1.函数块:最开始用全局函数将代码块包括在函数体内,然后把很多函数写 ...
- Javascript模块化编程(三):require.js的用法
Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...
- Javascript模块化编程(二):AMD规范
Javascript模块化编程(二):AMD规范 作者: 阮一峰 原文地址:http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_d ...
- Javascript模块化编程(一):模块的写法
Javascript模块化编程(一):模块的写法 作者: 阮一峰 原文链接:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html ...
- Javascript模块化编程(二):AMD规范(转)
这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要 ...
- Javascript模块化编程(一):模块的写法(转)
随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...
- Javascript模块化开发,使用模块化脚本加载工具RequireJS,提高你代码的速度和质量。
随着前端JavaScript代码越来越重,如何组织JavaScript代码变得非常重要,好的组织方式,可以让别人和自己很好的理解代码,也便于维护和测试.模块化是一种非常好的代码组织方式,本文试着对Ja ...
随机推荐
- Ubuntu 软件更新 系统升级
注意:操作前请先切换root权限 sudo su 1.软件更新 更新源 apt-get update 更新软件 apt-get upgrade 2.系统升级 安装系统更新 apt-get dist-u ...
- origin2018去掉demo水印
消除demo字样 有的origin破解完成后,使用没问题,但导出的图有demo水印.其实不需要重装,只需要下载一个补丁即可解决. 1. 把下载到的origin.exe复制到安装文件夹 2. 双击执行一 ...
- element-ui 的el-select如何不显示value,显示value对应的label值
有时根据需要,我们根据v-model的值绑定option, 想要的效果: 实际的效果: 原因: value的格式存在问题,数据库读取到的数据不一定为number类型,需要手动转换. 第一种 <t ...
- Go语言安装配置
一.Go语言下载 官方下载地址:https://golang.google.cn/dl/ 选择自己需要的版本下载即可. 二.Go语言安装 下载完成之后,双击go1.16.4.windows-amd64 ...
- Java核心技术卷阅读随笔--第4章【对象与类】
对 象 与 类 4.1 面向对象程序设计概述 面向对象程序设计(简称 OOP) 是当今主流的程序设计范型, 它已经取代了 20 世纪 70 年代的" 结构化" 过程化程序设计开发技 ...
- Git 分支基本命令
1. 查看当前分支 (git branch) 2. 创建分支 (git branch 分支名) 3.切换分支(git checkout 分支名) 4.分支上的常规操作 5.分支的合并 (git che ...
- SpringBoot2 集成测试组件,七种测试手段对比
一.背景描述 在版本开发中,时间段大致的划分为:需求,开发,测试: 需求阶段:理解需求做好接口设计: 开发阶段:完成功能开发和对接: 测试上线:自测,提测,修复,上线: 实际上开发阶段两个核心的工作, ...
- 针对Spring MVC的Interceptor内存马
针对Spring MVC的Interceptor内存马 目录 针对Spring MVC的Interceptor内存马 1 基础拦截器和调用流程的探索 1.1 基础拦截器 1.2 探索拦截器的调用链 1 ...
- TVM 优化 ARM GPU 上的移动深度学习
TVM 优化 ARM GPU 上的移动深度学习 随着深度学习的巨大成功,将深度神经网络部署到移动设备的需求正在迅速增长.与桌面平台上所做的类似,在移动设备中使用 GPU 既有利于推理速度,也有利于能源 ...
- ADAS可行驶区域道路积水反光区域的识别算法
ADAS可行驶区域道路积水反光区域的识别算法 Water logging area reflecting recognition algorithm for ADAS 1. 工程概要 1.1 概述: ...