• JavaScript 创建对象之单例、工厂、构造函数模式


    01单例模式

    首先看一个问题,我们要在程序中描述两个人,这两个人都有姓名和年龄,可能刚刚开始学习js的时候会写成这样:

    1 var name1 = 'iceman';
    2 var age1 = 25;
    3 
    4 var name2 = 'mengzhe';
    5 var age2 = 26;

    以上的写法的确是描述两个人,每个人都有姓名和年龄,但是每个人的姓名和年龄并没有放在一起,也就是说每个人的年龄和姓名并没有对应起来。这时候我们就引出对象的概念:把描述同一个事物(同一个对象)的属性和方法放在同一个内存空间下面,起到了分组的作用,这样不同事物之间的属性即使属性名相同相互也不会发生冲突。

    1 var person1 = {
    2     name:'iceman',
    3     age:25};
    4 
    5 var person2 = {
    6     name:'mengzhe',
    7     age:26};

    以上这种写法可以认为是一种分组编写代码的模式,通过如此分组之后,每一个人的姓名和年龄都在同一块内存空间下,也就是每个人的姓名和年龄都对应起来了。我们也把这种分组编写代码的模式称之为单例模式(在《JavaScript高级程序设计》中也称之为对象字面量模式),在单例模式中,把person1和person2叫做命名空间。

    单例模式是一种项目开发中经常使用的模式,因为项目中我们可以使用单例模式来进行模块化开发,对一个相对来说比较大的项目中,需要多人协作开发,所以一般情况下会根据当前项目的需求,划分几个功能模块,每个人负责一部分,同时开发,最后把每个人的代码进行合并,比如:

     公共模块:提供公共方法

    1 var utils = {
    2   select:function () {
    3       //...
    4   }
    5 };

    页面选项卡模块:实现选项卡切换

    1 var tabModule = {
    2   change:function () {
    3       utils.select(); // 在自己的命名空间下调用其他命名空间的方法
    4   }
    5 };

    搜索模块:实现搜索内容变化的处理

    1 var searchModule  = {
    2   change:function () {
    3       this.clickEvent(); // 在自己的命名空间下调用自己命名空间的方法
    4   },
    5   clickEvent:function () {
    6       //...
    7   }
    8 };

    以上在例子中,在选项卡模块(tabModule)和和搜索模块(searchModule)中都有change方法,如果没有分模块来编写的话会造成命名的冲突,按照JavaScript语言的解析规则,后声明的方法会覆盖前面声明的方法。而通过模块划分之后,这两个模块下的change方法归属于各自的模块,调用的时候都是调用自己模块下的方法(tabModule.change()、searchModule.change()),不会有冲突。

    02工厂模式

    回顾单例模式:
    1 var person1 = {
    2     name:'iceman',
    3     age:25,
    4     writeJs:function () {
    5         console.log(this.name + 'write js');
    6     }
    7 };
    8 person1.writeJs();

    单例模式解决了分组的问题,让每个对象有了自己独立的命名空间,但是不能批量生产,每一个新的对象都要重新写一份一模一样的代码。这时候就有了工厂模式,即:把实现同一事情的相同代码,放到一个函数中,以后如果再想实现这个功能,就不需要重新编写这些代码了,只要执行当前的函数即可,这就是函数的封装,体现了高内聚、低耦合的思想:减少页面的中的冗余代码,提高代码的重复利用率:

     1 function createPerson(name, age) {
     2     var obj = {};
     3     obj.name = name;
     4     obj.age = age;
     5     obj.writeJs = function () {
     6         console.log(this.name + 'write js');
     7     }    return obj;
     8 }
     9 
    10 var p1 = createPerson('mengzhe' , 26);
    11 p1.writeJs();
    12 
    13 var p2 = createPerson('iceman' , 25);
    14 p2.writeJs();

    顺便讲一下重载:在Java、C#等强类型的面向对象编程语言中,有函数重载的概念,但是在JavaScript中不存在重载,如果方法名一样的话,后面的会把前面的覆盖掉,最后只保留一个方法的定义,不过我们可以根据传递的参数不一样,实现模拟重载的功能:

    1 function sum(num) {    if (typeof num === 'undefined') {        return 0;
    2     }    return num;
    3 }
    4 sum(100);
    5 sum();

    03构造函数模式

     1 function CreateJsPerson(name, age) {
     2     this.name = name;
     3     this.age = age;
     4     this.writeJs = function () {
     5         console.log(this.name + 'write js');
     6     }
     7     // 浏览器再把创建的实例默认的进行返回
     8 }
     9 var p1 = new CreateJsPerson('iceman' , 25);
    10 p1.writeJs();
    11 var p2 = new CreateJsPerson('mengzhe' , 26);
    12 p2.writeJs();

    注意:上面是new CreateJsPerson('iceman' , 25)这样,使用了new创建了对象,这和普通调用函数的方式有区别的:

    1 var res = CreateJsPerson('xx' , 7);

    这样没有用new而直接调用函数的方式,不是构造函数而是普通函数执行,由于没有写return,所以res=undefined,并且CreateJsPerson这个方法中的this是window。

    构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。

    构造函数模式和普通函数的模式的区别:

    执行的时候

    • 普通函数执行:CreateJsPerson()

    • 构造函数执行:new CreateJsPerson(),通过new执行后,CreateJsPerson就是一个类了,而函数的返回值就是CreateJsPerson这个类的一个实例。

    在函数代码执行的时候

    • 相同:都是形成一个私有的作用域,然后经历:形参赋值 --> 预解释 --> 代码从上到下执行(类和普通的函数一样执行,它也有普通函数的一面)。

    • 不同:① 在构造函数的代码执行之前,不用自己再手动的创建对象,浏览器会默认的创建一个对象数据类型的值(这个对象类型的值其实就是当前类的一个实例);② 接下来代码从上到下执行,以当前实例为执行的主体(this代表的就是当前的实例),然后分别的把属性名和属性值赋值给当前的实例;③ 最后,浏览器会默认的把创建的实例返回。 

    注意点:

    • JavaScript中所有的类都是函数数据类型的,它通过new执行变成了一个类,但是它本身也是一个普通的函数;

    • JavaScript中所有的实例都是对象数据类型的;

    • 在构造函数模式中,类中(函数体中)出现的 this.xx = xx中的this是当前类的一个实例;

    • p1和p2都是CreatePerson这个类的实例,所以都拥有writeJs这个方法,但是不同实例之间的方法是不一样的,在类中给实例增加的属性(this.xxx=xxx)属于当前实例的私有的属性,实例和实例之间是单独的个体,所以私有的属性之间是不相等的。

      1 console.log(p1.writeJs === p2.writeJs); // --> false



  • 相关阅读:
    Linux内存管理1---内存寻址
    UML和模式应用5:细化阶段(10)---UML交互图
    AT91RM9200---电源管理控制器(PMC)介绍
    AT91RM9200---定时器简介
    [转]指针大小是由谁决定的?
    UML和模式应用5:细化阶段(9)---迈向对象设计
    UML和模式应用5:细化阶段(8)---逻辑架构和UML包图
    UML和模式应用5:细化阶段(7)---从需求到设计迭代进化
    UML和模式应用5:细化阶段(6)---操作契约
    VxWorks软件开发项目实例完全解析1-VxWorks简介
  • 原文地址:https://www.cnblogs.com/haonanZhang/p/6372875.html
Copyright © 2020-2023  润新知