1. 程式人生 > >JScript建立物件與繼承方式--紅寶書第六章

JScript建立物件與繼承方式--紅寶書第六章

一. 建立物件
1. 工廠模式
解決了建立多個類似物件的問題,但是通過工廠模式建立的物件無法識別是一個什麼樣的物件型別

function objFactory(name,age){
       var  o = new Object();  //適合於原生建構函式建立例項
       o.name=name;
       o.age=age;
       o.getAction=function(){console.log(this.name)};
       return o;
}
var person1=objFactory("jasson",10);
var person2=objFactory("jim",8);

2. 建構函式模式

//自定義一類特性的型別
function  Animal(name,age){
        this,name=name;
        this.age=age;
        this.getAction=function(){
               console.log(this.name);
        }
}
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

建構函式可以用於建立特定型別的物件。除了Object、Array原生建構函式,還可以自定義建構函式。自定義建構函式可以用於將它的例項標識為一種特定的型別,如Dog、Cat。
問題:每個方法都會在每個例項上建立一遍。在ECMAscript中函式是物件,每定義一個函式相當於例項化了一個Function物件
即 this.getAction=function(){……}
邏輯上等價於 this.getAction=new Function(){……}
所以不同例項上的同名函式是不相等的如下:

console.log(dog.getAction==cat.getAction);
VM649:1 false

但是,建立兩個可以完成同樣任務的Function例項是沒有必要的。大可將函式移到建構函式體外去,如下:

function  Animal(name,age){
        this,name=name;
        this.age=age;
 //此時this.getAction屬性設為等於全域性函式getAction,而getAction是一個指向函式的指標,因此解決了兩個函式做同一件事的問題。
        this.getAction=getAction; 
}
function getAction(){
               console.log(this.name);
        }
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

問題:如果物件需要定義很多方法,那麼會存在很多全域性函式,那麼自定義引用型別的封裝性無法得以體現了。這一點可以用原型模式解決。

3. 原型模式
可以讓所有物件例項共享它所包含的屬性和方法。

function  Animal(){
}
Animal.prototype.name="dog";
Animal.prototype.age=2;
**Animal.prototype.getAction=function(){
               console.log(this.name);
        }**
var dog = new Animal();
var  cat=new Animal();

4. 組合構造模式
建構函式模式+原型模式的方法
使例項可以擁有各自的例項屬性,而原型模式可以用於定義共同的屬性和方法。

function  Animal(name,age){
        this,name=name;
        this.age=age;
        }
        *Animal.prototype.getAction=function(){
               console.log(this.name);
        }
        var dog = new Animal("DOG",3);
        var  cat=new Animal("cat",2);

5. 動態原型模式
將所有資訊封裝在建構函式中,在必要情況下初始化原型。

function  Animal(name,age){
        this,name=name;
        this.age=age;
       
        **if(typeof this.getAction != "function"){
             Animal.prototype.getAction=function(){
               console.log(this.name);
           }
      }**
 }
        var dog = new Animal("DOG",3);
        var  cat=new Animal("cat",2);
        dog.getAction();

6. 寄生建構函式

function  Animal(name,age){     //寄生的宿主建構函式
        var o= new Object();   //寄生者
       o.name=name;
       o.age=age;
       o.getAction=function(){console.log(this.name)};
       return o;
}
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

二. 繼承

例項、建構函式、例項的關係
在這裡插入圖片描述

1. 原型鏈繼承
定義一個父類Animal

function Animal(){
      this.name="animal";
}
Animal.prototype.getName=function(){return this.name};
//定義子類
function Dog(){
     this.age=2;
}
Dog.prototype = new Animal(); //原型繼承
var instance = new Dog();   //子類的例項
alert(instance.getName());    //輸出為animal,繼承了父類的方法
console.log(instance.constructor==Animal);    //VM2342:1 true, 

使用原型繼承後,instance.constructor會指向父類Animal,因為Dog.prototype指向了Animal的原型,所以constructor指向了animal。
問題:1.建立子型別的例項時,無法在不影響其他物件例項的情況下向超型別的建構函式傳遞引數。2.無法實現多繼承
特點:1.簡單易於實現

2. 借用建構函式繼承

