前言
我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣带你进入前端巅峰交流群 今天继续对前端知识的小结
命令模式宏命令
<!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>命令模式宏命令</title>
</head>
<body>
<script>
var command1 = {
execute: function(){
console.log(1);
}
};
var command2 = {
execute: function(){
console.log(2);
}
};
var command3 = {
execute: function(){
console.log(3);
}
};
// 定义宏命令,command.add方法把子命令添加进宏命令对象,
// 当调用宏命令对象的execute方法时,会迭代这一组命令对象,
// 并且依次执行他们的execute方法。
var command = function(){
return {
commandsList: [],
add: function(command){
this.commandsList.push(command);
},
execute: function(){
for(var i = 0,commands = this.commandsList.length; i < commands; i+=1) {
this.commandsList[i].execute();
}
}
}
};
// 初始化宏命令
var c = command();
c.add(command1);
c.add(command2);
c.add(command3);
c.execute(); // 1,2,3
</script>
</body>
</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>命令模式</title>
</head>
<body>
<button id="button1">刷新菜单目录</button>
<button id="button2">增加子菜单</button>
<button id="button3">删除子菜单</button>
<script>
var b1 = document.getElementById("button1"),
b2 = document.getElementById("button2"),
b3 = document.getElementById("button3");
// 定义setCommand 函数,该函数负责往按钮上面安装命令。点击按钮后会执行command对象的execute()方法。
var setCommand = function (button, command) {
button.onclick = function () {
command.execute();
}
};
// 下面我们自己来定义各个对象来完成自己的业务操作
var MenuBar = {
refersh: function () {
alert("刷新菜单目录");
}
};
var SubMenu = {
add: function () {
alert("增加子菜单");
},
del: function () {
alert("删除子菜单");
}
};
// 下面是编写命令类
var RefreshMenuBarCommand = function (receiver) {
this.receiver = receiver;
};
RefreshMenuBarCommand.prototype.execute = function () {
this.receiver.refersh();
}
// 增加命令操作
var AddSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
AddSubMenuCommand.prototype.execute = function () {
this.receiver.add();
}
// 删除命令操作
var DelSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
DelSubMenuCommand.prototype.execute = function () {
this.receiver.del();
}
// 最后把命令接收者传入到command对象中,并且把command对象安装到button上面
var refershBtn = new RefreshMenuBarCommand(MenuBar);
var addBtn = new AddSubMenuCommand(SubMenu);
var delBtn = new DelSubMenuCommand(SubMenu);
setCommand(b1, refershBtn);
setCommand(b2, addBtn);
setCommand(b3, delBtn);
</script>
</body>
</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>四次挥手</title>
</head>
<body>
<!-- 因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,
SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,
所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。 -->
</body>
</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>圣杯布局</title>
</head>
<style>
#container {
padding-left: 200px;
padding-right: 150px;
overflow: auto;
}
#container p {
float: left;
}
.center {
width: 100%;
background-color: lightcoral;
}
.left {
width: 200px;
position: relative;
left: -200px;
margin-left: -100%;
background-color: lightcyan;
}
.right {
width: 150px;
margin-right: -150px;
background-color: lightgreen;
}
.clearfix:after {
content: "";
display: table;
clear: both;
}
</style>
<body>
<!-- 三栏布局,中间一栏最先加载和渲染(内容最重要,这就是为什么还需要了解这种布局的原因)。
两侧内容固定,中间内容随着宽度自适应。 -->
<div id="container" class="clearfix">
<p class="center">我是中间</p>
<p class="left">我是左边</p>
<p class="right">我是右边</p>
</div>
</body>
</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>原型和原型链</title>
</head>
<body>
<script>
//在构造函数上直接定义方法(不共享)
// function Animai(){
// this.eat=function(){
// console.log("我爱吃饭")
// }
// }
// let dog=new Animai()
// let cat=new Animai()
// dog.eat();//我爱吃饭
// cat.eat();//我爱吃饭
// console.log(dog.eat===cat.eat)//false
//在原型上直接定义方法(共享)
function Animai() {
this.name = name
}
Animai.prototype.eat = function () {
console.log('我爱吃饭', this.name)
}
let dog = new Animai()
let cat = new Animai()
dog.eat() //我爱吃饭
cat.eat() //我爱吃饭
console.log(dog.eat===cat.eat)//true
</script>
</body>
</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>
<!-- 有两种垃圾回收策略:
标记清除:标记阶段即为所有活动对象做上标记,清除阶段则把没有标记(也就是非活动对象)销毁。
引用计数:它把对象是否不再需要简化定义为对象有没有其他对象引用到它。如果没有引用指向该对象(引用计数为
0),对象将被垃圾回收机制回收。 标记清除的缺点:
内存碎片化,空闲内存块是不连续的,容易出现很多空闲内存块,还可能会出现分配所需内存过大的对象时找不到合适的块。
分配速度慢,因为即便是使用 First-fit 策略,其操作仍是一个 O(n)
的操作,最坏情况是每次都要遍历到最后,同时因为碎片化,大对象的分配效率会更慢。
解决以上的缺点可以使用 **标记整理(Mark-Compact)算法
**,标记结束后,标记整理算法会将活着的对象(即不需要清理的对象)向内存的一端移动,最后清理掉边界的内存
引用计数的缺点:
需要一个计数器,所占内存空间大,因为我们也不知道被引用数量的上限。
解决不了循环引用导致的无法回收问题。 V8
的垃圾回收机制也是基于标记清除算法,不过对其做了一些优化。
针对新生区采用并行回收。 针对老生区采用增量标记与惰性回收。 -->
</body>
</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></title>
</head>
<body>
<script>
//第一步 定义自行车的构造函数 两个属性 一个name和一个方法method
var BicycleShop = function (name) {
this.name = name
this.method = function () {
return this.name
}
}
BicycleShop.prototype = {
constructor: BicycleShop,
/*
* 买自行车这个方法
* @param {model} 自行车型号
*/
sellBicycle: function (model) {
var bicycle = this.createBicycle(model)
// 执行A业务逻辑
bicycle.A()
// 执行B业务逻辑
bicycle.B()
return bicycle
},
createBicycle: function (model) {
throw new Error(
'父类是抽象类不能直接调用,需要子类重写该方法'
)
},
}
// 实现原型继承 Sub表示子类,Sup表示超类
function extend(Sub, Sup) {
// 首先定义一个空函数
var F = function () {}
// 设置空函数的原型为超类的原型
F.prototype = Sup.prototype
// 实例化空函数,并把超类原型引用传递给子类
Sub.prototype = new F()
// 重置子类原型的构造器为子类自身
Sub.prototype.constructor = Sub
// 在子类中保存超类的原型,避免子类与超类耦合
Sub.sup = Sup.prototype
if (
Sup.prototype.constructor === Object.prototype.constructor
) {
// 检测超类原型的构造器是否为原型自身
Sup.prototype.constructor = Sup
}
}
var BicycleChild = function (name) {
this.name = name
// 继承构造函数父类中的属性和方法
BicycleShop.call(this, name)
}
// 子类继承父类原型方法
extend(BicycleChild, BicycleShop)
// BicycleChild 子类重写父类的方法
BicycleChild.prototype.createBicycle = function () {
var A = function () {
console.log('执行A业务操作')
}
var B = function () {
console.log('执行B业务操作')
}
return {
A: A,
B: B,
}
}
var childClass = new BicycleChild('歌谣')
console.log(childClass,"childClass")
console.log(childClass.createBicycle())//a方法和b方法
console.log(childClass.sellBicycle())//执行a b业务操作
</script>
</body>
</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>如何写一个简单的回调函数</title>
</head>
<body>
<script>
//函数的参数为回调函数
function fangfang(callback) {
var data = {
"name": "fangyalan",
"age": 18
};
callback(data);
}
//调用
fangfang(function (data) {
//这里操作回调返回的数据
console.log(data)
})
</script>
</body>
</html>
总结
我是歌谣 最好的种树是十年前 其次是现在 加油 歌谣