zoukankan      html  css  js  c++  java
  • 初涉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方法,但是新问题又来了,如果这种方法很多,我们就不得不在全局定义很多函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了,好在这些我们可以用原型模式来解决(下一篇,呵呵)

    后记 :

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

    作者:未然丶
  • 相关阅读:
    自定义input标签输入框
    sys.argv 启动时可以传入变量
    falcon 监控
    wrk 压测工具
    mysql UPDATE和REPLACE
    tesseract识别图片中文字
    centos 查看日志 & 查找文件、目录、内容 & centos查看磁盘使用情况
    压力测试
    tensorflow + scikit-learn
    Pycharm快捷键配置
  • 原文地址:https://www.cnblogs.com/ahjx777/p/3506460.html
Copyright © 2011-2022 走看看