function Animal(){
      this.names=["animal"];
}
function Dog(){
   **Animal.call(this);**     // 借調了父類的建構函式
}
 //每當建立一個例項時,都會利用call方法借調animal的建構函式,在例項物件上會執行animal建構函式中定義的初始化程式碼,因此Dog的每個例項上都會有names屬性的副本。所以instance1和instance1的names打印出來結果會不一樣
var instance1 = new Dog();  
instance1.names.push("dog");
console.log(instance1.names);   //(2) ["animal", "dog"]

var instance2 = new Dog();
console.log(instance2.names);  //VM2406:12 ["animal"]

借用建構函式的另一點----子型別建構函式可以向父類建構函式傳遞引數

function Animal(name){
      this.names=name;
}
function Dog(){
   **Animal.call(this,"dog");**  // 借調了父類的建構函式同時傳遞引數
   this.age=2;
}
var instance = new Dog();
console.log(instance.name);  //VM2406:12  "dog"

問題:1.函式無法複用。因此需要用組合繼承 。 2.只能繼承父類的例項和方法,無法繼承原型屬性和方法
特點:1.可以實現多繼承。2.建立子類例項時可以向父類傳參

3. 組合繼承
借用建構函式繼承+原型繼承

function Animal(name){
      this.name=name;
      this.colors=["red","blue","green"];
}
Animal.prototype.getName=function(){
      console.log(this.name);
}
function Dog(name,age){
     Animal.call(this,name);    //**第二次呼叫超類animal的建構函式**
     this.age=age;
}
Dog.prototype=new Animal();   //**第一次呼叫超類animal建構函式**
Dog.prototype.constructor=Dog;  //使得dog.prototype.constructor仍然指向dog
Dog.prototype.getAge=function(){console.log(this.age);};

var instance1 = new Dog("JIM",2);
instance1.colors.push("yellow");  
console.log(instance1.colors);  //(4) ["red", "blue", "green", "yellow"]
instance1.getName();  // JIM
instance1.getAge();  //2

var instance2 = new Dog("tom",11);
console.log(instance2.colors);  //VM2911: (3) ["red", "blue", "green"]
instance2.getName();  // tom
instance2.getAge();  //11

如果註釋掉Dog.prototype.constructor=Dog; 這句,那麼
console.log(Dog.prototype.constructorDog);.//false
console.log(Dog.prototype.constructor
Animal); //true

問題:1.無論什麼情況下,都會呼叫兩次超類的建構函式,導致有兩組超類中的屬性name和colors,一組在例項上,一組在Dog原型中。------解決方案為寄生組合式繼承
特點:1.可以繼承父類的屬性方法,也可以繼承原型屬性方法。2.可以傳參 。 3.函式可以複用

4. 寄生式繼承
利用createAnimal()函式封裝繼承過程,類似於工廠模式和寄生建構函式的思維。

function createAnimal(original){
      var  o=new Object(original);   //original初始化的引數
      o.getName=function(){console.log(original.name);};
      return o;
}
var animal={
    name: "JIm",
    colors: ["red","bluer"]
};
var obj = createAnimal(animal);   //利用函式封裝繼承過程,返回的結果是個物件
obj.getName();  //JIM

5. 寄生組合式繼承
寄生式繼承+組合式繼承
通過借用建構函式繼承屬性,利用原型鏈的混成形式繼承方法。

//借用建構函式方法
function Animal(name){
      this.name=name;
      this.colors=["red","blue","green"];
}
Animal.prototype.getName=function(){
      console.log(this.name);
}
function Dog(name,age){
     Animal.call(this,name);    //**第二次呼叫超類animal的建構函式**
     this.age=age;
}
Dog.prototype.getAge=function(){
        console.log(this.age);
  };
//寄生組合繼承的重點!!!!!
function inheritPrototype(dog, animal){
      var o = new Object(animal.prototype);
      o.constructor = dog;
      dog.prototype = o;
}
inheritPrototype(Dog,Animal);

var instance1 = new Dog("JIM",2);
console.log(instance1.colors);  // ["red", "blue", "green"]
instance1.getName();  // JIM
instance1.getAge();  //2

重點部分!!!
**function inheritPrototype(dog, animal){

var o = new Object(animal.prototype);
o.constructor = dog;
dog.prototype = o;
}
inheritPrototype(Dog,Animal);**
問題:1. 實現較為複雜
特點: 1.整體實現較為理想