js 面向對象總結

面向對象的程序設計(Object-Oriented OO)

最近感受,不知道該學點什麼,總是覺的本身什麼都不會,又感受是會點什麼,說是也知道面向對象,可是讓系統的說一下這裏面的東西,感受連不上線,成不了太系統的瞭解,因此就看了一下這的知識點,當本身的搬運工,僞裝是發了一篇文章,等本身查看方便;bash

建立對象

1. 工廠模式:用函數來封裝,以特定接口建立對象的細節

  1. 解決了建立多個類似對象的問題,
  2. 多用於建立多個含有相同屬性,和方法的對象,避免代碼的重複編寫;
  3. 沒有解決對象識別的問題(即怎麼知道一個對象的類型)(它的 instanceof 只能是Object)
function creatPerson(name,age,job) {
        var o = new Object();
        o.name= name;
        o.age= age;
        o.job= job;
        o.sayName = function(){
            alert(this.name);
        };
        return o;
    }
    var p1 = creatPerson("hh",23,"worker");
    var p2 = creatPerson("xx",26,"worker1");
    p1.__proto__===p2.__proto__===Object.prototype;

    對象的constructor 屬性最先是用來描述隊形類型的,檢測對象類型仍是 instanceof 更可靠
    工廠模式建立的對象,constructor只有Object,這樣的實例沒有特定的類型;

複製代碼

2. 構造函數模式:

  1. 解決對象識別的問題(即怎麼知道一個對象的類型)
  2. 缺點:每一個方法都在每一個實例上從新建立了一次,下面栗子中p1.sayName!=p2.sayName
  3. 解決方式:提出構造函數,在全局寫一個函數申明;(這種解決方式的缺點:全局函數只是局部調用,方法過多就得建立多個全局函數,沒什麼封裝性可言);
function Person(name,age,job){
        this.age = age;
        this.name = name;
        this.job = job;
        this.sayName = function(){
            alert(this.name)
        }
        //this.sayName = sayName;   //解決方式
    }
    var p1 = new Person("hh",23,"worker");
    var p2 = new Person("xx",26,"worker1");
        
        //function sayName(){alert(this.name)}  //解決方式


    new的執行:
        {
            var obj ={};
            obj.__proto__ = Person.prototype;
            Person.call(obj);
            return obj
        }
    p1 instanceof Person //true;
    p2 instanceof Person //true;
    p1 instanceof Object //true;
    p2 instanceof Object //true;
    這樣是得p1和p2實例有了特定的類型, Person;

複製代碼

3. 原型模式

  1. 優勢:他省略了構造函數初始化參數這個環節,原型中全部屬性都被不少實例共享,共享對函數很是合適,基本屬性也還行 經過在實例上添加同名屬性,可隱藏原型中的對應屬性值;app

  2. 缺點: 他的共享屬性,對於包含引用類型值的屬性 若是實例從新賦值沒什麼影響,和基本類型同樣,若是是操做修改 就有些問題了,會使得全部實例獲取到的該屬性都被修改, 因此也不單獨使用函數

    function Person(){}
        Person.prototype={
            constructor:Person,
            name:"ss",
            friends:["s1","s2"],
            sayName:function(){alert(this.name)}
        }
        var p1= new Person();
        var p2= new Person();
        p1.name = "p1"
        console.log(p1.name) //p1
        console.log(p2.name) //ss
        p1.friends.push("s3");
        console.log(p1.friends) //["s1","s2","s3"]
        console.log(p2.friends) //["s1","s2","s3"]
    複製代碼
  3. 用法:ui

    1. 通常用法:
      function Person(){}
          Person.prototype.name="ceshi"
          Person.prototype.age =12;
          Person.prototype.sayName = function(){
              alert(this.name)
          }
          //這樣就是實現了代碼的共享
      
      複製代碼
    2. 簡單寫法
      更簡單的寫法:
              Person.prototype={
                  //constructor:Person,
                  name:"test",
                  age:12,
                  sayName:function(){alert(this.name)}
              }
          var friend = new Person();
          friend instanceof Object //true
          friend instanceof Person //true
          friend.constructor==Person //false
          friend.constructor==Object //true
      
          這種簡單的寫法constructor 屬性就不在指向Person,而是指向Object構造函數;
          此時能夠添加一個屬性constructor( 如上面註釋):可是此時的constructor 變成了可枚舉的屬性,原生是不可枚舉的,能夠考慮用Object.defineProperty()
      
      複製代碼
    3. 原型動態:
      var p1 = new Person();
          <!-- 1 -->
              Person.prototype.hh="ss";
              p1.hh//ss 是能夠先建立實例在改邊原型在訪問的;
              
          <!-- 2 -->
              Person.prototype={
                  name:"ss"
              }
              p1.__proto__!=Person.prototype;
              p1.name // undefined 
      
      複製代碼
    4. 原生對象的原型:
      1. 能夠給原生引用類型(Object、Array、String。。。)添加修改方法
        String.prototype.strarWith=function(tesx){return this.indexOf(text)==0}

