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

  • 相关阅读:
    LeetCode15 3Sum
    LeetCode10 Regular Expression Matching
    LeetCode20 Valid Parentheses
    LeetCode21 Merge Two Sorted Lists
    LeetCode13 Roman to Integer
    LeetCode12 Integer to Roman
    LeetCode11 Container With Most Water
    LeetCode19 Remove Nth Node From End of List
    LeetCode14 Longest Common Prefix
    LeetCode9 Palindrome Number
  • 原文地址:https://www.cnblogs.com/QingFlye/p/4483842.html
Copyright © 2011-2022 走看看