1. 程式人生 > >關於對象、構造函數、原型、原型鏈、繼承

關於對象、構造函數、原型、原型鏈、繼承

mes 創建對象 light 表示 {} highlight col 面向 原型鏈

對象:

在傳統的面向過程的程序設計中,會造成函數或變量的冗余。而js中對象的目的是將所有的具有相同屬性或行為的代碼整合到一起,形成一個集合,這樣就會方便管理,例如:
var person1={
    name:"memphis",
    age:26,
    showMessage:function(){
        alert("name:"+this.name);
    }
};
person1.showMessage();//輸出name:memphis
以上的例子將name、age、showMessage放進person這個對象中,方便管理也減少命名困難。 1)、內存會給每個對象分配一個內存空間;
2)、函數也是一個對象 每一個對象都會占據一定的內存空間。

構造函數:

對象的產生方便了代碼的管理,但是又產生了一個問題,如果又定義了一個對象person2,如下:
var person2={
    name:"memphis",
    age:26,
    showMessage:function(){
        alert("name:"+this.name);
    }
};
這樣的話person2和person1就產生了代碼重復問題(person1和person2有同樣的屬性和行為);由此就引出了構造函數的概念。
function Person(name,age)={
    this.name=name;
    this.age=age;
    this.showMessage=function(){
       alert("name:"+this.name);
    };
}
var person1=new Person(tan,26);
var person2=new Person(song,16);
這樣通過構造函數我們就不用反復去重新定義屬性和行為,我們就創造了兩個對象person1和person2person1和person2也叫作構造函數Person的兩個實例。 構造函數:用來在創建對象時初始化對象。特點:構造函數名一般為大寫字母開頭;與new運算符一起使用來實例化對象。
function Person(){}         //Person構造函數  
var p=new Person();         //Person構造函數創建對象,也可叫做實例化

原型:

構造函數可以解決代碼管理和重復性的問題。但是,正如在 對象 中提到的函數也是對象,也會有一定的內存空間,屬性可以每個對象占據一個空間,但是方法也就是行為,他對每個對象來說動作是一樣的,只是可能傳的參數不一樣。因此要想一個方法來解決內存空間被過多的占用的問題。
擬解決方法1:函數的定義轉移到構造函數外,例如:
function Person(name,age)={
    this.name=name;
    this.age=age;
    this.showMessage=showMessage;
}
function showMessage(){
    alert("name:"+name);
}
這時構造函數中this.showMessage會指向showMessage這個全局變量,先在構造函數的內部去找showMessage這個變量,然後去外部找。 這個解決方法看似可以,但一個對象若有多個方法時,代碼的封裝性無法體現,而且全局的函數只是為一個對象服務,全局性體現的不明顯。 擬解決方法2:原型 每個函數在創建的時候都會默認的分配一個prototype屬性,構造函數也不例外。 那麽prototype屬性是什麽? => prototype是一個指針,它指向一個對象。指針就像是: 想要把一本書存在一間房子裏(行為),要完成這個行為,就要先建房子然後把書放進房子,下次要存一本新書,就還要先建房子再放另一本書,這就很麻煩了。 更好的解決辦法: 整個行為中,房子是一個確定的動作,不需要每次都重建,建一次房子把地址記下來,以後每一次有放書這個動作時只需要通過地址找到對應的房子就行了。 如上面的例子: showMessage就是建房子的動作,name是書,prototype屬性是地址。構造函數就是每放一本書就要建一個房子,而原型就是通過地址找房子。
//建房子
function Person(){
}
//房子裏有什麽並確定了指針的指向
Person.prototype={
    name:"memphis",
    age:"22",
    showMessage:function(){
       alert("name:"+this.name);
    }
};
var person1 = new Person();
person1這樣就有了指針,就能訪問指針指定的內存空間。 1)、person1中也可以有自己屬性,而且對於person1和原型Person中都有的屬性,優先考慮的是person1中的屬性。 2)、不能通過person1改變原型屬性值,實例person1只是獲取了一個指向原型的指針,並沒有改變原型的權利。(註意:對於包含引用類型的屬性——例如數組。有一些操作是允許通過地址去訪問內存的,例如push,這些操作就有可能改變原型屬性,這個改變會造成災難性的後果,因為所有引用這個原型的對象都會隨之改變。)

原型鏈:

沒有原型的對象為數不多,Object.prototype算一個,它不繼承任何屬性。其他原型對象都是普通對象,普通對象都具有原型。Object.prototype是祖宗,其他的構造函數都是它兒子或者孫子、重孫子。它的孫子的原型是他兒子,同樣也是它,因為他兒子是繼承它的,這樣一來,每個對象都繼承至少一個原型對象,這一系列鏈接的原型對象就是所謂的“原型鏈”。 每一個對象都有自己的原型對象,原型對象本身也是對象,原型對象也有自己的原型對象,這樣就形成了一個鏈式結構,叫做原型鏈。 上面說的都是同類型下的對象,person1和person2都是Person的實例。如果有Person和Man兩個引用類型。Person中的屬性和方法是有Man需要的,想直接從Person中所有的屬性和方法拿過來,這就是繼承。 作為一個繼承的引用類型,能獲取誰的屬性和方法,name在這個問題上就會有原型鏈的概念。當對象嘗試獲某個屬性時,該對象沒有,會嘗試從原型對象中去找,原型對象沒有,在從原型對象的原型去找,最後到達Object.prototype。
例如:
function Person(name,age){
this.pname=name;
this.page=age; 
}
Person.prototype={
showPMessage:function(){
alert("name:"+this.pname);
}
};
function Man(name,age){
    this.mname=name;
this.mage=age; 
}
// 這一句話表示原型的指針指向了Person
Man.prototype = new Person("memphis",22,"man");
//  給原型添加方法一定要放在替換原型的語句之後
Man.prototype.test="wo shi";
Man.prototype.showMMessage=function(){
alert("name:"+this.mname);
};
var song=new Man("song",1);
song.showMMessage();//顯示song
song.showPMessage();//顯示memphis

繼承

1. for-in繼承
function Person(){              //父類  
     this.name="水煮魚";  
     this.age=18;  
}  
function Son(){                 //子類  
}  
var p=new Person();  
var s=new Son();  
for(var k in p){  
    s[k]=p[k];  
}  
console.log(s.name);           //水煮魚  
console.log(s.age);            //18  
2. 原型繼承
function Human(){  
    this.name="香辣蝦";  
    this.age=21;  
}  
function Man(){  
}  
Man.prototype=new Human();  
var m=new Man();  
console.log(m.name);           //香辣蝦  
console.log(m.age);            //21  
3. 經典繼承
var animal={  
    name:"阿咪",  
    type:"貓科"  
};  
var a=Object.create(animal)    //ES5屬性  
console.log(a.name);           //阿咪  
console.log(a.type);           //貓科  
Object.create()是讓一個對象的原型繼承另外一個對象;所以雖然a.name和a.age是可以訪問成功的,但實際上a本身並沒有這些屬性,而是a的原型上有這些屬性。 如下圖所示: 技術分享

關於對象、構造函數、原型、原型鏈、繼承