4. 組合使用構造函數模式和原型模式:(定義引用類型的一種默認模式)

  1. 構造函數模式用於定義實例屬性; 每一個屬性在每一個實例上都從新建立了一次;即便引用類型的修改也不會影響其餘實例
  2. 原型模式用於定義方法和共享屬性;
function Person(age,name){
        this.name = name;
        this.age = age;
        this.friends=[1,2,3]
    }
    Person.prototype={
        constructor:Person,
        sayName:function(){
            alert(this.name)
        }
    }
    var p1 = new Person("ss",12);
    var p2 = new Person("ss3",123);
    p1.friends.push(2);
    console.log(p1.friends) // [1,2,3,2]
    console.log(p2.friends)// [1,2,3]
複製代碼

5. 動態原型模式:

  1. 原型和狗仔函數獨立開,感受和其餘語言的OO不同,動態原型就是把全部的信息都封裝在構造函數中;
  2. 在構造函數中檢查某個應該從在的方法是否有效,來以爲是否是初始化原型,其實就是初始化一次原型
function Person(name,age){
        this.name = name;
        this.age = age;
        if(typeof this.sayName !="function"){//sayName沒初始化 這裏對一個方法判斷就能夠,而後初始化全部的,不必都每一個方法都判斷

            Person.prototype.sayName=function(){alert(this.name)}
            Person.prototype.sayAge=function(){alert(this.age)};
            .....
        }
  ****注意****:此處不能使用對象字面量形式重寫原型, 由於這中寫法是先建立的實例,而後在修改的原型,要是用對象字面量重寫原型,會切斷現有實例和新原型之間的聯繫, 致使方法實例上無此方法;
    }

複製代碼

6. 寄生構造函數模式:

  1. 和工廠模式差很少,只是用了new 初始化實例;
  2. 它返回的對象與構造函數和構造函數的原型沒有任何關係;
function Person(name,age){
        var o = new Object();
        o.name=name;
        o.age=age;
        o.sayName=function(){
            alert(this.name)
        };
        return o;
    }
    var friends = new Person("xiaoming",12)
    friends.asyName()  // xiaoming

複製代碼

7. 穩妥構造函數模式:

穩妥對象: 沒有公共屬性,而且其方法中不引用this的對象;this

function Person(name,age){
        var o = new Object();
        o.sayName=function(){
            alert(name)
        };
        return o;
    }
    var friends = new Person("xiaoming",12)
    friends.asyName()  // xiaoming
複製代碼

繼承 :

  1. 繼承通常包括: 接口繼承:繼承方法和簽名; 實現繼承:繼承實際的方法;ECMAScript 只支持實現繼承spa

  2. js主要經過原型鏈實現繼承,原型鏈的構建是經過將一個類型的實例賦值給另外一個構造函數的原型實現的prototype

繼承方式

