3.Contructor(构造器)模式—精读《JavaScript 设计模式》Addy Osmani著

967 阅读5分钟

同系列友情链接:


1.设计模式之初体验—精读《JavaScript 设计模式》Addy Osmani著
2.设计模式的分类—精读《JavaScript 设计模式》Addy Osmani著

Construct(构造器)模式


在经典的面向对象编程语言中,Construtor是一种在内存已分配给该对象的情况下,用于初始化新创建对象的特殊方法。

在 JavaScript 中,几乎所有东西都是都是对象,可能你会经常找不到对象,😝,你承认不?😁

来看一下什么是 Object构造器 :

用于创建特定类型的对象——准备好对象以备使用,同时接受构造器可以使用的参数,以在第一次创建对象时,设置成员属性和方法值。

下图为:Constructor(构造器)模式

Object构造器

对象的创建

在 JavaScript 中,创建对象时有发生,常见的创建方式有两种:

  1. 直接空对象赋值;
  2. 使用 new关键字
// 1. 直接空对象赋值
var newObject = {};

// 2. 使用 new 关键字创建,newObject构造器的简洁记法
var newObject = new Object();

在 Object构造器为特定的值创建对象封装,或者没有传递值时,它将创建 一个空对象并返回这个空对象;

对象的赋值

四种方法可以将键值赋值给一个对象:

  1. ECMAScript 3 兼容方式;
    1. “点”语法;
    2. 中括号语法
  2. 只适用于ECMAScript 5 方式;
    1. Object.defineProperty;
    2. Object.defineProperties
// 1.点语法
// 设置属性
newObject.someKey = "Hello World!";
// 获取属性值
var key = newObject.someKey;


// 2.中括号语法
// 设置属性
newObject["somekey"] = "Hello world!";
// 获取属性值
var key = newObject["somekey"];


// 3.Object.defineProperty
// 设置属性
Object.defineProperty(newObject,"somekey",{
    value:"Hello World!",// 该属性对应的值,默认为undefined
    writable:true,// 能否修改属性的值,如果直接使用字面量定义对象,默认值为true
    enumerable:true,// 表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true
    configurable:true// 表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true
});
// 也可以简化一下这种方式
var defineProp = function(obj,key,value){
    config.value=value;
    Object.defineProperty(obj,key,config);
}
// 使用上述方式,先创建一个空的 person对象
var person = Object.create(null);
// 然后设置各个属性
defineProp(person,"car","Delorean");
defineProp(person,"dateOfBrith","1989");
defineProp(person,"hasBeard",false);
// 获取属性值同1,2
var key_car = person["car"];
var key_dateOfBrith = person["dateOfBrith"];
var key_hasBeard = person["hasBeard"];


// 4.Object.defineProperties
// 设置属性
Object.defineProperties(newObject,{
    "someKey":{
        value:"Hello World!",
        writable:true
    },
    "anotherKey":{
        value:"Foo Bar",
        writable:false
    }
});
// 获取属性值同1,2
var key_someKey = person["someKey"];
var key_anotherKey = person["anotherKey"];

上面定义的这些方法甚至可以用于继承如下所示:

// 用法
// 创建赛车司机 driver 对象,继承于 person 对象
var driver = Object.create(person);
// 为 driver 设置一些属性
defineProp(deriver,"topSpeed","100mph");
// 获取继承属性
console.log(driver.dateOfBrith);
// 获取我们设置的100mph属性
console.log(driver.topSpeed);

基本Constructor(构造器)

大家都知道 JavaScript 不支持类的概念,但是它却支持与对象一起使用的 特殊的 Constructor 函数。通过在构造器前面加 new关键字,告诉 JavaScript 像使用构造器一样实例化一个新的对象,并且对象成员由该函数定义。

在构造器内,关键字 this引用新创建的对象。回顾对象创建,基本的构造器看起来可能是这样的:

function Car(model,year,miles){
    this.model = model;
    this.year = year;
    this.miles = miles;
    this.toString= function(){
        return this.model+ " has done " + this.miles + " miles";
    }
}
// 用法
var civic = new Car("Honda Civic",2009,20000);
var mondeo= new Car("Ford Mondeo",2010,5000);

console.log(civic.toString());
console.log(mondeo.toString());

上面是一个简单的构造器模式版本,但是也是存在问题的:因为她很难继承,另一个 问题就是 toString()这样的函数是为每个使用 Car 构造器创建的新对象而重新定义的。 这不是最理想的,因为这种函数应该在所有的 Car 实例之间共享。

其实这个问题很好解决,因为有很多ES3和 ES5兼容替代方法能够用于创建对象。

带原型的Constructor(构造器)

JavaScript中有一个名为 prototype 的属性。调用 JavaScript 构造器创建一个对象后,新的对象就具有构造器原型的所有属性。通过这种方式,可以创建多个 Car 对象,并访问相同的原型。所以我们可以扩展原始示例,如下所示:

function Car(model,year,miles){
    this.model = model;
    this.year = year;
    this.miles = miles;
}
// 前方警告:小伙伴是否还记得反模式一条:避免重新定义 prototype对象
// 所以下面我们是使用 Object.prototype.newMethod而不是Object.prototype来定义对象内部的方法
Car.prototype.toString=function(){
    return this.model+ " has done " + this.miles + " miles";
}
// 用法
var civic = new Car("Honda Civic",2009,20000);
var mondeo= new Car("Ford Mondeo",2010,5000);

console.log(civic.toString());
console.log(mondeo.toString());

// 这样 toString()的单一示实例就可以在所有的 Car 对象之间共享了

小结

今天的构造器模式,是不是很nice?

但是,你掌握了多少?

你可以动动小手指示例代码都敲一遍,相信你可以更进一步了解,掌握 Constructor(构造器)模式。

下一篇将对Module(模块)模式做详细的介绍。这一模式更精彩,因为很快你就会知道为什么别人都那么写了,以及模块化的相关概念等等等

( ^_^ )/~~拜拜