接着上篇介绍的在 JavaScript 中面向对象编程的工厂模式,我们发现其实这个模式虽然解决了基本模式的创建多个对象的麻烦,但是呢还有一些问题的,当然,这些问题也是可以解决的。那么本章来介绍一下如何解决上篇留下的的问题并去改进它。首先,用构造函数有什么好处:

① 使用了 new 调用的函数为构造函数,构造函数和普通函数区别仅仅在于是否使用了new 来调用
② 所谓“构造函数”,就是专门用来生成“对象”函数,它提供模板作为对象的基本结构,其他的就属于基本普通的函数
③ 构造函数内部使用了 this变量。对构造函数使用new 运算符,就能生成实例,并且this 变量会绑定在实例对象上
虽然构造函数解决了是否使用的 new 关键字来调用的,但是也没有解决 工厂模式出现的浪费内存的问题:每生成一个实例,都会增加一个重复的内容。

上面说到使用 new 关键字,为什么要使用 new 关键字,使用了给我们带来了什么变化。举个简单的例子:

<script>
   //new 关键字
   function fun(){
    alert(this);
   }
   fun();       //弹出的是 object window
   new fun();       //弹出的是 object object
   // 说明如果使用 new 关键字,函数 fun 里面 this 就是新创建出来的对象,如果没有 new 就是 window
</script>

看完上面的代码我们就知道在构造函数中使用 new 关键字的重要性了。
具体实例我们看如下代码:

<script>
   // 为了和工厂模式做区别,把上篇创建的函数复制过来
   function createPeople(name,weapon){
    // 这里没有 var people = new Object(); 此步骤是系统在后台默认完成的
    /* 都是使用的 this 关键字,而不是用的创建的对象 people ;
    * 使用 this 我们在下面 new createPeople() 就是在我们函数里面新创建一个对象,
    * 相当于上一步在函数内部 var people = new Object();
    */
    this.name = name;
    this.weapon = weapon;
    this.run = function(){
       return this.name + '的武器是' + this.weapon;
    };
   // 没有 return people; 这个对象,注意看上篇的代码, 此步骤是系统在后台默认完成的
   }
   var wujing = new createPeople('沙悟净','禅杖');
   var wukong = new createPeople('悟空','金箍棒');
   var bajie = new createPeople('八戒','钉耙');
   alert(wujing.run());
   //instanceof 判断实例化的函数是不是 createPeople 函数创建的,解决了工厂模式出现的 实例与原型的内在联系。
   alert(wujing instanceof createPeople);
</script>

这里在复习以之前讲到的 JavaScript 中 This 关键字的使用 里面的 Apply() 和 Call(),我们说这两个方法可以实现改变函数运行的作用域,所以在面向对象的时候用的是有很多的,接着上面的代码

<script>
   var monster = new Object();
   alert(monster.run();)        // 没有弹出任何东西,只是创建了一个对象,并没有属性和方法,当然是不能访问函数 createPeople 里面的方法了
   createPeople.call(monster,'妖怪','葫芦');        //使用call 方法——对象冒充
   createPeople.apply(monster,['妖怪','葫芦']);
   alert(monster.run());
   alert(monster.name);

   /* 虽然我们解决了基本模式的创建多个对象的浪费内存的问题和工厂模式出现的没有使用 new 关键字问题
   * 但是我们使用构造函数也并不是完全没有缺陷的,它仍然还存在着工厂模式出现的 浪费资源,占两个空间地址的问题
   * 下面举个例子,再说明一下工厂模式的缺陷
   */
   var monster1 = new createPeople('妖怪','葫芦');
   var monster2 = new createPeople('小妖','葫芦');
   alert(monster1.run()+"\n"+monster2.run());   // 弹出的是两个一样的句子
   alert(monster2.run == monster1.run);     // 弹出 false ,说明两个函数并不相等,跟上篇工厂函数存在的问题是一样的
                            // 因为两个对象实例的地址是不同的,说明两个对象会占用两个地址空间的内存,如果有很多个占用空间,会导致程序,运行缓慢
</script>

在上面的代码中,我们也看出并不是构造函数模式就可以完美的解决所有的问题,但是相比前两个来说如果创建的对象少这个方法还是比较实用,那么存在的这个问题我们要如何去解决呢,在开发中不可能就创建一个两个,而是成百上千个,在这种模式下肯定是不行的,所以我们就要用到下面的方法,创建对象的 Prototype 模式。