zoukankan      html  css  js  c++  java
  • ife task0003学习笔记(四):JavaScript构造函数

    JavaScript创建对象主要是3种方法:工厂模式、构造函数模式、原型模式。其实对于构造函数的概念,我们并不陌生。在之前学习c++语言的时候,也有提到过构造函数的概念。除了创建对象,构造函数(constructor) 可以自动为创建的新对象设置原型对象(prototype object) ,原型对象存放于Constructor Function.prototype 属性中。

    1.对象封装

    如果一个对象具有属性"(property)和"方法"(method),我们希望封装成一个对象,甚至要从原型对象生成一个实例对象,那么就诞生了构造函数的思想。首先来看原始的实现方式:

    var Cat = {
        name : '',
        color : ''
      }
    
    

    现在可以根据这个原型对象的规格(schema,生成两个实例:

    
    var cat1 = {}; // 创建一个空对象
        cat1.name = "大毛"; // 按照原型对象的属性赋值
        cat1.color = "黄色";
      var cat2 = {};
        cat2.name = "二毛";
        cat2.color = "黑色";
    

    为了解决代码重复赘余问题,上述代码可以改进如下:

     function Cat(name,color){
        return {
          name:name,
          color:color
        }
      }
    

    接下来是生成实例对象,即调用函数:

     var cat1 = Cat("大毛","黄色");
      var cat2 = Cat("二毛","黑色");
    

    问题:at1和cat2之间没有内在的联系,不能反映出它们是同一个原型对象的实例

    2.构造函数

    为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
    所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

    function Cat(name,color){
        this.name=name;
        this.color=color;
      }
    

    生成实例对象:

        var cat1 = new Cat("大毛","黄色");
      var cat2 = new Cat("二毛","黑色");
      alert(cat1.name); // 大毛
      alert(cat1.color); // 黄色
    

    这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。

       alert(cat1.constructor == Cat); //true
      alert(cat2.constructor == Cat); //true
    

    Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。

      alert(cat1 instanceof Cat); //true
      alert(cat2 instanceof Cat); //true
    

    构造函数方法很好用,但是存在一个浪费内存的问题。

    3.构造函数的深入理解

    // 构造函数
    function Foo(y) {
      // 构造函数将会以特定模式创建对象:被创建的对象都会有"y"属性
      this.y = y;
    }
     
    // "Foo.prototype"存放了新建对象的原型引用
    // 所以我们可以将之用于定义继承和共享属性或方法
    // 所以,和上例一样,我们有了如下代码:
     
    // 继承属性"x"
    Foo.prototype.x = 10;
     
    // 继承方法"calculate"
    Foo.prototype.calculate = function (z) {
      return this.x + this.y + z;
    };
     
    // 使用foo模式创建 "b" and "c"
    var b = new Foo(20);
    var c = new Foo(30);
     
    // 调用继承的方法
    b.calculate(30); // 60
    c.calculate(40); // 80
     
    // 让我们看看是否使用了预期的属性
     
    console.log(
     
      b.__proto__ === Foo.prototype, // true
      c.__proto__ === Foo.prototype, // true
     
      // "Foo.prototype"自动创建了一个特殊的属性"constructor"
      // 指向a的构造函数本身
      // 实例"b"和"c"可以通过授权找到它并用以检测自己的构造函数
     
      b.constructor === Foo, // true
      c.constructor === Foo, // true
      Foo.prototype.constructor === Foo // true
     
      b.calculate === b.__proto__.calculate, // true
      b.__proto__.calculate === Foo.prototype.calculate // true
     
    );
    
    

    上述代码可以表示关系为:

    JavaScript 中的构造函数和其它语言中的构造函数是不同的。 通过 new 关键字方式调用的函数都被认为是构造函数。

    在构造函数内部 - 也就是被调用的函数内 - this 指向新创建的对象 Object。 这个新创建的对象的 prototype 被指向到构造函数的 prototype。

    如果被调用的函数没有显式的 return 表达式,则隐式的会返回 this 对象 - 也就是新创建的对象。

    
    function Foo() {
        this.bla = 1;
    }
    
    Foo.prototype.test = function() {
        console.log(this.bla);
    };
    
    var test = new Foo();
    

    上面代码把 Foo 作为构造函数调用,并设置新创建对象的 prototype 为 Foo.prototype。

    显式的 return 表达式将会影响返回结果,但仅限于返回的是一个对象。

    4.构造函数问题

    可能会浪费内存。那就是对于每一个实例对象,如果这些实例的某些属性和方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。能不能让一模一样的属性和方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的,Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

     function Cat(name,color){
        this.name = name;
        this.color = color;
      }
      Cat.prototype.type = "猫科动物";
      Cat.prototype.eat = function(){alert("吃老鼠")};
    

    生成实例:

      var cat1 = new Cat("大毛","黄色");
      var cat2 = new Cat("二毛","黑色");
      alert(cat1.type); // 猫科动物
      cat1.eat(); // 吃老鼠
    

    这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。

      alert(cat1.eat == cat2.eat); //true
    
    

    5. Prototype模式的验证方法

    1.isPrototypeOf()

    这个方法用来判断,某个proptotype对象和某个实例之间的关

      alert(Cat.prototype.isPrototypeOf(cat1)); //true
      alert(Cat.prototype.isPrototypeOf(cat2)); //true
    

    2.hasOwnProperty()

    每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。

    
     alert(cat1.hasOwnProperty("name")); // true
     alert(cat1.hasOwnProperty("type")); // false
    
    

    3.in

    in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。

      alert("name" in cat1); // true
      alert("type" in cat1); // true
    
    

    参考资料:
    阮一峰http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
    JavaScript探秘:构造函数 Constructorhttp://www.nowamagic.net/librarys/veda/detail/1642

  • 相关阅读:
    分布式版本控制系统Git的安装与使用
    利用GitLab自动同步软件仓库
    MakerDAO 代币解释:DAI, WETH, PETH, SIN, MKR(一)
    数组 Major^
    String 类 Major^
    深度优先排序(数字全排列) Major^
    喊数字小游戏 Major^
    java数据类型 Major^
    ArrayList类的使用方法 Major^
    深度优先搜索(迷宫救人最短路径) Major^
  • 原文地址:https://www.cnblogs.com/QingFlye/p/4483842.html
Copyright © 2011-2022 走看看