如何区分工厂模式和构造函数模式?

所谓的程序设计模式,主要目的无非就是为了低耦合高内聚、减少冗余代码,、 提高代码利用率。
注:该文章所提到的构造函数模式,这个倒不是经典的几十个设计模式之一,而只是面向对象的一个典型的实现过程,就是构造对象前需要初始化的一个过程,把这个过程叫做构造。

还不太清楚工厂模式和构造函数模式的同学,可以看看下面的示例代码 :
工厂模式和构造函数模式示例代码

一、工厂模式

  • 把实现同一件事的相同代码封装到一个函数里, 通过这个函数可以批量生产相同功能
function personFactory (name, age) {
  let obj = { name, age };
  obj.info = function() {
    console.log(`name: ${this.name}, age: ${this.age}`);
  };
  return obj;
}

let Jay = personFactory('Jay', 18);
Jay.info(); // name: Jay, age: 18

let Jolin = personFactory('Jolin', 17);
Jolin.info(); // name: Jolin, age: 17

二、构造函数模式

  • 创建自定义的类, 并且可以创建这个类的实例
  • 用法上,与工厂模式的区别在于使用new来创建实例,用来创建实例的函数就变成了一个类
  • 由于使用函数来实现类,所以在JS中,类的数据类型为函数数据类型
  • 类产生的实例都是对象数据类型
  • 不用手动创建对象返回,JS会自己创建并返回对象数据类型,就是当前类的实例
function StarClass(name, age) {
  this.name = name;
  this.age = age;
  this.info = function() {
    console.log(`name: ${this.name}, age: ${this.age}`);
  }
}

let JoStar = new StarClass('JoStar', 20);
JoStar.info(); // -> name: JoStar, age: 20

let Dio = new StarClass('Dio', 21);
Dio.info(); // -> name: Dio, age: 21

用new执行时,上面的this的指向就是构造函数所指向的实例。

但是,如果构造函数当作普通函数执行,则会出现一些问题:当成普通函数执行,函数中的this便指向了全局对象。
如果以浏览器为例的话,把属性就被挂载到window下,并且由于没有返回对象,所以函数结果为undefined。

let normalFn = StarClass('GG', 22);
console.log(normalFn); // -> undefined
normalFn.info(); // 报错

和其他编程语言一样,若创建实例时不用传参的话,那么创建时就可以不用写括号;而普通函数不能这样。

function NoBrackets () {
  this.x = 10;
  this.info = function() {
    console.log(`this x: ${this.x}`);
  }
}

let nobracket = new NoBrackets;
nobracket.info(); // this x: 10

三、私有变量

当在构造函数内部定义私有变量时,使用var、let、const之类定义时,这种变量只是函数的私有变量,并不会挂载到示例上;只有使用 this.xxx = xxx 的方式创建的变量才能被挂载到实例上

function PrivateVariable () {
  let x = 100;
  this.info = function() {
    console.log(`this x: ${this.x}, Private x: ${x}`);
  }
}

let priVar = new PrivateVariable;
priVar.info(); // this x: undefined, Private x: 100

四、返回值

构造函数模式不需要返回值。
如果写了返回值,则有以下两种情况:

  • 返回值为普通数据类型时,不影响构造函数运行
  • 返回值为对象数据类型时,则实例就被替换为返回的对象类型
function ReturnVariable () {
  let x = 100;
  this.info = function() {
    console.log(`this x: ${this.x}, Private x: ${x}`);
  }
  // return 200; // 当返回值为基本数据类型, 不影响构造函数
  return {x: 200} // 当返回值为对象数据类型, 则示例为这个返回值
}

let returnVar = new ReturnVariable;
console.log(returnVar);

五、判断实例是否属于某个类

一般可以使用instanceof 来检测实例是否属于某个类。
但是如果直接检测Object或者这个类含有父类,这些情况就不能用instanceof 来检测了。

function BelongTo (value) {
 this.value = value
 this.info = function () {
   console.log(`value: ${value}`);
 }
}

let belongTo = new BelongTo;
console.log(`is BelongTo Class ? ${belongTo instanceof BelongTo}`); // -> is BelongTo Class ? true
console.log(`is Array ? ${belongTo instanceof Array}`); // -> is Array ? false
console.log(`is Object ? ${belongTo instanceof Object}`); // is Object ? true

六、判断属性是否属于某个对象

  • in检测:attr in object ,不管是私有属性或者公有属性,只要存在于对象中就返回true
  • hasOwnProperty检测:用来检测某个属性是否为这个对象的私有属性,经常与遍历对象属性组合使用
function HasAttr (value) {
  this.privateValue = value
  this.info = function () {
    console.log(`value: ${value}`);
  }
}

HasAttr.prototype.publicValue = 'public value';
 
let attrObj = new HasAttr('attrValue');
console.log(`${'privateValue' in attrObj}`); // -> true
console.log(`${'publicValue' in attrObj}`); // -> true
console.log(`${attrObj.hasOwnProperty('privateValue')}`); // -> true
console.log(`${attrObj.hasOwnProperty('publicValue')}`); // -> false

你可能感兴趣的:(如何区分工厂模式和构造函数模式?)