web学习 -- JavaScript设计模式

设计模式

  1. 在软件工程中,设计模式是软件设计中常见问题可重用的解决方案。
  2. 设计模式代表着经验丰富的软件开发人员使用的最佳实践。
  3. 设计模式可以被认为是编程模板。

模块模式

模块是一段独立的代码,因此我们可以在不影响其他代码的情况下单独更新模块。
模块还允许我们为变量创建单独的作用域来避免命名空间的污染。
当它们与其他代码段分离时,我们也可以在其他项目中重用模块。

模块是任何现代 JavaScript 应用程序不可或缺的一部分,有助于保持代码清洁,分离和组织
有许多方法可以在JavaScript 中创建模块,其中一种是模块模式。

Bit之类的平台可以帮助将模块和组件转换为共享的构建块,可以与任何项目共享,发现和开发。
通过零重构,它是一种快速且可扩展的方式来共享和重用代码。

与其他编程语言不同,JavaScript 没有访问修饰符的特性,也就是说,你不能将变量声明为私有(private)或公开(public)。 因此模块模式也常常被用于模拟封装的概念。

此模式使用IIFE(立即调用的函数表达式),闭包和函数作用域来模拟此概念。

const myModule = (function() {
  
  const privateVariable = 'Hello World';
  
  function privateMethod() {
    console.log(privateVariable);
  }
 
  return {
    publicMethod: function() {
      privateMethod();
    }
  }
 
})();
 
myModule.publicMethod();
//"Hello World"
/*
* 执行代码后,myModule变量如下
 const myModule = {
  publicMethod: function() {
    privateMethod();
  }
};
*/

注:
由于上面的代码是IIFE,代码会立即执行,返回的对象被分配给 myModule 变量。 由于闭包,即使在IIFE完成之后,返回的对象仍然可以访问 IIFE 内定义的函数和变量。

因此,在 IIFE 中定义的变量和函数对外部作用域来说基本上是隐藏的,因此它们对 myModule 变量是私有的。

模块模式必须创建新的公开函数调用私有函数和变量

暴露模块模式(Revealing Module Pattern)

暴露模块模式是对模块模式略改进的版本

const myRevealingModule = (function() {
  
  let privateVar = 'Peter';
  const publicVar  = 'Hello World';
 
  function privateFunction() {
    console.log('Name: '+ privateVar);
  }
  
  function publicSetName(name) {
    privateVar = name;
  }
 
  function publicGetName() {
    privateFunction();
  }
 
  /** reveal methods and variables by assigning them to object     properties */
 
return {
    setName: publicSetName,
    greeting: publicVar,
    getName: publicGetName
  };
})();
 
myRevealingModule.setName('Mark');
 
// prints Name: Mark
myRevealingModule.getName();

/*
* 执行代码后,myRevealingModule 变量如下
const myRevealingModule = {
  setName: publicSetName,
  greeting: publicVar,
  getName: publicGetName
};
*/

优点

能够修改return语句中的一行代码,将成员从public(公开)变为private(私有),反之亦然
返回的对象不包含函数定义吗,所有右侧表达式都在IIFE中定义,使代码清晰易读

ES6 模块(ES6 Modules)

在ES6中,JavaScript拥有了原生的模块系统

ES6 模块存储在单独的文件中。
每个文件只能有一个模块。默认情况下,模块中的所有内容都是私有的。
函数、变量和类使用 export 关键字来向外公开。
模块内的代码总是在 严格模式(strict mode) 下运行。

导出模块

导出函数和变量声明有两种方法:

  1. 通过在函数和变量声明前添加 export 关键字。
// utils.js
export const greeting = 'Hello World';
 
export function sum(num1, num2) {
  console.log('Sum:', num1, num2);
  return num1 + num2;
}
 
export function subtract(num1, num2) {
  console.log('Subtract:', num1, num2);
  return num1 - num2;
}
 
// This is a private function
 
function privateLog() {
  console.log('Private Function');
}
  1. 通过在代码末尾添加 export 关键字,并包含我们要导出的函数和变量的名称
// utils.js
function multiply(num1, num2) {
  console.log('Multiply:', num1, num2);
  return num1 * num2;
}
function divide(num1, num2) {
  console.log('Divide:', num1, num2);
  return num1 / num2;
}
// This is a private function
function privateLog() {
  console.log('Private Function');
}
export {multiply, divide};

导入模块

导入模块也有两种方法进行导入

  1. 一次导入多个项目
// main.js
 
// importing multiple items
import { sum, multiply } from './utils.js';
 
console.log(sum(3, 7));
console.log(multiply(3, 7));

2)导入全部项目

// main.js
 
// importing all of module
import * as utils from './utils.js';
 
console.log(utils.sum(3, 7));
console.log(utils.multiply(3, 7));

导入/导出模块可以使用别名
1)重命名导出

// utils.js
 
function sum(num1, num2) {
  console.log('Sum:', num1, num2);
  return num1 + num2;
}
 
