1. 程式人生 > >JavaScript面向對象(收集整理)

JavaScript面向對象(收集整理)

span 但是 cti 運算 www n) 兩個 eat 擁有

(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

JavaScript面向對象(收集整理)