zoukankan      html  css  js  c++  java
  • JavaScript面向对象(收集整理)

    (1)封装

      首先理解构造函数:所谓"构造函数",其实就是一个普通函数,但是内部使用了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); // 黄色

    其中cat1cat2会自动含有一个constructor属性,指向它们的构造函数。

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

    构造函数存在一个弊端:浪费内存,比如:

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

    其中前两个属性name,color是实例独自拥有的,cat1和cat2的name,color是不同的,而type,eat()确是可以共同拥有的,所有可以把共有的方法,属性定义在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.eat == cat2.eat); //true

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

    (2)继承

      function Animal(){
        this.species = "动物";
      }
    
      function Cat(name,color){
        this.name = name;
        this.color = color;
      }

    (Cat要继承Animal)

    1.构造函数绑定   

     

    使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行

      function Cat(name,color){
       Animal.apply(this, arguments);
        this.name = name;
        this.color = color;
      }
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物

    2. prototype模式

    将Cat(子)的prototype指向Animal(父)的实例,那么Cat所创建出来的实例就都继承了Animal

      Cat.prototype = new Animal();
      Cat.prototype.constructor = Cat;
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物

    其中第二行代码 Cat.prototype.constructor = Cat; 是因为如果原本constructor本来是指向自己的构造函数cat()的,但是这里被赋值给了new Animal(),换了个新构造函数,所以为了不造成继承链的紊乱,必须手动修改回来

    3. 直接继承prototype

    Cat不变的属性或方法可以直接写入Animal.prototype,然后Cat.prototype = Animal.prototype直接继承

      function Animal(){ }
      Animal.prototype.species = "动物";
    
      Cat.prototype = Animal.prototype;
      Cat.prototype.constructor = Cat;
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物

    这样的好处是,对比方法2中,不用执行和建立Animal()的实例,也省了内存;

    这样的缺点是,由于Cat.prototype = Animal.prototype,Cat.prototype和Animal.prototype现在指向了同一个对象,实际上把Animal.prototype对象的constructor属性也改掉了!

    4.利用空对象作为中介

    用一个F空对象,几乎不占内存,作为中间桥梁,修改Cat的prototype对象,就不会影响到Animal的prototype对象。

      var F = function(){};
      F.prototype = Animal.prototype;
      Cat.prototype = new F();
      Cat.prototype.constructor = Cat;

    可以封装成一个函数:

    function extend(Child,Parent){
         var F = function (){};
         F.prototype = Parent.prototype;
         Child.prototype = new F();
         Child.prototype.construction = Child;
         Child.uber = Parent.prototype;  //假设一个Child不变的属性uber      
    }
    
    extend(Cat,Animal);
    var cat1 = new Cat("大毛","黄色");
    alert(cat1.species); // 动物

    5.拷贝继承

    把父对象的所有属性和方法,拷贝进子对象

    function Animal(){}
    Animal.prototype.species = "动物";
    
    function extend2(Child, Parent) {
      var p = Parent.prototype;
      var c = Child.prototype;
      for (var i in p) {
        c[i] = p[i];
      }
      c.uber = p;
    }
    
    extend2(Cat, Animal);
    var cat1 = new Cat("大毛","黄色");
    alert(cat1.species); // 动物

    (3)非构造函数继承

    1.object()方法

      var Chinese = {
        nation:'中国'
      };
    
      var Doctor ={
        career:'医生'
      }

    如何使Doctor对象继承Chinese对象?

      function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
      }
      
    var Doctor = object(Chinese);   Doctor.career = '医生';   alert(Doctor.nation); //中国

    2.浅拷贝:

    只是拷贝基本类型的数据

      function extendCopy(p) {
        var c = {};
        for (var i in p) { 
          c[i] = p[i];
        }
        c.uber = p;
        return c;
      }
    
      var Doctor = extendCopy(Chinese);
      Doctor.career = '医生';
      alert(Doctor.nation); // 中国
     Chinese.birthPlaces = ['北京','上海','香港'];

     var Doctor = extendCopy(Chinese);
     Doctor.birthPlaces.push('厦门');

      alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门

      alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门

    下面的代码显露出钱浅拷贝的缺点,就是假如父对象的某个属性也是数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。

    3.深拷贝

    jQuery库使用的就是这种继承方法。

      function deepCopy(p, c) {
        var c = c || {};
        for (var i in p) {
          if (typeof p[i] === 'object') {
            c[i] = (p[i].constructor === Array) ? [] : {};
            deepCopy(p[i], c[i]);
          } else {
             c[i] = p[i];
          }
        }
        return c;
      }
    
      var Doctor = deepCopy(Chinese);
    
      Chinese.birthPlaces = ['北京','上海','香港'];
      Doctor.birthPlaces.push('厦门');
    
      alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
      alert(Chinese.birthPlaces); //北京, 上海, 香港

    以上内容均参考自:

    http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

    http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

    http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

  • 相关阅读:
    图论-最短路
    windows对拍及其应用
    RMQ与st表
    树状数组
    二分和三分题
    [转载]图论500题
    浏览器请求背后的网络数据传输过程
    百度ocr文字识别接口使用
    Mysql启动报错解决方案:Failed to open log (file './mysql-bin.000901', errno 2)
    Mac环境下nginx https配置
  • 原文地址:https://www.cnblogs.com/zgx123/p/7392548.html
Copyright © 2011-2022 走看看