所谓的程序设计模式,主要目的无非就是为了低耦合高内聚、减少冗余代码,、 提高代码利用率。
注:该文章所提到的构造函数模式,这个倒不是经典的几十个设计模式之一,而只是面向对象的一个典型的实现过程,就是构造对象前需要初始化的一个过程,把这个过程叫做构造。
还不太清楚工厂模式和构造函数模式的同学,可以看看下面的示例代码 :
工厂模式和构造函数模式示例代码
一、工厂模式
- 把实现同一件事的相同代码封装到一个函数里, 通过这个函数可以批量生产相同功能
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