function multiply(num1, num2) {
  console.log('Multiply:', num1, num2);
  return num1 * num2;
}
 
export {sum as add, multiply};

2)重命名导入

import { add, multiply as mult } from './utils.js';
 
console.log(add(3, 7));
console.log(mult(3, 7));

单例模式(Singleton Pattern)

Singleton(单例) 是一个只能实例化一次的对象。

如果不存在,则单例模式会创建类的新实例;
如果存在实例,则它只返回对该对象的引用。

对构造函数的任何重复调用总是会获取相同的对象。

JavaScript 一直支持单例模式。 我们只是不称他们为单例,我们称之为 对象字面量

const user = {
  name: 'Peter',
  age: 25,
  job: 'Teacher',
  greet: function() {
    console.log('Hello!');
  }
};

注:JavaScript 中的每个对象占用一个唯一的内存位置,当我们调用 user 对象时,我们实际上是返回对该对象的引用。(ECMAScript中所有参数传递都是值,不可能通过引用传递参数)

使用构造函数实现单例模式

let instance = null;
 
function User() {
  if(instance) {
    return instance;
  }
 
  instance = this;
  this.name = 'Peter';
  this.age = 25;
  
  return instance;
}
 
const user1 = new User();
const user2 = new User();
 
// prints true
console.log(user1 === user2); 

使用模块模式实现单例

const singleton = (function() {
  let instance;
  
  function init() {
    return {
      name: 'Peter',
      age: 24,
    };
  }
 
  return {
    getInstance: function() {
      if(!instance) {
        instance = init();
      }
      
      return instance;
    }
  }
})();
 
const instanceA = singleton.getInstance();
const instanceB = singleton.getInstance();
 
// prints true
console.log(instanceA === instanceB);

工厂模式

工厂模式是一种使用工厂方法创建对象的设计模式,而不指定创建对象的确切的类或构造函数

工厂模式用于在不公开实例化逻辑的情况下创建对象

工厂定义

class Car{
  constructor(options) {
    this.doors = options.doors || 4;
    this.state = options.state || 'brand new';
    this.color = options.color || 'white';
  }
}
 
class Truck {
  constructor(options) {
    this.doors = options.doors || 4;
    this.state = options.state || 'used';
    this.color = options.color || 'black';
  }
}
 
class VehicleFactory {
  createVehicle(options) {
    if(options.vehicleType === 'car') {
      return new Car(options);
    } else if(options.vehicleType === 'truck') {
      return new Truck(options);
      }
  }
}

使用工厂

const factory = new VehicleFactory();
 
const car = factory.createVehicle({
  vehicleType: 'car',
  doors: 4,
  color: 'silver',
  state: 'Brand New'
});
 
const truck= factory.createVehicle({
  vehicleType: 'truck',
  doors: 2,
  color: 'white',
  state: 'used'
});
 
// Prints Car {doors: 4, state: "Brand New", color: "silver"}
console.log(car);
 
// Prints Truck {doors: 2, state: "used", color: "white"}
console.log(truck);

装饰者模式(Decorator Pattern)

装饰者模式用于扩展对象的功能,而无需修改现有的类或构造函数
此模式可用于向对象添加功能,而无需它们修改底层代码

简单举例:

function Car(name) {
  this.name = name;
 
  // Default values
  this.color = 'White';
}
 
// Creating a new Object to decorate
const tesla= new Car('Tesla Model 3');
 
// Decorating the object with new functionality
 
tesla.setColor = function(color) {
  this.color = color;
}
 
tesla.setPrice = function(price) {
  this.price = price;
}
 
tesla.setColor('black');
tesla.setPrice(49000);
 
// prints black
console.log(tesla.color);

复杂例子:
创建基类

class Car() {
}
 
class CarWithAC() {
}
 
class CarWithAutoTransmission {
}
 
class CarWithPowerLocks {
}
 
class CarWithACandPowerLocks {
}

使用装饰者函数

class Car {
  constructor() {
    // Default Cost
    this.cost = function() {
      return 20000;
    }
  }
}
 
// Decorator function
function carWithAC(car) {
  car.hasAC = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}
 
// Decorator function
function carWithAutoTransmission(car) {
  car.hasAutoTransmission = true;
   const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 2000;
  }
}
 
// Decorator function
function carWithPowerLocks(car) {
  car.hasPowerLocks = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}

首先,我们创建一个基类 Car,用于创建 Car 对象。
然后,然后我们为了不同的功能创建了装饰者函数,并将 Car 对象作为参数传递。
然后我们覆盖该对象的成本函数,该函数返回汽车的更新成本,并向该对象添加新属性以指示添加了哪个特征。

添加新功能:

const car = new Car();
console.log(car.cost());
 
carWithAC(car);
carWithAutoTransmission(car);
carWithPowerLocks(car);

最后计算汽车成本

// Calculating total cost of the car
console.log(car.cost());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值