设计模式,在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。
抽取类相同的属性和方法封装到对象上
let UserFactory = function (role, opt) {
function User(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
switch (role) {
case ‘superAdmin‘:
return new User(opt);
break;
case ‘admin‘:
return new User(opt);
break;
case ‘user‘:
return new User(opt);
break;
default:
throw new Error(‘参数错误, 可选参数:superAdmin、admin、user‘)
}
}
let superAdmin = UserFactory(‘superAdmin‘, {"name": "zhangsan", "viewPage": "superAdmin"});
创建实例
var Factory=function(type, content){
if(this instanceof Factory){
var s=new this[type](content);
return s;
}else{
return new Factory(type,content);
}
};
//工厂原型中设置创建类型数据对象的属性
Factory.prototype={
constructor: Factory,
Java: function(content){
console.log(‘Java值为‘,content);
},
PHP: function(content){
console.log(‘PHP值为‘,content);
},
Python: function(content){
console.log(‘Python值为‘,content);
}
}
Factory(‘Python‘, ‘我是Python‘);
设置函数的原型属性,实现继承
function Animal (name) {
this.name = name || ‘Animal‘;
this.sleep = function(){
console.log(this.name + ‘正在睡觉!‘);
}
}
Animal.prototype.eat = function(food) {
console.log(this.name + ‘正在吃:‘ + food);
};
function Cat(){ }
Cat.prototype = new Animal();
Cat.prototype.name = ‘cat‘
var cat = new Cat();
console.log(cat.name); // cat
console.log(cat.eat(‘fish‘)); // cat正在吃:fish
console.log(cat.sleep()); // cat正在睡觉!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
只允许被实例化一次的类,提供一个命名空间
let singleCase = function(name){
this.name = name;
};
singleCase.prototype.getName = function(){
return this.name;
}
// 获取实例对象
let getInstance = (function() {
var instance = null;
return function(name) {
if(!instance) { // 闭包
instance = new singleCase(name);
}
return instance;
}
})();
console.log(getInstance("one") === getInstance("two")) // true
一种数据结构改成另一种数据结构,将一个接口转换成客户端需要的接口而不需要去修改客户端代码,使得不兼容的代码可以一起工作;主要用于解决两个接口之间不匹配的问题
const zhejiangCityOld = (function() {
return [{
name: ‘hangzhou‘,
id: 11,
},
{
name: ‘jinhua‘,
id: 12
}]
}());
const adaptor = (function(oldCity) {
const obj = {}
for (let city of oldCity) {
obj[city.name] = city.id
}
return obj
})(zhejiangCityOld)
adaptor // {hangzhou: 11, jinhua: 12}
不改变原对象的基础上,动态的给对象添加属性或方法
let decorator=function(input,fn){
let input=document.getElementById(input); //获取事件源
if(typeof input.onclick==‘function‘){ //若事件源已经绑定事件
let oldClickFn=input.onclick; //缓存事件源原有的回调函数
input.onclick=function(){ //为事件源定义新事件
oldClickFn(); //事件源原有回调函数
fn(); //执行事件源新增回调函数
}
}else{
input.onclick=fn; //未绑定绑定
}
}
decorator(‘textInp‘,function(){
console.log(‘文本框执行啦‘);
})
const wear1 = function() {
console.log(‘穿上第一件衣服‘)
}
const wear2 = function() {
console.log(‘穿上第二件衣服‘)
}
const wear3 = function() {
console.log(‘穿上第三件衣服‘)
}
const after = function(fn, afterFn) {
const self = this
return function() {
fn.apply(self, arguments)
afterFn.apply(self, arguments)
}
}
const wear = after(after(wear1, wear2), wear3)
wear()
将抽象部分与它的实现部分分离,使它们都可以独立地变化
class Speed { // 运动模块
constructor(x, y) {
this.x = x
this.y = y
}
run() { console.log(`运动起来 ${this.x} + ${this.y}`) }
}
class Color { // 着色模块
constructor(cl) {
this.color = cl
}
draw() { console.log(`绘制颜色 ${this.color}`) }
}
class Speak {
constructor(wd) {
this.word = wd
}
say() { console.log(`说话 ${this.word}`) }
}
class Ball { // 创建球类,可以着色和运动
constructor(x, y, cl) {
this.speed = new Speed(x, y)
this.color = new Color(cl)
}
init() {
this.speed.run()
this.color.draw()
}
}
class Man { // 人类,可以运动和说话
constructor(x, y, wd) {
this.speed = new Speed(x, y)
this.speak = new Speak(wd)
}
init() {
this.speed.run()
this.speak.say()
}
}
const man = new Man(1, 2, ‘hehe?‘)
man.init()
Object.prototype.addMethod = function(name,fn){
this[name] = fn;
}
function Box(x,y,z){ // 创建类并实例化对象(实现层)
this.x=x;
this.y=y;
this.z=z;
}
var box=new Box(20,10,10);
box.addMethod("init",function(){ // 为对象拓展方法(桥接方法)
console.log("盒子的长度为:"+this.x+" , 宽度为:"+this.y+" , 高度为:"+this.z);
});
box.init();
解决类与对象,对象与对象之间的耦合
let Observer = (function(){
let _message={};
return {
//注册接口,
//1.作用:将订阅者注册的消息推入到消息队列
//2.参数:所以要传两个参数,消息类型和处理动作,
//3.消息不存在重新创建,存在将消息推入到执行方法
regist: function(type,fn){
//如果消息不存在,创建
if(typeof _message[type]===‘undefined‘){
_message[type]=[fn];
}else{
//将消息推入到消息的执行动作
_message[type].push(fn);
}
},
//发布信息接口
//1.作用:观察这发布消息将所有订阅的消息一次执行
//2.参数:消息类型和动作执行传递参数
//3.消息类型参数必须校验
fire: function(type,args){
//如果消息没有注册,则返回
if(!_message[type]) return;
//定义消息信息
var events={
type: type, //消息类型
args: args || {} //消息携带数据
},
i=0,
len=_message[type].length;
//遍历消息
for(; i<len; i++){
//依次执行注册消息
_message[type][i].call(this,events);
}
},
//移除信息接口
//1.作用:将订阅者注销消息从消息队列清除
//2.参数:消息类型和执行的动作
//3.消息参数校验
remove: function(type,fn){
//如果消息动作队列存在
if(_message[type] instanceof Array){
//从最后一个消息动作序遍历
var i=_message[type].length-1;
for(; i>=0; i--){
//如果存在该动作在消息队列中移除
_message[type][i]===fn&&_message[type].splice(i,1);
}
}
}
}
})()
Observer.regist(‘test‘,function(e){
console.log(e.type,e.args.msg);
})
Observer.fire(‘test‘,{msg:‘传递参数1‘});
Observer.fire(‘test‘,{msg:‘传递参数2‘});
Observer.fire(‘test‘,{msg:‘传递参数3‘});
一个对象状态改变会导致行为变化,解决复杂的if判断
const weakLight = function(light) {
this.light = light
}
weakLight.prototype.press = function() {
console.log(‘打开强光‘)
this.light.setState(this.light.strongLight)
}
const strongLight = function(light) {
this.light = light
}
strongLight.prototype.press = function() {
console.log(‘关灯‘)
this.light.setState(this.light.offLight)
}
const offLight = function(light) {
this.light = light
}
offLight.prototype.press = function() {
console.log(‘打开弱光‘)
this.light.setState(this.light.weakLight)
}
const Light = function() {
this.weakLight = new weakLight(this)
this.strongLight = new strongLight(this)
this.offLight = new offLight(this)
this.currentState = this.offLight // 初始状态
}
Light.prototype.init = function() {
const btn = document.createElement(‘button‘)
btn.innerHTML = ‘按钮‘
document.body.append(btn)
const self = this
btn.addEventListener(‘click‘, function() {
self.currentState.press()
})
}
Light.prototype.setState = function(state) { // 改变当前状态
this.currentState = state
}
const light = new Light()
light.init() // 打开弱光 打开强光 关灯
定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户,根据不同参数可以命中不同的策略。
const S = function(salary) {
return salary * 4
}
const A = function(salary) {
return salary * 3
}
const B = function(salary) {
return salary * 2
}
const calculateBonus = function(func, salary) {
return func(salary)
}
calculateBonus(A, 10000)
设置一个中间层,处理对象之间的交互,对象和对象之间借助第三方中介者进行通信
const player = function(name) {
this.name = name
playerMiddle.add(name)
}
player.prototype.win = function() {
playerMiddle.win(this.name)
}
player.prototype.lose = function() {
playerMiddle.lose(this.name)
}
const playerMiddle = (function() { // 将就用下这个 demo, 这个函数当成中介者
const players = [], winArr = [], loseArr = []
return {
add: function(name) {
players.push(name)
},
win: function(name) {
winArr.push(name)
if (winArr.length + loseArr.length === players.length) {
this.show()
}
},
lose: function(name) {
loseArr.push(name)
if (winArr.length + loseArr.length === players.length) {
this.show()
}
},
show: function() {
for (let winner of winArr) {
console.log(winner + ‘挑战成功;‘)
}
for (let loser of loseArr) {
console.log(loser + ‘挑战失败;‘)
}
},
}
}())
const a = new player(‘A 选手‘)
const b = new player(‘B 选手‘)
const c = new player(‘C 选手‘)
a.win() // A 选手挑战成功;
b.win() // B 选手挑战成功;
c.lose() // C 选手挑战失败;
超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。是一个基于TCP实现的应用层协议。
特点:
HTTP(S) 请求地址 → DNS 解析 → 三次握手 → 发送请求 → 四次挥手
OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO组织在1985年研究的网络互联模型。该体系结构标准定义了网络互联的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层和应用层),即OSI开放系统互连参考模型。
HTTP/0.9 极其简单:请求由单行指令构成,以唯一可用方法GET开头,其后跟目标资源的路径(一旦连接到服务器,协议、服务器、端口号这些都不是必须的)。响应也极其简单的:只包含响应文档本身。
跟后来的版本不同,HTTP/0.9 的响应内容并不包含HTTP头,这意味着只有HTML文件可以传送,无法传输其他类型的文件;也没有状态码或错误代码:一旦出现问题,一个特殊的包含问题描述信息的HTML文件将被发回,供人们查看。
只允许客户端发送 GET 这一种请求;且不支持请求头,协议只支持纯文本;无状态性,每个访问独立处理,完成断开;无状态码。
特点:
有身份认证,三次握手; 请求与响应支持头域。
请求头内容:
响应头内容:
expires 是响应头内容,返回一个固定的时间,缺陷是时间到了服务器要重新设置;请求头中如果有 If-Modified-Since,服务器会将时间与 last-modified 对比,相同返回 304;支持 GET、HEAD、POST 方法;有状态码;支持长连接(但默认还是使用短连接)、缓存机制以及身份认证。
特点:
请求头增加 Cache-Control:
Cache-Control 的 max-age 返回是缓存的相对时间,Cache-Control 优先级比 expires 高,缺点:不能第一时间拿到最新修改文件
HTTP/2在HTTP/1.1有几处基本的不同:
采用二进制格式传输;多路复用,将请求数据分成帧乱序发送到 TCP 中,TCP 只能有一个 steam,所以还是会阻塞;报头压缩;服务器推送主动向 B 端发送静态资源,避免往返延迟。
基于 QUIC 协议,基于 UDP。
特点:
https(全称:Hyper Text Transfer Protocol over Secure Socket Layer) 是在 http 协议的基础上加了个 SSL;主要包括:握手(凭证交换和验证)和记录协议(数据进行加密)。
HTTP 与 HTTPS 的区别:
分类:
etag 优先级高于 last-modified;etag 精度高,last-modified 精度是 s,1s 内 etag 修改多少次都会被记录; last-modified 性能好,etag 要得到 hash 值。
浏览器读取缓存流程:会先判断强缓存;再判断协商缓存 etag(last-modified)是否存在;存在利用属性 If-None-match(If-Modified-since)携带值;请求服务器,服务器对比 etag(last-modified),生效返回 304。
F5 刷新会忽略强缓存不会忽略协商缓存,ctrl+f5 都失效
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。HTTP状态码的英文为HTTP Status Code。
HTTP状态码分类:
1xx
:表示临时响应并需要请求者继续执行操作的状态码
2xx
:成功,操作被成功接收并处理
3xx
:重定向,需要进一步的操作以完成请求
4xx
:客户端错误,请求包含语法错误或无法完成请求
5xx
:服务器错误,服务器在处理请求的过程中发生了错误
WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
Ajax 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
主要接口:
Websocket 使用 ws 或 wss 的统一资源标志符,类似于 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。如:ws://example.com/wsapi
、wss://secure.example.com/
。
Websocket 使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket 协议使用 80 端口;运行在 TLS 之上时,默认使用 443 端口。
Socket 是传输控制层协议,WebSocket 是应用层协议。
// url 要连接的URL;这应该是WebSocket服务器将响应的URL
// protocols 一个协议字符串或者一个包含协议字符串的数组;这些字符串用于指定子协议,这样单个服务器可以实现多个WebSocket子协议
var aWebSocket = new WebSocket(url [, protocols]); // 返回一个 WebSocket 对象
属性:
var bufferedAmount = aWebSocket.bufferedAmount;
var extensions = aWebSocket.extensions;
aWebSocket.onclose = function(event) {
console.log("WebSocket is closed now.");
};
aWebSocket.onerror = function(event) {
console.error("WebSocket error observed:", event);
};
aWebSocket.onmessage = function(event) {
console.debug("WebSocket message received:", event);
};
aWebSocket.onopen = function(event) {
console.log("WebSocket is open now.");
};
var protocol = aWebSocket.protocol;
var readyState = aWebSocket.readyState; // 0 - 正在链接中,1 - 已经链接并且可以通讯,2 - 连接正在关闭,3 - 连接已关闭或者没有链接成功
var url = aWebSocket.url;
方法:
function WebSocketTest() {
if ("WebSocket" in window) {
alert("您的浏览器支持 WebSocket!");
// 打开一个 web socket
var ws = new WebSocket("ws://localhost:9998/echo");
ws.onopen = function() {
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("发送数据");
alert("数据发送中...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("数据已接收...");
};
ws.onclose = function() {
// 关闭 websocket
alert("连接已关闭...");
};
} else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
const socket = new WebSocket(‘ws://localhost:8080‘);
socket.addEventListener(‘open‘, function (event) {
socket.send(‘Hello Server!‘);
});
socket.addEventListener(‘message‘, function (event) {
console.log(‘Message from server ‘, event.data);
});
CloseEvent 会在连接关闭时发送给使用 WebSockets 的客户端. 它在 WebSocket 对象的 onclose 事件监听器中使用.
var event = new CloseEvent(typeArg, closeEventInit);
MessageEvent 是接口代表一段被目标对象接收的消息。
var messageEvent = new MessageEvent(type, init);
var myMessage = new MessageEvent(‘worker‘, {
data : ‘hello‘
});
参考文章:
面试中的JavaScript之设计模式、HTTP、WebSocket.md
原文:https://www.cnblogs.com/dongqunren/p/11902241.html