• 初涉JavaScript模式 (4) : 构造函数


    什么是构造函数?

    构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 特别的一个类可以有多个构造函数 可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载 ---引自百度百科

    在JavaScript中是没有类的,但是我们有构造函数(是不是很怪),很深的东西我也说不来,直接上代码:

    ```javascript
               //工厂模式
               function createCat(name){
                   var o = {};
                   o.name = name;
                   o.cry = function(){
                       console.log(this.name + " : " + "喵喵喵!");
                   };
                   return o;
               }
              var tom = createCat("tom");
              tom.cry();
              //构造函数模式
              function Mouse(name){
                  this.name = name;
                  this.cry = function(){
                      console.log(this.name + " : " + "吱吱吱!");
                  }
              }
              var jerry = new Mouse("jerry",5);
              jerry.cry();
    ```
    

    以上实例代码分别是工厂模式和构造函数模式,构造函数模式相比于工厂模式,存在一下几个不同之处:

    • 没有显式的创建对象
    • 直接将属性和方法赋给了this对象
    • 没有return语句

    实际上,调用构造函数会经历以下几个步骤:

    • 创建一个新对象
    • 将构造函数的作用域赋给新对象(因此this就指向了新对象)
    • 执行构造函数中的代码(给这个新对象添加方法和属性)
    • 返回这个新对象

    我们要注意以上是JS隐式执行的,我们也可以显式的来,上代码:

    ```javascript
               function Mouse(name){
                   var o = {};
                   var that = o;
                   that.name = name;
                   that.cry = function(){
                       console.log(that.name);
                   }
                   return that;
               }
              var jerry = new Mouse("jerry",5);     
              jerry.cry();
    ```
    

    在隐式的构造函数中,我们要注意一个问题,return是隐式返回this的,但是我们可以手动return ,可是这有可能会return我们意料之外的结果:

    ```javascript
               function Mouse(name){
                   this.name = name;
                   this.cry = function(){
                       console.log(this.name + " : " + "吱吱吱!");
                   }
                   return "WeiRan"
               }
               Mouse.prototype.a = {};
               var jerry = new Mouse("jerry",5);     
              jerry.cry(); // jerry : 吱吱吱! 
    ```
    

    以上代码,虽然我们手动返回的是字符串但是真正返回的还是this,其实JS会判断我们返回的是不是对象,数组,function 如果不是这还是会返回this(即便是undefined,null,空)

    对象识别

    虽然工厂模式解决了多个相似对象的问题,却没有解决对象识别的问题,但是构造函数模式却解决了这个问题,在构造函数模式中,每一个实例都有一个属性constructor,该属性指向他么的构造函数,可以这样来检测对象的类型

    ```javascript
       console.log(jerry.constructor == Mouse); //true
    ```
    

    但是这样做其实是不严谨的,可能会出现以下的问题:

    ```javascript
               //构造函数模式
               function Mouse(name){
                   this.name = name;
                   this.cry = function(){
                       console.log(this.name + " : " + "吱吱吱!");
                   }
                   return;
               }
               var jerry = new Mouse("jerry",5); 
              Mouse.prototype.constructor = {};    
              console.log(jerry.constructor);//Object {}
    ```
    

    这段代码说明,jerry的constructor其实指向的是Mouse的prototype的constructor,这样很不严谨,故我们可以采用instanceof来检测对象类型

    ```javascript
               //构造函数模式
               function Mouse(name){
                   this.name = name;
                   this.cry = function(){
                       console.log(this.name + " : " + "吱吱吱!");
                   }
                   return;
               }
               var jerry = new Mouse("jerry",5); 
              Mouse.prototype.constructor = {}; 
              console.log(jerry.constructor == Mouse);//false
              console.log(jerry instanceof Mouse); //true
    ```
    

    将构造函数当作函数

    构造函数与其他函数的唯一不同,就在于调用他们的方式不同。但是构造函数也是函数,故我们可以以普通函数的方式执行构造函数,任何函数也可以通过new来调用(慎用),下面我列举了几个调用方式:

    ```javascript
               //构造函数模式
               function Mouse(name){
                   this.name = name;
                   this.cry = function(){
                       console.log(this.name + " : " + "吱吱吱!");
                   }
               }
               //当作构造函数使用
               var m1 = new Mouse("m1");
              m1.cry(); //m1 : 吱吱吱! 
              //当作普通函数使用
              Mouse("m2");
              window.cry(); //m2 : 吱吱吱! 
              //在其他作用域调用
              var obj = {};
              Mouse.call(obj,"m3");
              obj.cry(); //m3 : 吱吱吱! 
    ```
    

    第一种是用最常见的调用构造函数的方式,第二种,所有的属性和方法都被添加到Global对象上去了(在浏览器中就是window),第三种,我们制定了作用域,所以obj就有了所有的属性和方法

    构造函数的问题

    构造函数虽然好用,但是他也有缺点,使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,即每个实例的方法都是不同的(虽然代码一样),上代码:

    ```javascript
               //构造函数模式
               function Mouse(name){
                   this.name = name;
                   this.cry = function(){
                       console.log(this.name + " : " + "吱吱吱!");
                   }
               }
               var m1 = new Mouse();
               var m2 = new Mouse();
              console.log(m1.cry == m2.cry); //false
    ```
    

    然而,创建两个完成相同功能的Function实例的确没有必要,而且有this对象在,根本没有必要在执行代码前就把函数绑定到特定的对象上去,以此我们可以用下面的代码来解决这个问题:

    ```javascript
               //构造函数模式
               function Mouse(name){
                   this.name = name;
                   this.cry = cry;
               }
               function cry(){
                   alert(this.name);
               }
    ```
    

    在上面的例子中我们把cry方法定义在了构造函数外部,这样大大避免了资源的浪费,我们创建的实例调用的都是同一个cry方法,但是新问题又来了,如果这种方法很多,我们就不得不在全局定义很多函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了,好在这些我们可以用原型模式来解决(下一篇,呵呵)

    后记 :

    关于这篇,我开始是想写的非常全,但是奈何经验不足,大体框架也是按照书上的逻辑,最大的收获就是真的用心去看书了。如果在文中发现错误,请指正,共同进步

    作者:未然丶
  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/ahjx777/p/3506460.html
Copyright © 2020-2023  润新知