前端代码复杂带来的问题以及模块化的引进

一.前端发展历史

在了解前端代码复杂带来的问题之前,我们先了解前端的发展历史。

1、静态页面阶段
互联网发展的早期,网站的前后端开发是一体的,即前端代码是后端代码的一部分。
1.后端收到浏览器的请求
2.生成静态页面
3.发送到浏览器

那时的前端页面都是静态的,所有前端代码和前端数据都是后端生成的。前端只是纯粹的展示功能,脚本的作用只是增加一些特殊效果,比如那时很流行用脚本控制页面上飞来飞去的广告。

那时的网站开发,采用的是后端 MVC 模式。

Model(模型层):提供/保存数据
Controller(控制层):数据处理,实现业务逻辑
View(视图层):展示数据,提供用户界面
前端只是后端 MVC 的 V。

2、AJAX 阶段
2004年,AJAX 技术诞生,改变了前端开发。Gmail 和 Google 地图这样革命性的产品出现,使得开发者发现,前端的作用不仅仅是展示页面,还可以管理数据并与用户互动。

AJAX 技术指的是脚本独立向服务器请求数据,拿到数据以后,进行处理并更新网页。整个过程中,后端只是负责提供数据,其他事情都由前端处理。前端不再是后端的模板,而是实现了从“获取数据 --》 处理数据 --》展示数据”的完整业务逻辑。

就是从这个阶段开始,前端脚本开始变得复杂,不再仅仅是一些玩具性的功能。

3、前端 MVC 阶段
前端代码有了读写数据、处理数据、生成视图等功能,因此迫切需要辅助工具,方便开发者组织代码。这导致了前端 MVC 框架的诞生。

2010年,第一个前端 MVC 框架 Backbone.js 诞生。它基本上是把 MVC 模式搬到了前端,但是只有 M (读写数据)和 V(展示数据),没有 C(处理数据)。因为,Backbone 认为前端 Controller 与后端不同,不需要、也不应该处理业务逻辑,只需要处理 UI 逻辑,响应用户的一举一动。所以,数据处理都放在后端,前端只用事件响应处理 UI 逻辑(用户操作)。

后来,更多的前端 MVC 框架出现。另一些框架提出 MVVM 模式,用 View Model 代替 Controller。MVVM 模式也将前端应用分成三个部分。

Model:读写数据
View:展示数据
View-Model:数据处理
View Model 是简化的 Controller,所有的数据逻辑都放在这个部分。它的唯一作用就是为 View 提供处理好的数据,不含其他逻辑。也就是说,Model 拿到数据以后,View Model 将数据处理成视图层(View)需要的格式,在视图层展示出来。

这个模型的特点是 View 绑定 View Model。如果 View Model 的数据变了,View(视图层)也跟着变了;反之亦然,如果用户在视图层修改了数据,也立刻反映在 View Model。整个过程完全不需要手工处理。

4、SPA 阶段
前端可以做到读写数据、切换视图、用户交互,这意味着,网页其实是一个应用程序,而不是信息的纯展示。这种单张网页的应用程序称为 SPA(single-page application)。

所谓 SPA,就是指在一张网页(single page)上,通过良好的体验,模拟出多页面应用程序(application)。用户的浏览器只需要将网页载入一次,然后所有操作都可以在这张页面上完成,带有迅速的响应和虚拟的页面切换。

随着 SPA 的兴起,2010年后,前端工程师从开发页面(切模板),逐渐变成了开发“前端应用”(跑在浏览器里面的应用程序)。

目前,最流行的前端框架 Vue、Angular、React 等等,都属于 SPA 开发框架。

二.前端代码复杂带来的问题

从发展历史可以看到,前端慢慢从一个简单的HTML页面发展到CSS.、JS的加入,到后来框架的加入,前端已经不仅仅局限于页面的展示,一些简单甚至复杂的功能也逐渐在前端得到显示,这就不得不使前端的代码越来越多越来越多,这就给前端带来了几乎灾难性的问题。

1.全局变量命名冲突问题
下面我举一个例子来说明全局变量重名所带来的的问题
假设在一个项目开发过程中,有多个人同时开发,这里就假设有
1.项目组长:main.js 用于定义全局规范,会把整个框架搭建,然后再分工
2.小明:aaa.js
3.小红:bbb.js
这三人开发一个项目:

①主界面导入三人的js文件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<!--在项目开发中,一个项目可能需要多人开发
			为了解释全局变量带来的问题,这里模拟三人开发
			1.项目组长:main.js 用于定义全局规范,会把整个框架搭建,然后再分工
			2.小明:aaa.js
			3.小红:bbb.js
		-->
		<script src="main.js" type="text/javascript" charset="utf-8"></script>
		<script src="aaa.js" type="text/javascript" charset="utf-8"></script>
		<script src="bbb.js" type="text/javascript" charset="utf-8"></script>
		<script src="mmm.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>

②小明做的JS

