JavaScript 设计模式包括以下五个原则:单一职责原则(S)、开放封闭原则(O)、里氏替换原则(L)、接口分离原则(I)和依赖倒置原则(D)。
1. 工厂模式:将对象的创建过程封装在工厂类中,使得客户端不需要关心对象的具体实现。这样可以降低耦合度,提高代码的可维护性。示例代码如下:
```javascript
class CarFactory {
constructor(name) {
this.name = name;
}
productBus() {
console.log(this.name, '生产公交车');
}
productCar() {
console.log(this.name, '生产小汽车');
}
}
class Creator {
constructor(name) {
return new CarFactory(name);
}
}
// 测试
let p = new Creator('汽车工厂');
p.productBus();
p.productCar();
```
应用场景:jQuery、React.createElement 和 Vue.component 都是遵循这些设计原则的例子。
ue.js 中的异步组件示例:
```javascript
setTimeout(() => {
resolve({
template: '
})
}, 1000);
});
```
单例模式示例:
```javascript
class SinglonObject {
login() {
console.log('登录');
}
}
SinglonObject.getInstance = (() => {
let instance;
return () => {
if (!instance) {
instance = new SinglonObject();
}
return instance;
};
})(); // 测试
let login1 = SinglonObject.getInstance();
let login2 = SinglonObject.getInstance();
login1.login();
login2.login();
console.log(login1 === login2);
```
jQuery 的单例模式实现:
```javascript
if (window.jQuery != null) {
return window.jQuery;
} else {
// 初始化
}
```
```javascriptclass LoginDialog {
constructor() {
this.state = 'hide';
}
show() {
if (this.state === "show") {
console.log("登录框已显示");
return;
}
this.state = 'show';
console.log("显示登录框");
}
hide() {
if (this.state === "hide") {
console.log("登录框已隐藏");
return;
}
this.state = 'hide';
console.log("隐藏登录框");
}
}
// 测试
let login1 = LoginDialog.getInstance();
let login2 = LoginDialog.getInstance();
login1.show();
login2.show();
console.log(login2 == login1);
```
```
class Adaptee {
specialRequest() {
return '德国插头';
}
}
class Target {
constructor() {
this.adaptee = new Adaptee();
}
request() {
return `${this.adaptee.specialRequest()}--->中国插头`;
}
}
function createTarget() {
return new Target();
}
let target = createTarget();
let res = target.request(); // "德国插头--->中国插头"
console.log(res); // "德国插头--->中国插头"
```
```javascriptclass Circle {
draw() {
console.log('画一个圆');
}
}
class Decorator {
constructor(circle) {
this.circle = circle;
}
draw() {
this.circle.draw();
this.setRedBorder(this.circle);
}
setRedBorder(circle) {
console.log('给圆设置红色边框');
}
}
let circle = new Circle();
circle.draw();
console.log(circle); // {}
let dec = new Decorator(circle);
dec.draw();
// [Circle] {} // Circle类的原型被添加到了装饰器中,所以在dec中也可以看到Circle类的内容。
function testDec(isDec) {
return target => {
target.isDec = isDec;
};
}
@testDec(true) class Demo {}; // Demo类现在具有isDec属性,值为true。可以通过Demo.isDec获取。
console.log(Demo.isDec); // true
const Foo = { foo() { console.log('foo'); } }; // Foo对象具有foo方法。
@Mixins(Foo) class MyClass {}; // MyClass类继承了Foo对象的所有方法。可以通过new MyClass().foo()调用foo方法。
let obj = new MyClass();
obj.foo(); // 'foo'
function makeImmutable(target) {
return Object.freeze((Object.assign(Object.create(target), target))); // 将目标对象转换为只读对象,使其不可修改。
}
const immutableObj = makeImmutable({ foo: function() {} }); // 在makeImmutable函数中使用Object.create创建了一个新对象,该对象与原始对象共享所有属性,但不是同一个对象。因此,immutableObj可以访问原始对象的属性,但不能直接修改它们。例如,immutableObj.foo()将调用原始对象的属性,而不是重新定义它。如果尝试通过immutableObj来修改属性,则会抛出错误。例如,immutableObj.foo = function() {}将引发TypeError。
```javascript/**
* @desc 只读
* @param {Class} target 目标类
* @param {string} name 属性名
* @param {Object} descriptor 属性描述对象,包含四个值:writable、enumerable、configurable、value
*/
function readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Person {
constructor() {
this.first = 'a';
this.last = 'b';
}
@readonly
getName() {
return `a: ${this.first}, b: ${this.last}`;
}
}
let people = new Person();
console.log(people.getName()); // people.getName = 'iwen' 修改会报错
import { deprecate } from "core-decorators";
class Person {
@deprecate({ message: '即将废弃', url: 'www.baidu.com' })
getName() {
return "iwen";
}
}
let p = new Person();
console.log(p); // 在不修改 add 方法的前提下打印出参数:Person { first: 'a', last: 'b', getName: [Function] }
```
## 代理模式
客户端与主机无法直接交互,但通过代理可以实现访问。例如,科学上网和公司内部网络的访问。
### RealImg
```javascript
class RealImg {
constructor(fileName) {
this.fileName = fileName;
this.loadFromDisk();
}
console.log('加载', this.fileName);
}
display() {
console.log('显示', this.fileName);
}
}
```
### ProxyImg
```javascript
class ProxyImg {
constructor(fileName) {
this.realImg = new RealImg(fileName);
}
display() {
this.realImg.display();
}
}
```
使用示例:
```javascript
let proxyImg = new ProxyImg('1.png');
proxyImg.display();
```
```javascript// 明星经纪人
const star = {name: '张xx', age: 18, phone: 'star 16666666666'};
const agent = new Proxy(star, {
get(target, key, val) {
if (key === 'phone') {
return 'agent 15888888888';
}
if (key === 'price') {
return 120000;
}
return target[key];
},
set(target, key, val) {
if (key === 'customPrice') {
if (val < 100000) {
console.log('价格太低');
} else {
target[key] = val;
return;
}
}
}
});
console.log(agent.phone); // agent 15888888888
console.log(agent.price); // 120000
console.log(agent.name); // 张xx
agent.customPrice = 1200;
```
应用场景
## 页面事件绑定
在前端开发中,我们经常需要为页面元素绑定事件处理器。例如,当用户点击按钮时触发某个函数。这时候,我们可以使用事件代理来简化代码。
```javascript
document.getElementById('button').addEventListener('click', function() {
// do something
});
```
## Promise中的then
Promise 是 JavaScript 中用于处理异步操作的一种方式。当我们需要在 Promise 完成后执行一些操作时,可以使用 `then` 方法。
```javascript
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 1000);
});
promise.then(function(value) {
console.log(value); // 'success'
});
```
## Node中的Event
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。在 Node.js 中,我们可以使用 `EventEmitter` 类来处理事件。
```javascript
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
console.log('event occurred');
});
myEmitter.emit('event'); // 'event occurred' logged to the console
```
## Vue中的生命周期
在 Vue.js 中,每个组件都有一个生命周期,可以在不同的阶段执行一些操作。例如,在组件创建完成后执行一些初始化操作。
```javascript
new Vue({
el: '#app',
data: {},
created() {
console.log('Component created'); // 'Component created' logged to the console after the component is instantiated
}
});
```
```javascriptclass State {
constructor(color) {
this.color = color;
}
handle(context) {
console.log(`turn to ${this.color} light`);
context.setState(this);
}
}
class Context {
constructor() {
this.state = null;
}
getState() {
return this.state;
}
setState(state) {
this.state = state;
}
}
let context = new Context();
let red = new State('红灯');
let green = new State('绿灯');
let yellow = new State('黄灯');
red.handle(context);
console.log(context.getState()); // State: RedLight
green.handle(context);
console.log(context.getState()); // State: GreenLight
yellow.handle(context);
console.log(context.getState()); // State: YellowLight
```
这段代码是使用javascript-state-machine库实现的状态机。状态机是一种行为模型,它将系统分为一组有限的状态,每个状态都有自己的规则。在这个例子中,状态机有两个状态:收藏和取消收藏。当用户点击一个按钮时,程序会根据当前状态执行相应的操作。如果当前状态是收藏,则执行doStore方法;否则,执行deleteStore方法。这两个方法都会调用updateText函数来更新按钮的文本。
责任链模式
```javascript
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();
```
策略模式
```javascript
function strategy(condition) {
switch (condition) {
case 'A':
return function() { /* ... */ };
case 'B':
return function() { /* ... */ };
case 'C':
return function() { /* ... */ };
}
}
let condition = 'A'; // 或者根据实际需求获取条件值
let strategyFunction = strategy(condition); // 根据条件选择对应的策略函数
strategyFunction(); // 执行策略函数
```
桥接模式是一种结构性模式,将抽象部分与实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称柄体(Handle and body)模式或者接口(Interface)模式 。当一个抽象可能有多个实现时,通常用继承来协调他们。
```javascript// 原型模式实现
const prototype = {
sayName() {
return `${this.first} ${this.last}`;
},
say() {
return 'hello';
},
};
// 基于原型创建x
let x = Object.create(prototype);
x.first = 'a';
x.last = 'b';
console.log(x.sayName()); // a b
console.log(x.say()); // hello
// 基于原型创建y
let y = Object.create(prototype);
y.first = 'c';
y.last = 'd';
console.log(y.sayName()); // c d
console.log(y.say()); // hello
```