Js设计模式与开发实践

  • 面向对象
  • 5大设计原则
  • 23种设计模式(实际只有21种)

设计模式主要分为下面三大类

  1. 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  2. 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  3. 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

在JS中比较重要的设计模式有9种,分别是:工厂模式、单例模式、适配器模式、装饰器模式、代理模式、外观模式、观察者模式、迭代器模式、状态模式。特别地,因为受限于JS的使用场景和特定语法,所以将工厂方法模式、抽象工厂模式、建造者模式都归于工厂模式。因此,这篇文章只介绍21种设计模式。

面向对象

继承,封装和多态

  1. js实现继承。(react中有应用)
    作用:继承可以将公共方法抽离出来,提高复用率,减少冗余
 class Person{constructor(name,age) {this.name = name;this.age = age;}getPerson(){return `${this.name}今年${this.age}岁了!`;}}class Student extends Person {constructor(name,age,lesson){super(name,age); //继承this.lesson = lesson}getLesson(){return `${this.name}最喜欢${this.lesson}`}} let p = new Student('陈拉拉',21,'英语');alert(p.getPerson());alert(p.getLesson());

2.js实现封装。public,private,protected。只能在ts(typescriptlang.org/play)中实现。
作用:减少耦合,不该外露数据和方法不会外露;有利于数据和接口的权限管理。
虽然es6虽然不支持,但是一般认为_开头的属性为私有属性。

  class Person{public name;protected age;constructor(name,age) {this.name = name;this.age = age;}getPerson(){return `${this.name}今年${this.age}岁了!`;}}class Student extends Person {private lesson;constructor(name,age,lesson){super(name,age); //继承this.lesson = lesson}getLesson(){return `${this.name}最喜欢${this.lesson}`}} let p = new Student('陈拉拉',21,'英语');alert(p.getPerson());alert(p.getLesson());alert(p.name);alert(p.age); //有问题alert(p.lesson); //有问题

3.多态:同一个接口有多种不同实现方式,js中应用极少,面向接口的编程。
作用:保证子类的开放性和灵活性

class Person{constructor(name,lesson) {this.name = name;this.lesson = lesson;}getPerson(){}}class Student extends Person{constructor(name,lesson) {super(name,lesson);}getPerson(){return `${this.name}最喜欢${this.lesson}`}}class Teacher extends Person{constructor(name,lesson) {super(name,lesson);}getPerson(){return `${this.name}最不喜欢${this.lesson}`}}const student = new Student('李娜','数学');const teacher = new Teacher('李老师','英语');alert(student.getPerson());alert(teacher.getPerson());

jquery就是应用面向对象三要素的一个很好的例子。其中,$()代表着new一个class。

  class JQuery {constructor(selector){let slice = Array.prototype.slice;//让document.querySelectorAll(selector)拥有数组的slice方法,//当slice方法被调用,其作用目标为document.querySelectorAll(selector),//由于没有传入其他参数,slice()默认返回所有下标的元素并返回新数组let dom = slice.call(document.querySelectorAll(selector));debugger;for(let i=0;i<dom.length;i++){this[i] = dom[i]}this.len = dom.length;this.selector = selector || ''}append(node){// ...}addClass(name){// ...}html(data){// ...}}// 工厂模式window.$ = function(selector){return new JQuery(selector)}let $p = $('p');console.log($p);console.log($p.addClass);

UML类图
UML,统一建模语言「Unified Modeling Language」,是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。在www.processon.com或者visio可实现绘制。一般都建议在写代码之前先绘制UML类图。类的书写格式如下:

//   ------------------------------------
//  |                 类名               |
//   ------------------------------------
//  |         + public属性名A:类型       |
//  |         # protected属性名B:类型    |
//  |         - private属性名C:类型      |
//   ------------------------------------
//  | + public方法名A(参数):返回值类型    |
//  | # protected方法名B(参数):返回值类型 |
//  | - private方法名C(参数):返回值类型   |
//   ------------------------------------

UML类图中有六种关系,分别是依赖关系,关联关系,聚合关系,组合关系,实现关系,泛化关系。示例图如下。详细内容可以参考终于明白六大类UML类图关系了。

5大设计原则

SOLID是面向对象软件开发中最流行的设计原则之一。它是以下五个设计原则的助记符缩写:

  • 单一责任原则 (JS中常用)
  • 开放/封闭原则 (JS中常用)
  • 李氏替代原则
  • 接口隔离原理
  • 依赖倒置

23种设计模式(实际只有21种)

第一种到第九种为js中常用的设计模式。
1. 工厂模式(符合开放封闭原则)
我们在创建对象时不会对客户端直接暴露创建逻辑,而是通过使用一个共同的接口根据不同的条件来指向具体想要创建的对象。
使用场景:执行new操作的时候,考虑是否需要使用工厂模式。

 class Product{constructor(name){this.name = name;}func1(){return `func1的名字:${this.name}`}func2(){return `func2的名字:${this.name}`}}class Creator{create(name){return new Product(name);}}//下面是测试代码let creator = new Creator();let getName = creator.create('小明');alert(getName.func1());alert(getName.func2());

经典的使用场景有:jquery的$('div),React.createElement()和vue的异步组件。

2. 单例模式(单一职责原则)
单例模式,顾名思义就是只有一个实例,并且她自己负责创建自己的对象,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。常用场景:购物车,登录框,vuex和redux中的store。


使用js模拟单例模式。

class SingleObject {login(){console.log('正在登陆中')}
}
SingleObject.getInstance = (function(){let instance;return function(){if(!instance){instance = new SingleObject();}return instance;}
})()let obj1 = SingleObject.getInstance();
obj1.login()
let obj2 = SingleObject.getInstance();
obj2.login()console.log('obj1=obj2吗?',obj1===obj2);// 跟java不同的是,js没有private,所以js new SingleObject()实现的单例模式不会报错
let obj3 = new SingleObject();
console.log('obj3和obj1是否相同:',obj1===obj3,obj3);

3. 适配器模式(开关封闭原则)
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。

class Adapter{request(){return '德国的标准插头'}
}class NewAdapter{constructor(){this.adapter = new Adapter();}newRequest(){return  `${this.adapter.request()}-->转换成-->中国标准插头`;}
}let newAdapter = new NewAdapter();
let newRequest = newAdapter.newRequest();
console.log(newRequest);

4. 装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。

class Boy{@run //给类属性方法(speak)加的一个装饰器 ,扩展了类Boy的speak(在讲话的同时跑步)speak (){console.log('I can speak')}
}
function run () {console.log('I can run')
}let tj =  new Boy()
tj.speak()// I can run
// I can speak

可安装babel-plugin-transform-decorators-legacy 插件或者core-decorators.js来实现装饰器。

5. 代理模式(符合开放封闭原则)
为其他对象提供一种代理以控制对这个对象的访问。

class ReadImg {constructor(fileName){this.fileName = fileName;this.load();}load(){console.log('正在从硬盘中读取图片数据~');}displayImg(){console.log('图片数据已经展示,啦啦啦');}
}class ProxyAddr{constructor(fileName){this.readImg = new ReadImg(fileName);}displayImg(){this.readImg.displayImg();}
}let proxy = new ProxyAddr('1.png');
proxy.displayImg();

6. 外观模式
目的是为了让子系统中的一组接口提供一个高级接口,让外部使用者调用该高级接口。不符合单一职责原则和开放封闭原则以及接口独立原则。

实现代码如下

function bindEvent(elem, type, selector, fn){if(fn===null){fn = selector;selector = null;}// *****
}bindEvent(elem, 'click', '#div', fn);
bindEvent(elem, 'click', fn)

7. 观察者模式( 符合开放封闭原则)
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。是最重要的一个设计模式。

// 主题和观察者分离,不是主动触发,而是被动监听,两者是解耦的
class Subject{constructor(){this.state = 0;this.observers = [];}getState(){return this.state;}setState(state){this.state = state;this.notifyAllobservers();}notifyAllobservers(){this.observers.forEach(observer=>{observer.update();})}append(obr){this.observers.push(obr);}
}class Observers{constructor(name,sub){this.name = name;this.subject = sub;this.subject.append(this);}update(){console.log(`${this.name}的state为:${this.subject.getState()}`)}
}//测试
let sub = new Subject();
let obs1 = new Observers('observers1', sub);
let obs2 = new Observers('observers2', sub);
let obs3 = new Observers('observers3', sub);
sub.setState(234)

应用场景有:jquery,node,vue和react



8. 迭代模式(开放封闭原则)
让用户通过特定的接口访问容器的数据,不需要了解容器内部的数据结构。

使用上面的方法实现迭代器模式,而不是下面这种。

9. 状态模式
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。下面举两个状态模式的例子。第一个是有限状态机。

// javascript-state-machine库
import StateMachine from 'javascript-state-machine';
let fsm = new StateMachine({init: '收藏',transition: [{name:'deleteStore',from:'收藏',to:'取消收藏'},{name:'store',from:'取消收藏',to:'收藏'}],method:{onDeleteStore(){alert('收藏->取消收藏');updateButText();},onStore(){alert('取消收藏->收藏');updateButText();}}
})let but = document.getElementById('but');// 点击按钮,实现切换按钮文本内容
but.onclick = function(){if(fsm.is('收藏')){fsm.onDeleteStore()}else{fsm.onStore()}
}function updateButText(){but.innerHTML = fsm.state;
}// 初始化
updateButText();

第二个是使用状态模式简单地实现promise。

import StateMachine from 'javascript-state-machine';
let fsm = new StateMachine({init: 'pending',transitions: [{name:'resolve',from:'pending',to:'fullfilled'},{name:'reject',from:'pending',to:'rejected'}],methods:{onResolve:function(state,data){data.successList.forEach(fn=>fn())},onReject:function(state,data){data.failureList.forEach(fn=>fn())}}
})// 自定义的promise
class MyPromise {constructor(fn){let _this = this;this.successList = [];this.failureList = [];fn(function(){fsm.resolve(_this);},function(){fsm.reject(_this);})};then(success,failure){this.successList.push(success);this.failureList.push(failure);}
}// 加载图片
function loadImg(src){let promise = new MyPromise(function(resolve,reject){let imgEle = document.createElement('img');//图片加载完成之后触发 imgEle.onload = function(){resolve(imgEle);}//图片加载失败之后触发imgEle.onerror = function(){reject();}imgEle.src= src;})return promise;
}//测试
let result = loadImg('http://yuhui7pm.cn/picture/xiongbenxiong.jpg');
result.then(function(){console.log('第一次图片加载成功');
},function(){console.log('第一次图片加载失败');
})result.then(function(){console.log('第二次图片加载成功');
},function(){console.log('第二次图片加载失败');
})// 结果:
// 第一次图片加载成功
// 第二次图片加载成功

10. 原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

// 原型对象
const person = {isHuman: false,printIntroduction: function () {console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);}
};// 基于原型对象创造的对象
const David = Object.create(person);
David.name = "David"; // "name" is a property set on "me", but not on "person"
David.isHuman = true; // inherited properties can be overwritten
David.printIntroduction();
// expected output: "My name is David. Am I human? true"// 基于原型对象创造的对象
const Lili = Object.create(person);
Lili.name = "Lili"; // "name" is a property set on "me", but not on "person"
Lili.isHuman = true; // inherited properties can be overwritten
Lili.printIntroduction();
// expected output: "My name is Lili. Am I human? true"

11. 桥接模式(开放封闭原则)
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。为什么需要该模式呢?
假设要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:

  • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
  • 第二种设计方案是根据实际需要对形状和颜色进行组合。

    对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。实例代码如下:

    12. 组合模型
    组合模式(Composite Pattern) 也称为 整体-部分(Part-Whole)模式,它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性。常见的应用为虚拟节点vnode。
   <div id="app"><span>{{ message }}</span><ul><li v-for="item of list" class="item-cls">{{ item }}</li></ul></div>

将上述html代码转换成vnode:

{"tag": "div","data": {"attr": { "id": "app" }},"children": [{"tag": "span","children": [{ "text": "hello Vue.js" }]},{"tag": "ul","children": [{"tag": "li","data": { "staticClass": "item-cls" },"children": [{ "text": "jack" }]},{"tag": "li","data": { "staticClass": "item-cls" },"children": [{ "text": "rose" }]},{"tag": "li","data": { "staticClass": "item-cls" },"children": [{ "text": "james" }]}]}],"context": "$Vue$3","elm": "div#app"
}

13. 享元模式
享元模式(Flyweight Pattern)主要是为了减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。该种模式在JS中没有应用场景,但是有预期思想类似的应用场景:

14.策略模式
策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。

策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。


15. 模板方法模式
模板方法模式(Template Method Pattern) 实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同实现,从而让固定的流程产生不同的结果。

class Client {public static void main(String[] args) {AbstractClass abc = new ConcreteClassA();abc.templateMehthod();abc = new ConcreteClassB();abc.templateMehthod();}// 抽象模板类static abstract class AbstractClass {protected void step1() {System.out.println("AbstractClass:step1");}protected void step2() {System.out.println("AbstractClass:step2");}protected void step3() {System.out.println("AbstractClass:step3");}// 声明为final方法,避免子类覆写public final void templateMehthod() {this.step1();this.step2();this.step3();}}// 具体实现类Astatic class ConcreteClassA extends AbstractClass {@Overrideprotected void step1() {System.out.println("ConcreateClassA:step1");}}// 具体实现类Bstatic class ConcreteClassB extends AbstractClass {@Overrideprotected void step2() {System.out.println("ConcreateClassB:step2");}}
}

16. 责任链模式(开放封闭原则)
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

class Action {constructor(name){this.name = name;this.nextAction = null}setNextAction(action){this.nextAction = action}handle(){console.log(`${this.name}审批`);if(this.nextAction != null){this.nextAction.handle();}}
}//测试代码
let a1 = new Action('组长');
let a2 = new Action('经理');
let a3 = new Action('总监');
a1.setNextAction(a2);
a2.setNextAction(a3);
a1.handle();// output:
// 组长审批
// 经理审批
// 总监审批

在Jquery的链式操作和Promise.then的链式操作中都有所体现。
17. 命令模式
什么是命令模式?假设现在有一个请求处理类(低层类/第三方类),如果客户端拿到这个类之后直接调用它,那么客户端和这个请求处理类之间的藕合度过高。

这时候我们在客户端的请求发送类和请求处理类之间增加一个Invoker类,再将请求发送类发送的所有请求封装成对象,然后让Invoker类去管理这些请求对象,并决定这些请求是否允许执行、何时执行、按什么顺序执行。

由于在请求发送类和请求处理类之间增加了请求转发者,因此这两个类之间的藕合度就大大降低。

 class Receiver {exec(){console.log('3.接收命令并执行');}}class Invoker {constructor(receiver){this.receiver = receiver;}invoke(){console.log('2.转发命令');this.receiver.exec();}}class Client{constructor(invoker){this.invoker = invoker;}command(){console.log('1.发布命令')this.invoker.invoke();}}// 测试
let receiver = new Receiver();
let invoker = new Invoker(receiver);
let client = new Client(invoker);
client.command();// output:
// 1.发布命令
// 2.转发命令
// 3.接收命令并执行

应用场景:在js中常见于富文本编辑器。
命令模式优点:

  1. 命令模式将请求发送者和请求处理者分离开,从而降低了这两个类之间的藕合;
  2. 通过在请求发送者和请求处理者之间增加转发类的方式,从而客户端发出的请求可以在被处理之前都存放在Invoker类的容器中,请求在被执行前就有了一个缓冲,能起到以下作用:
    a)Invoker能够对客户端发出的请求进行排序;
    b)Invoker能够决定是否需要驳回请求;
    c)客户端可以在请求被执行前选择撤销某个请求;
    d)在需要的情况下,客户端的请求可以被记录成日志;
  3. 增加新的命令时只需增加新的命令子类即可。

18.备忘录模式
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。

// 备忘录的某一项
class Item {constructor(item){this.item = item;}getItem(){return this.item;}
}// 备忘录列表
class Memo {constructor(){this.list = []}add(item){this.list.push(item);}get(index){return this.list[index]}
}// 编辑器
class Editor {constructor(){this.memonto = null;}setContent(item){this.memonto = item;}getContent(){return this.memonto;}saveContentToMomento(){return new Item(this.memonto);}getContentFromMemento(item){this.memonto = item.getItem();}
}// 测试
let editor = new Editor();
let memo = new Memo();editor.setContent('1111');
editor.setContent('2222');
memo.add(editor.saveContentToMomento()); // 备份
editor.setContent('3333');
memo.add(editor.saveContentToMomento()); // 备份
editor.setContent('4444');console.log(editor.getContent()); // output: 444
editor.getContentFromMemento(memo.get(1));
console.log(editor.getContent()); // output: 333
editor.getContentFromMemento(memo.get(0));
console.log(editor.getContent()); // output: 222

19. 中介者模式
定义一个中介者对象, 封装一系列对象的交互关系, 使得各对象不必显示的相互引用, 从而使其耦合松散, 而且可以独立的改变它们的交互。

 // 要求实现:A通过中介修改B的价格,B通过中介修改A的价格// 中介class Medium {constructor(clientA, clientB){this.clientA = clientA;this.clientB = clientB;}setAPrice(){let newPrice = this.clientA.price;this.clientA.revisePrice(newPrice + 200);}setBPrice(){let newPrice = this.clientB.price;this.clientB.revisePrice(newPrice + 400);}}// 用户Aclass ClientA {constructor(){this.price = 0;} revisePrice(price, medium){this.price = price;medium && medium.setAPrice();}getPrice(){console.log("clicentA's price:", this.price)}}// 用户Bclass ClientB {constructor(){this.price = 0;} revisePrice(price, medium){this.price = price;medium && medium.setBPrice();}getPrice(){console.log("ClientB's price:", this.price)}}// 测试let clientA = new ClientA();let clientB = new ClientB();let medium = new Medium(clientA, clientB);clientA.revisePrice(200, medium);clientB.revisePrice(200, medium);clientA.getPrice(); // output: clicentA's price: 400clientB.getPrice(); // output: ClientB's price: 600

20. 访问者模式
访问者模式是一种将数据操作和数据结构分离的设计模式。几乎没有使用场景,所以不多加介绍。感兴趣的小伙伴自行google。

21. 解释器模式
解释器模式(Interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。主要使用在babel,sass,less中。普通开发者的使用场景不多,这里不多加说明。

以上内容主要学习自双越老师的网课"JavaScript设计模式与开发实践",以及参考了其它博主的文章!

JavaScript设计模式与开发实践(网课学习)相关推荐

  1. 专访《Javascript设计模式与开发实践》作者曾探:爱编程 爱生活

     专访<Javascript设计模式与开发实践>作者曾探:爱编程 爱生活 发表于12小时前| 2742次阅读| 来源CSDN| 8 条评论| 作者夏梦竹 专访曾探图书作者Javascr ...

  2. JavaScript设计模式与开发实践系列之单例模式

    本系列为<JavaScript设计模式与开发实践>(作者:曾探)学习总结,如想深入了解,请支持作者原版 单例模式 实现单例模式 单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的 ...

  3. 《JavaScript设计模式与开发实践》模式篇(12)—— 装饰者模式

    在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活, 还会带来许多问题:一方面会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之 改变;另一方面,继承这种功能复 ...

  4. JavaScript设计模式与开发实践——JavaScript的多态

    "多态"一词源于希腊文polymorphism,拆开来看是poly(复数)+ morph(形态)+ ism,从字面上我们可以理解为复数形态. 多态的实际含义是:同一操作作用于不同的 ...

  5. 《JavaScript设计模式与开发实践》阅读摘要

    <JavaScript设计模式与开发实践>作者:曾探 系统的介绍了各种模式,以及js中的实现.应用,以及超大量高质量代码,绝对值得一读 面向对象的js 静态类型:编译时便已确定变量的类型 ...

  6. JS代理模式《JavaScript设计模式与开发实践》阅读笔记

    代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问. 保护代理和虚拟代理 保护代理:当有许多需求要向某对象发出一些请求时,可以设置保护代理,通过一些条件判断对请求进行过滤. 虚拟 ...

  7. 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式

    发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知.在 JavaScript 开发中,我们一般用事件模型 来替代传统的发布- ...

  8. 《JavaScript设计模式与开发实践》模式篇(3)—— 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 故事背景: 假设当 A 在心情好的时候收到花,小明表白成功的几率有 60%,而当 A 在心情差的时候收到花,小明表白的成功率无限趋近于 ...

  9. JavaScript设计模式与开发实践 | 02 - this、call和apply

    this JavaScript的this总是指向一个对象,至于指向哪个对象,是在运行时基于函数的执行环境的动态绑定的,而非函数被声明时的环境. this的指向 this的指向大致可以分为以下4类: 作 ...

最新文章

  1. 反编译插件jadclips
  2. java jdk缓存-128~127的Long与Integer
  3. CodeForces 392C Yet Another Number Sequence 矩阵快速幂
  4. ACL 2019开源论文 | 句对匹配任务中的样本选择偏差与去偏方法
  5. Android 仿王者荣耀广告弹窗,android仿王者荣耀对战资料之能力图
  6. Django基本命令
  7. JavaScript数组常用的方法总结
  8. mysql 批量删除之大坑
  9. linux下无权限安装ffmpeg-4.1.3
  10. 6.王道考研数据结构-栈
  11. gg修改器偏移量修改_GG修改器偏移是怎么弄 | 手游网游页游攻略大全
  12. UCOIII时间片轮转调度
  13. 中国地图填色问题Python API(动态)
  14. Pandas的基本操作
  15. 服务器搭建centos7系统操作过程(使用系统盘搭建centos7系统)
  16. 视频编解码 GOP基本概念
  17. mxgraph 画布
  18. 两台Ubuntu18.04局域网共享文件夹,互相访问
  19. 锐达机械对H型钢抛丸机的维修调整工作
  20. 推荐三款动态壁纸软件,足够让你的桌面惊艳!

热门文章

  1. python将一个列表赋值给另一个列表_将一个列表分配给另一个
  2. 解决Expected a string but was BEGIN_ARRAY错误 Gson
  3. FasterXML Jackson
  4. java中的事务管理
  5. 分布式 —— 基于Raft算法的KV服务
  6. 怎么用计算机上摄像头拍照,win7电脑怎么用摄像头拍照?win7电脑用摄像头拍照的详细步骤...
  7. Android Studio 用USB连接到真机调试方法
  8. 2006年最受瞩目的七大IT技术
  9. js阻止默认事件(a标签跳转),阻止事件冒泡
  10. PDF之父、Adobe联合创始人离世,乔布斯收购未果给了他第一桶金