1. 原型鏈(不多單獨使用)
  1. 問題:操做引用類型的數據(從新賦值不影響,至關於子類添加隱藏父類),會被全部實例共享受
  2. 問題er: 建立子類時候不能向父類的構造函數傳遞參數;???
Son.prototype = new Father();
    
    //此時Son.constructor 被改寫爲了 Father;
    Son.prototype.constructor = Son;
    
    //給子類修改或者是添加方法的時候,要放在替換語句,改版子類原型語句以後, 
    //原型繼承時,不能使用字面量方式建立原型方法,這樣就從新寫了原型鏈了
    Son.prototype.getName=function(){alert(this.name)};

複製代碼
2. 構造函數綁定: call ,apply 繼承:(不多單獨使用)
  1. 問題: 父函數原型(prototype)中的方法,子類是不能夠見的
  2. 問題兔:方法屬性都是在構造函數中定義的,每一個實例和方法都從新建立一次,沒有複用之說z
function Son(){
        Father.call(this,arguments)
    }
複製代碼
3. 組合繼承:(經常使用繼承模式)
  1. 這樣可使得實例分別擁有各自的屬性(包括引用類型的,實例間互補影響),又可使用相同的方法;
  2. 缺陷: 不管什麼狀況下,都會調用兩次父類的構造函數;
function Father(){
        this.name ="ss";
        this.friends=[1,2,3,4]
    }
    function Son(){
        Father.call(this);
    }
    Son.prototype = new Father(); // Son 原型得到Father上的屬性,name和friends


    var son1 = new Son(); // 此時調用Son構造函數爲son1 實例上添加了屬性(name和friends), 這些屬性就屏蔽了原型中的同名屬性;
    // 調用兩次Father構造函數的結果就是有兩組屬性,一組在實例上,一組在原型上;

複製代碼
4. 原型式繼承:
  1. 在不必興師動衆建立構造函數,而是隻想讓一個對象與另外一個對象保持相似的狀況,可使用, 相似錢拷貝;
function object(o){
        function F(){};
        F.prototype = o;
        return new F();
    }
    // 和 Object.creat() 傳遞一個參數時候相同
複製代碼
5. 寄生式繼承:
  1. 繼承origin 的屬性和方法;
  2. 同時還有本身的方法;
function creat(origin){
        var clone = object(origin); // 能夠是任何返回新對象的函數
        clone.sayName(){alert("name")}; //這裏的函數每次都建立,不存在複用一說,
        return clone;
    }
複製代碼
6. 寄生組合式:(理想的繼承實現方式)
  1. 解決組合繼承中的缺陷,生成兩組屬性,只在實例上生成原型;
  2. 經過構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法(就是給子類原型,指定一個父類的副本便可)
function inherit(son,father){

        var prototype = object(father.prototype); 
            // 上句話,建立父類原型的副本,prototype.__proto__ = Father.prototype;
            // prototype 繼承constructor prototype.constructor 取的是原型鏈上,原型的Father.prototype.constructor, 爲 Father();即:prototype.constructor == prototype.__proto__.constructor  // true
            // prototype.hasOwnPrototyoe("constructor") //false
        

        prototype.constructor = son; // 彌補重寫原型形成的默認屬性的修改;
            //此時是給prototype 添加了constructor 屬性,賦值爲son, 屏蔽了原型上的constructor屬性
            // prototype.hasOwnPrototype("constructor") // true
            // prototype.constructor = son;
            // prototype.__proto__.constructor = father
        son.prototype  = prototype;
            // 給子類原型賦值爲父類原型的副本;
    }

    //使用:
    function Father(){
        this.name="11";
        this.age=12;
    }
    Father.prototype.sayName=function(){
        alert(this.name);
    }
    function Son(){
        Father.call(this);
        this.age=23;
    }
    inherit(Son,Father);
    Son.prototype.sayAge=function(){
        alert(this.age)
    }

複製代碼
相關文章
相關標籤/搜索