//小明
var  name = '小明'
var age= 22
/*计算两个值的大小*/
function sum(num1, num2) {
	return num1+ num2
}

var flag = true

if (flag) {
	console.log(sum(10, 20))
}

现在运行html,打开控制台,能看到正确的运算结果,如图所示:
在这里插入图片描述

③小红开始做JS

var name = '小红'
//小红也存在与小明同名的变量flag
var flag = false

console.log(name)

现在运行html,打开控制台,仍能看到正确的运算结果,如图所示:
在这里插入图片描述
可以看到控制台输出了小红的名字并且小明的也没有出错。
④小明继续开发,创建了另一个js文件
因为他知道之前创建过flag变量,所以他打算直接拿来用。

//如果flag是正确的,就会执行if
if(flag) {
	console.log('小红把我的改了!!')
}

然后小明打开网页控制台,发现这一个JS没有起到作用,没有显示到应该显示的那句话
在这里插入图片描述
那么问题到底出在哪里呢,明明自己之前写的flag是true啊,怎么会不显示,小明第一时间会查看自己的代码发现自己的代码正确,然后查看小红的代码,发现是小红也有一个跟自己一样的变量。当然这里的示例只有几行左右,但是在真正的项目开发过程中,一个js文件可能存在成千上万行代码,要一个一个查看其工作量可想而知,可能要加班到凌晨三四点还弄不完。这就是全局变量重名问题。

2.js依赖顺序强制性
接上面的例子,小明发现问题之后,便将自己刚做的mmm.js移到小红的bbb.js上方。刷新后发现小明做的mmm.js能够显示了。如图所示:
在这里插入图片描述
从上可以看到,一旦JS引入的顺序改变,页面也有可能发生改变,甚至可能带来灾难性的问题。

解决方案
一.匿名函数
我们可以使用匿名函数来解决重名问题,采用闭包来减少全局变量,这样都是在自己的定义域里面定义自己的变量。下面我仍然用上面的例子说明。
1.修改小明的js,将js闭包

(function() {
	//小明
var  name = '小明'
var age= 22
/*计算两个值的大小*/
function sum(num1, num2) {
	return num1+ num2
}

var flag = true

if (flag) {
	console.log(sum(10, 20))
}

})()

2.修改小红的js,将js闭包

;(function() {
	var name = '小红'
//小红也存在与小明同名的变量flag
var flag = false

console.log(name)

})()

这样小红和小明之间的变量就毫不干扰。
但是这也会带来一些问题,下面当我们刷新网页的时候
在这里插入图片描述
会发现mmm.js里面的内容又消失了,因为当我们使用了匿名函数,匿名函数里面的变量就只能在函数里面使用,相当于变成来局部变量,所以对于mmm.js中的flag用不到之前定义的。没办法,为了使用这个flag,mmm.js又必须再定义一次,这样就使代码复用性降低,代码冗余了。

2.为了解决这一问题,我们必须使用模块化(ES5),使用模块作为出口。这里就是本文章的重点了。

小明还是想用aaa.js里面的flag,就必须设置要导出的对象。将自己的js定位模块A

var moduleA= (function() {
//小明
//导出的对象
var obj = {}

var  name = '小明'
var age= 22
/*计算两个值的大小*/
function sum(num1, num2) {
	return num1+ num2
}

var flag = true

if (flag) {
	console.log(sum(10, 20))
}
//obj绑定flag和sum
obj.flag= flag;
obj.sum = sum;
//将obj发送出去
return obj
})()

此时,mmm.js就可以拿到返回的obj

(function() {
	//想使用flag
	if(moduleA.flag) {
	console.log('小红把我的改了!!')
	}
	
	//拿到sum
	console.log(moduleA.sum(40, 50));
})()

刷新页面可以发现mmm.js可以正常显示
在这里插入图片描述
当然,小红也可以定义自己的模块,她将自己的js定义为模块B

;

var moduleB = (function() {
	var obj= {}
	var name = '小红'
//小红也存在与小明同名的变量flag
var flag = false

console.log(name)

obj.flag= flag;
return obj
})()

以后小红在添加js的时候,就可以使用自己模块里面的东西,从而不会出现全局变量重名的情况了
比如小红创建了nnn.js文件

(function() {
	console.log(moduleB.flag);
})()

在这里面flag只会使用指定模块里面的变量。这就是模块化的雏形。

3.模块化开发
常见的模块化规范

  1. CommonJS
  2. AMD
  3. CMD
  4. ES6中的Modules

示例:CommonJS导出,利用exports进行导出

//CommonJS导入和导出
//小明

var  name = '小明'
var age= 22
/*计算两个值的大小*/
function sum(num1, num2) {
	return num1+ num2
}

var flag = true

if (flag) {
	console.log(sum(10, 20))
}
//导出
module.exports= {
	flag: flag,
	sum: sum
}

CommonJS导入:

var aaa = require('./aaa.js')
var flag = aaa.flag;
var sum = aaa.sum;

sum(20, 30)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值