前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
一、AMD和CMD规范(了解)
1.1传统的前端开发多个js文件的关系
yuan.js中定义了一个函数
function mianji(r){
return 3.14 * r * r
}
main.js文件中调用这个函数:
alert(mianji(10))
在页面上按顺序引入这两个js文件:
<html>
<head>
<title>Document</title>
</head>
<body> </body>
<script type="text/javascript" src="yuan.js"></script>
<script type="text/javascript" src="main.js"></script>
</html>
能运算,yuan.js中定义的函数,是window对象的属性,所以main.js中能放同一个window全局函数,但每个js文件之间没有“强的引用”关系,它们都是向window暴露自己的函数,其他人通过window周转。
1.2 CMD规范
function mianji(r){
return 3.14 * r * r
}
//暴露
exports.mianji = mianji;
var yuan = require("./yuan.js");
console.log(yuan.mianji(10))
exports、require(),在浏览器会报错,因为这两个对象是Nodejs才有的,在客户端浏览器不认识。
实际上在(比Nodejs还早),就有美国的程序员发明了Common.js,中国程序员阿里巴巴玉伯发明了sea.js,都解决了exports和require的识别问题。因为这个规范是Commonjs提出的,所以叫CMD规范,Common Module Definition,通用模块定义。Nodejs也遵循CMD规范,但Nodejs并不是CMD规范的发明人。Nodejs是CommonJS规范的实现,后面学习的webpack也是以CommonJS的形式来书写。
所以,Node.js的模块系统,就是参照CommonJS规范实现的。
1.3 AMD规范-require.js(过时)
概述:比如前期学习js基础时,经常引入其他的js文件,但是有一个文件之间的先后顺序问题:
比如haha.js里面有xixi.js需要的某一个函数,那么引入haha.js文件必须在引入xixi.js文件之前;
因此有人,研究出一些规范,这些规范是规范引用js文件的先后顺序。
require.js库是AMD规范的代表。
AMD,Asynchronous Module Definition,即异步模块定义。它是适用于浏览器端的一种模块加载方式。从名字可知,AMD采用的是异步加载方式(js中最典型的异步例子就是ajax)。浏览器需要使用的js文件(第一次加载,忽略缓存)都存放在服务器端,从服务器端加载文件到浏览器是受网速等各种环境因素的影响的,如果采用同步加载方式,一旦js文件加载受阻,后续在排队等待执行的js语句将执行出错,会导致页面的‘假死’,用户无法使用一些交互。所以在浏览器端是无法使用CommonJS的模式的。而CommonJS是适用于服务器端的,著名的Node执行环境就是采用的CommonJS模式。
AMD和CMD规范和你开发什么业务无关,和用什么设计模式无关。
AMD、CMD是JS文件之间的互相引用关系,设计模式是js类和类之间的关系。
二、ES6中的模块(CMD规范)
重点:在ES6中新增了js文件的暴露和引入的新写法:(import和export)
2.1 import和export基本使用
之前学习过Nodejs,用了require、exports来引入和暴露。
W3C那些老头想:Ryan Dahi那个小孩挺牛逼,在Nodejs发明了require()和exports挺好用,我们也制定一个标准吧!于是研究出了这样的语法:
require() → import
exports.*** → export
module.exports → default
l 使用export const暴露函数,import {} from "./路径"; 接收函数。
在yuan.js文件暴露
export const mianji = (r) => 3.14 * r * r;
export const zhouchang = (r) => 2 * 3.14 * r;
在main.js文件接收:
import {mianji,zhouchang} from "./yuan.js"; //引入
console.log(mianji(10));
console.log(zhouchang(10));
注意两个问题:
l 暴露时是什么名字,接收时一定是什么名字,比如暴露的是mianji,接收就叫mianji。
l 路径必须“./”开头
W3C新发明的CMD规范(export和import)关键字,到今天为止,你会发现如今的浏览器和Node平台都不支持。
Google黑板报说2018年将原生支持(export和import)
那现在不支持怎么办?
webpack应运而生,webpack是一个很智能的文件打包器,你只需告诉它主入口文件是谁,它就能顺着import链进行打包,最后能合并成为一个新的js文件,将不再有import和export的语法。
webpack打包命令
webpack main.js all.js
webpack进行了3个事情:
1)从main.js出发,顺着import链寻找每一个被引用的js文件
2)将每一个js文件智能合并打包。比如一个export暴露的函数没有被使用,将不会被打包;
3)去import、export化,也就是说all.js是IE8都兼容的。
webpack是一个构建工具,在html中只需要引入all.js一个文件即可
2.2命名空间
比如增加一个fang.js也向外暴露两个函数,也叫mianji和zhouchang
export const mianji = (a)=> 3.14 * a * a;
export const zhouchang = (a)=> 3.14 * a * 4;
此时主入口文件:
import {mianji,zhouchang} from "./yuan.js";
import {mianji,zhouchang} from "./fang.js";
console.log(mianji(15))
console.log(zhouchang(15))
会报错,因为函数名重复了:
解决方法就是命名空间:用import * as fang from "./路径"; 来接收函数
import * as yuan from "./yuan.js";
import * as fang from "./fang.js"; console.log(yuan.mianji(10))
console.log(fang.mianji(10))
此时函数必须通过yuan打点,或fang打点调用,因为接收到的是一个JSON。
也就是说import * as fang from "./文件";的语法,可以有效避免函数的名字冲突。
注意:import * as的这个名字,必须和文件名相同。
2.3默认暴露
如果js文件中是一个类(构造函数),此时不希望有命名空间,用默认暴露:
export default
相当于nodejs中的module.exports
比如写一个文件叫People.js这个文件向外暴露一个类:
export default class People {
constructor(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
change(){
alert(`啦啦啦!我是卖报的${this.name},今年${this.age}`)
}
}
在主入口文件,就不用{}引用这个类:
import People from "./People.js"; //类叫什么名字,import后就叫什么名字 var xiaoming = new People("小明",12,"男");
xiaoming.change();
一个文件可以有多个普通暴露,但是只能有一个默认暴露
// 默认暴露
export default class People {
constructor(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
change(){
alert(`啦啦啦!我是卖报的${this.name},今年${this.age}`)
}
} //以下是普通暴露
export const a = 100;
export const b = 200;
export const f1 = function(){
alert("我是普通的暴露函数f1")
};
export const f2 = function(){
alert("我是普通的暴露函数f2")
};
注意:引入时,接收默认的暴露,不能加{},接收普通暴露的加{}
// import People from "./People.js"; //类叫什么名字,import后就叫什么名字
import People, {a,b,f1,f2} from "./People.js"; console.log(a)
console.log(b)
f1();
f2(); var xiaoming = new People("小明",12,"男");
xiaoming.change();
暴露模块:
普通暴露 |
export const |
默认暴露 |
export default |
引用模块:
普通引用 |
import {mianji,zhouchang} "./yuan.js" import * as yuan "./yuan.js" |
默认引用(类的引用) |
import People from "./People.js" |
默认暴露和普通暴露一起引用 |
import People,{a,b,f1,f2} from "./People.js"; |
三、webpack(模块打包器)
3.1 webpack的简介和安装
官网:https://doc.webpack-china.org/
webpack 是一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)
安装webpack工作流工具:
npm install -g webpack@3.10.0
webpack有4代版本,优点是:打包合并文件速度快,快了90%。
3.2 webpack基本使用
在项目文件夹中运行CMD命令,webpack打包命令:
webpack main.js all.js
main.js是主入口文件
all.js 是出口文件(被打包的)
没有yuan.js的事情,因为在main.js中import {mianji} from "./yuan.js"; 所以webpack就链着import寻找yuan.js进行打包合并。
3.3 webpack.config.js文件
可以在项目中的根目录写webpack.config.js文件,来指导webpack工作。
就如同.babelrc文件一样,指导babel工作。
webpack.config.js文件的配置:
https://webpack.docschina.org/configuration/
先配置一个文件,以后用就行了:
const path = require('path'); module.exports = {
//程序的入口文件
entry:"./www/app/main.js", //程序的出口(打包的文件)
output:{
//打包文件输出的路径
path: path.resolve(__dirname, "./www/dist"),
//打包文件的名称
filename: 'all.js'
},
//自动监听文件的变化
watch:true
}
webpack.config.js文件配置好后,就可以使用webpack命令打包了。
3.4 babel-loader
webpack只是帮我们智能合并打包文件,但是没有翻译ES6、7、8语法为ES5语法。
所以现在的任务是,在webpack打包的过程中,对每一个js文件用babel进行翻译。
webpack提供了babel-loader功能,可以让webpack在打包文件时,顺便的翻译ES678语法。
安装依赖:
npm install --save-dev babel-core@6
npm install --save-dev babel-loader@7
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-es2016
babel-core 是babel的核心
babel-loader 是babel和webpack一起使用的桥梁
babel-preset-es2015 是翻译的字典
注意:babel-loader默认安装的是8代版本,但babel-core默认安装的是6,所以版本不兼容,会报错。解决方法是babel-loader降级安装7代,或者babel-core升级安装为7代。
安装完3个依赖,并配置好webpack.config.js文件后,webpack不但能打包,还能翻译了。
webpack.config.js文件配置
const path = require('path'); module.exports = {
//程序的入口文件
entry:"./www/app/main.js", //程序的出口(打包的文件)
output:{
//打包文件输出的路径
path: path.resolve(__dirname, "./www/dist"),
//打包文件的名称
filename: 'all.js'
},
//监听文件的变化(自动打包)
watch:true,
//配置webpack模块插件
module:{
//关于模块的配置规则
rules:[{
// 模块规则(配置 loader、解析器等选项)
test: /\.js$/, //解析的时候匹配js文件
loader:"babel-loader",
//翻译什么文件夹中的文件
include: [ path.resolve(__dirname, "www/app")],
//不翻译什么文件夹中的文件
exclude: [ path.resolve(__dirname, "node_modules")],
//配置翻译语法
options:{
presets:["es2015","es2016"]
}
}]
}
}
之前写的.babelrc文件,现在webpack在webpack.config.js文件中提供了,所以可以删除了。
四、Promise对象(重点)
Promise对象是关于解决异步的书写美观问题。
4.1复习同步和异步
当CPU面对一个长时间、设备处理的诸如文件读取、磁盘I/O、数据库查询、数据库的写入等等操作的时候,此时有两种模式:
① 同步模式:死等这个设备处理完成,此时CPU自己被阻塞
② 异步模式:不等这个设备处理完成,而是先执行后面的语句,等这个设备处理完成的时候,执行回调函数。
比如下面的代码,让CPU先执行一段计算,然后命令硬盘异步读取文件,读取的过程中不阻塞CPU,CPU提前执行后面的计算语句,等硬盘读取完毕之后,执行回调函数。
var fs = require("fs"); for(var i = 0; i < 100; i++){
i++;
}
console.log(i);
//异步读取文件
fs.readFile("./txt/1.txt", (err,data) =>{
console.log(data.toString());
}); for(var i = 0; i < 100; i++){
i++;
}
console.log(i);
4.2异步回调语法不美观
先读1.txt,然后读2.txt,最后读3.txt
fs.readFile("./data/1.txt", (err,data) =>{
console.log(data.toString());
fs.readFile("./data/2.txt", (err,data) =>{
console.log(data.toString());
fs.readFile("./data/3.txt", (err,data) =>{
console.log(data.toString());
});
});
});
写Ajax请,顺序读取3个api地址,分别是1.json、2.json、3.json
$.get("data/1.json", function(data1){
$.get("data/2.json", function(data2){
$.get("data/3.json", function(data3){
console.log(data1,data2,data3)
})
})
})
通过以上两个案例,我们遇见了回调黑洞问题(一层嵌套一层)
回调就是当有多个异步的事情,要排队进行的时候,此时必须回调嵌套回调。
之所以回调函数,因为fs.readFile()和ajax是异步的,需要有回调函数告诉主程序它读取完毕了。
那么有没有方法,让异步语句形式变的更好看?从嵌套写法,变为火车写法,而不是一层嵌套一层的缩进?
ES6推出了Promise对象,就是优雅的解决回调函数的黑洞问题。
http://es6.ruanyifeng.com/#docs/promise
4.3 ES6的Promise对象
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
下面代码创造了一个Promise实例。
const promise = new Promise(function(resolve, reject){
if(/* 异步操作成功 */){
resolve(value);
}else{
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve 表示成功执行的回调函数
reject 表示失败执行的回调函数
封装一个函数,叫读文件duwenjian(),这个函数接收url作为路径参数:
var fs = require("fs"); function duwenjian(url){
return new Promise(function(resolve,reject){
fs.readFile(url, (err,data)=>{
if(err){
reject(); //失败执行
return;
}
resolve(data.toString()); //成功执行
})
})
} duwenjian("./data/1.txt").then((data)=>{
console.log(data);
return duwenjian("./data/2.txt");
}).then((data)=>{
console.log(data);
return duwenjian("./data/3.txt");
}).then((data)=>{
console.log(data);
})
回调黑洞问题解决了,将原来的“嵌套模式”变为“队列模式”
可以认为这是一根语法糖,因为没有改变原理,只改变了写法。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
红色表示成功执行的回调函数,蓝色表示失败执行的回调函数:
duwenjian("./data/1.txt").then((data)=>{
console.log(data);
},()=>{
console.log("读取失败")
})
then表示然后。
这个函数返回一个Promise对象,这个对象是构造函数,ES6新增的。
Promise一定是某个函数的唯一返回值,Promise自己调用没有任何意义,必须当做一个函数的返回值才有意义!本例中,Promise就是duwenjian函数的返回值!!
这个函数中,一定是一个异步语句,我们的案例是fs.readFile()
异步语句的成功,要将数据通过resolve(数据)传出去,这个数据将成为then里面的data。
异步语句的失败,要将错误信息通过reject(err)传出去,这个数据将成then里面的第二个data。
Promise的实例拥有then()方法,也就是说,then方法是定义在原型对象。
在Ajax中使用promise对象,按顺序读取三个文件:
为了解决黑洞问题,此时用promise来解决:
function duwenjian(url){
return new Promise(function(resolve,reject){
$.ajax({
url : url,
success : function(data){
resolve(data);
},
error : function(){
reject();
}
})
})
} $("button").click(function(event) {
duwenjian("data/1.json").then(function(data){
console.log(data);
return duwenjian("data/2.json");
}).then((data)=>{
console.log(data);
return duwenjian("data/3.json");
}).then((data)=>{
console.log(data);
})
});
promise表示承诺、契约:当异步完毕之后,一定会执行resolve,从而then被执行,里面能够得到值。
4.4 ES7的async和await
ES6中的Promise对象,解决了回调黑洞,但实际上又产生了火车黑洞,then()过多不好看。
所以ES7中提出了async/await可以让我们用同步的方式写异步,不写then了。
async表示异步,await表示异步等待。
用写同步的方法,写异步函数:
注意:
1)必须写那个return Promise对象的函数;
2)await不能裸用,必须写在async字样的函数里;
3)所有异步语句前都要加await,但是后面的函数必须return Promise实例的函数。
function duwenjian(url){
return new Promise(function(resolve,reject){
$.ajax({
url : url,
success : function(data){
resolve(data);
},
error : function(){
reject();
}
})
})
} async function main(){
var data1 = await duwenjian("data/1.json").then(data=>data);
var data2 = await duwenjian("data/2.json").then(data=>data);
var data3 = await duwenjian("data/3.json").then(data=>data);
console.log(data1)
console.log(data2)
console.log(data3)
};
main();
Nodejs读文件:
var fs = require("fs"); function duwenjian(url){
return new Promise(function(resolve,reject){
fs.readFile(url, (err,data)=>{
if(err){
reject(); //失败执行
return;
}
resolve(data.toString()); //成功执行
})
})
} async function main(){
var data1 = await duwenjian("data/1.txt").then(data=>data);
var data2 = await duwenjian("data/2.txt").then(data=>data);
var data3 = await duwenjian("data/3.txt").then(data=>data);
console.log(data1)
console.log(data2)
console.log(data3)
}; main();
读文件
任何一个函数都可以在function之前加async这个关键字,表示这个函数中出现了await。
await后面只能跟着一个返回promise对象的实例的函数的调用,then里面的函数的返回值将自动被等号左边接收
使用async/await的哲学:用写同步语句的感觉,去写异步语句。
async写在function这个之前,await写在异步语句之前
await表示等待后面的操作执行完毕,再执行下一行代码。
4.5 ES8的fetch()
ES8中继续提出了fetch方法,这个方法发出ajax请求,返回Promise的实例
fetch()函数是ES8中提出的新的特性,它:
1)能够发出Ajax请求,并且请求机理不是xhr,而是新的机理;
2)天生可以跨域,但是需要设置头,服务器可以写脚本识别这个头部判断是否应该拒绝它;
3) fetch()返回Promise对象,所以可以用then来跟着,then里面的第一个函数就是resolve,这个resolve的返回值将自动被await等号左边的变量的接收。
4)不要忘记写async和await。
async function main(){
var data1 = await fetch("data/1.json").then(data=>data.json());
var data2 = await fetch("data/2.json").then(data=>data.json());
var data3 = await fetch("data/3.json").then(data=>data.json());
console.log(data1)
console.log(data2)
console.log(data3)
};
main();
可以不用jQuery了
babel没有任何插件可以翻译fetch为传统ajax。
fetch只能用在浏览器环境,不能用在Nodejs环境。
经典面试题:
Promise是什么:
传统的ajax或者fs写异步的时候,会遇见回调黑洞,回调套用回调,不美观。所以ES6中提出了Promise对象,此时可以封装一个函数,返回Promise的实例,new Promise的时候要传入一个函数,这个函数里面写具体的异步,当异步成功调用resolve(),异步失败调用reject()。此时在外部,我们就可以用.then().then()火车的形式,来实现异步、异步的顺序处理。
async/await是什么:
Promise虽然解决了回调黑洞,但是变成了火车的黑洞。我们可以给函数加上async的前缀,里面的异步语句加上await前缀,这样就可以用类似于同步的写法写异步。等号左侧就能有接收值,语句自然一条一条的执行了。
fetch是什么:
fetch就是ajax,但是返回的是promise的实例,可以直接then,而不需要再次封装一个什么函数了。
五、Generator函数
产生器。
我们没有任何理由封装它,都是别人的框架提供,比如react-saga、dva等。
解释:
l如同async写在函数前面一样,*要写在function函数后面
l如同await写在语句前面一样,yield要写在语句前面,但后面不一定是异步语句,表示“产出”
l函数可以像被打了断点,逐步执行,到了yield就停止执行。
l函数不能直接调用执行,直接调用返回一个对象,比如下面的hw,然后hw必须用next()调用函数。
function* helloWorldGenerator() {
console.log("哈哈");
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator(); console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数的更多相关文章
- JavaScript的模块化之AMD&CMD规范
前端开发常常会遇到的问题: 1.恼人的命名冲突: 2.繁琐的文件依赖: 模块化开发的优势: 1.解决命名冲突和依赖管理: 2.模块的版本管理: 3.提高代码的可维护性: 4.前端性能优化: JavaS ...
- 前端笔记之ES678&Webpack&Babel(中)对象|字符串|数组的扩展&函数新特性&类
一.对象的扩展 1.1对象属性名表达式 ES6可以在JSON中使用[]包裹一个key的名字.此时这个key将用表达式作为属性名(被当做变量求值),这个key值必须是字符串. var a = 'name ...
- 前端笔记之Vue(一)初识SPA和Vue&webpack配置和vue安装&指令
一.单页面应用(SPA) 1.1 C/S到B/S页面架构的转变 C/S:客户端/服务器(Client/Server)架构的软件. C/S 软件的特点: ① 从window桌面双击打开 ② 更新的时候会 ...
- Javascript模块化编程之CommonJS,AMD,CMD,UMD模块加载规范详解
JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发? 模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问 题进行系 ...
- JS开发之CommonJs和AMD/CMD规范
CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范. 在兼容CommonJS的系统中,你可以使用JavaScript开发 ...
- ArcGIS API for JavaScript 4.2学习笔记[7] 鹰眼(缩略图的实现及异步处理、Promise、回调函数、监听的笔记)
文前说明:关于style就是页面的css暂时不做评论,因为官方给的例子的样式实在太简单了,照抄阅读即可. 这篇文章有着大量AJS 4.x版本添加的内容,如监听watch.Promise对象.回调函数. ...
- 前端笔记之ES678&Webpack&Babel(上)初识ES678&Babel&let和const&解构&语法
一.ES版本简介和调试运行方法 1.1 ECMAScript简介 MDN手册:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript JavaS ...
- 前端笔记之服务器&Ajax(下)数据请求&解决跨域&三级联动&session&堆栈
一.请求后端的JSON数据 JSON是前后端通信的交互格式,JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式. JSON是互联网各个后台与 ...
- 前端笔记之HTML5&CSS3(下)2D/3D转换&animate动画
一.2D转换(transform) CSS3中的transform转换和PS中的变换是一样的,分别有:缩放.位移.斜切.旋转 1.1 transform:scale()缩放 transform:sca ...
随机推荐
- longestCommonPrefix
Description: Write a function to find the longest common prefix string amongst an array of strings. ...
- hadoop环境运行程序出现 Retrying connect to server 问题
程序运行时出现如下问题: 从网上查资料,有说重启format的..有说/etc/hosts出问题的... 反正都试了一遍..还是有这个问题 后来看日志,发现问题是访问服务器9001端口访问不到..开始 ...
- 基于DP的LCS(最长公共子序列)问题
最长公共子序列,即给出两个序列,给出最长的公共序列,例如: 序列1 understand 序列2 underground 最长公共序列undernd,长度为7 一般这类问题很适合使用动态规划,其动态规 ...
- linux下svn(subversion)服务端添加工程及配置权限
linux下svn(subversion)服务端添加工程及配置权限 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/9010507.html 此篇我只是将所做过的 ...
- Python_网络攻击之端口
#绝大多数成功的网络攻击都是以端口扫描开始的,在网络安全和黑客领域,端口扫描是经常用到的技术,可以探测指定主机上是否 #开放了指定端口,进一步判断主机是否运行了某些重要的网络服务,最终判断是否存在潜在 ...
- Spring Boot实战笔记(二)-- Spring常用配置(Scope、Spring EL和资源调用)
一.Bean的Scope Scope描述的是Spring容器如何新建Bean实例的.Spring的Scope有以下几种,通过@Scope注解来实现. (1)Singleton:一个Spring容器中只 ...
- [ SSH框架 ] Spring框架学习之二(Bean的管理和AOP思想)
一.Spring的Bean管理(注解方式) 1.1 什么是注解 要使用注解方式实现Spring的Bean管理,首先要明白什么是注解.通俗地讲,注解就是代码里的特殊标记,使用注解可以完成相应功能. 注解 ...
- SSM-Spring-08:Spring的静态代理初窥案例
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 静态代理 java的设计模式的代理模式,就是静态代理 写在前面的话,静态代理的优点和缺点 优点:可以在不改变一 ...
- Java 学习路线之四个阶段
写这篇总结,主要是记录下自己的学习经历,算是自己对知识的一个回顾.也给想要学习 Java 的提供一些参考,对于一些想要学习Java,又不知道从哪里下手,以及现在有哪些主流的 Java 技术.想必大家学 ...
- 玩转Spring MVC(二)----MVC框架
早期程序员在编写代码时是没有一个规范的,系统的业务逻辑和数据库的访问时混合在一起的,不仅增加了大量的重复工作,而且增加了后期维护的难度. 后来,人们逐渐发现某些通用的功能是可以单独的封装起来的,这样就 ...