自执行函数(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就解决上述问题:

  1. 实现js文件的异步加载,避免网页失去响应;

  2. 管理模块之间的依赖性,便于代码的编写和维护。

require.js的AMD格式规范:

// main.js

define(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){

    // some code here

});

define()函数接受的参数。

  1. 第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块;

  2. 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。

  3. 模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中

  4. 如果这个模块还依赖其他模块,那么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;
})

分析上述代码的执行流程:

  1. 先加载index.html以及require.js文件,找到模块的主入口(main.js)
  2. 加载main.js,由于main中依赖sum.js
  3. 再加载sum.js,sum中依赖add.js以及reduce.js
  4. 再加载add.js以及reduce.js
  5. 最后全部依赖执行完成后,回调得到的结果

执行效果以及文件加载顺序的观察:

模块演变5:

基于commonJS规范以及browserify浏览器端的模块演变

什么是browserify:

browserify是专注于解决按照CommonJS规范书写的模块能够在浏览器中使用问题的构建工具。

CommonJS规范:

  1. 每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见
  2. 每个模块内部,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模块化的演变的更多相关文章

  1. JavaScript模块化演变 CommonJs,AMD, CMD, UMD(一)

    原文链接:https://www.jianshu.com/p/33d53cce8237 原文系列2链接:https://www.jianshu.com/p/ad427d8879cb 前端完全手册: h ...

  2. Javascript模块化规范

    Javascript模块化规范 一.前端js模块化由来与演变 CommonJS 原来叫 ServerJS,推出 Modules/1.0 规范后,在 Node.js 等环境下取得了很不错的实践.09年下 ...

  3. JavaScript 模块化

    当项目越来越大时,会遇到一些问题: 1.命名冲突 2.文件依赖 所有就有了javascript模块化开发概念. 模块化开发的演变: 1.函数块:最开始用全局函数将代码块包括在函数体内,然后把很多函数写 ...

  4. Javascript模块化编程(三):require.js的用法

    Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...

  5. Javascript模块化编程(二):AMD规范

    Javascript模块化编程(二):AMD规范   作者: 阮一峰 原文地址:http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_d ...

  6. Javascript模块化编程(一):模块的写法

    Javascript模块化编程(一):模块的写法 作者: 阮一峰 原文链接:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html ...

  7. Javascript模块化编程(二):AMD规范(转)

    这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要 ...

  8. Javascript模块化编程(一):模块的写法(转)

    随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...

  9. Javascript模块化开发,使用模块化脚本加载工具RequireJS,提高你代码的速度和质量。

    随着前端JavaScript代码越来越重,如何组织JavaScript代码变得非常重要,好的组织方式,可以让别人和自己很好的理解代码,也便于维护和测试.模块化是一种非常好的代码组织方式,本文试着对Ja ...

随机推荐

  1. Ubuntu 软件更新 系统升级

    注意:操作前请先切换root权限 sudo su 1.软件更新 更新源 apt-get update 更新软件 apt-get upgrade 2.系统升级 安装系统更新 apt-get dist-u ...

  2. origin2018去掉demo水印

    消除demo字样 有的origin破解完成后,使用没问题,但导出的图有demo水印.其实不需要重装,只需要下载一个补丁即可解决. 1. 把下载到的origin.exe复制到安装文件夹 2. 双击执行一 ...

  3. element-ui 的el-select如何不显示value,显示value对应的label值

    有时根据需要,我们根据v-model的值绑定option, 想要的效果: 实际的效果: 原因: value的格式存在问题,数据库读取到的数据不一定为number类型,需要手动转换. 第一种 <t ...

  4. Go语言安装配置

    一.Go语言下载 官方下载地址:https://golang.google.cn/dl/ 选择自己需要的版本下载即可. 二.Go语言安装 下载完成之后,双击go1.16.4.windows-amd64 ...

  5. Java核心技术卷阅读随笔--第4章【对象与类】

    对 象 与 类 4.1 面向对象程序设计概述 面向对象程序设计(简称 OOP) 是当今主流的程序设计范型, 它已经取代了 20 世纪 70 年代的" 结构化" 过程化程序设计开发技 ...

  6. Git 分支基本命令

    1. 查看当前分支 (git branch) 2. 创建分支 (git branch 分支名) 3.切换分支(git checkout 分支名) 4.分支上的常规操作 5.分支的合并 (git che ...

  7. SpringBoot2 集成测试组件,七种测试手段对比

    一.背景描述 在版本开发中,时间段大致的划分为:需求,开发,测试: 需求阶段:理解需求做好接口设计: 开发阶段:完成功能开发和对接: 测试上线:自测,提测,修复,上线: 实际上开发阶段两个核心的工作, ...

  8. 针对Spring MVC的Interceptor内存马

    针对Spring MVC的Interceptor内存马 目录 针对Spring MVC的Interceptor内存马 1 基础拦截器和调用流程的探索 1.1 基础拦截器 1.2 探索拦截器的调用链 1 ...

  9. TVM 优化 ARM GPU 上的移动深度学习

    TVM 优化 ARM GPU 上的移动深度学习 随着深度学习的巨大成功,将深度神经网络部署到移动设备的需求正在迅速增长.与桌面平台上所做的类似,在移动设备中使用 GPU 既有利于推理速度,也有利于能源 ...

  10. ADAS可行驶区域道路积水反光区域的识别算法

    ADAS可行驶区域道路积水反光区域的识别算法 Water logging area reflecting recognition algorithm for ADAS 1. 工程概要 1.1  概述: ...