JavaScript prototype 原型

admin發表於2018-10-05

JavaScript是物件導向的語言,那麼繼承自然是其重要特徵之一。

與標準面嚮物件語言不同,JavaScript繼承主要通過prototype原型實現。

ES2015新增class類,繼承方式從表面上更加趨近於標準面嚮物件語言,但實質上還是利用原型實現。

關於class樣式類可以參閱JavaScript class類一章節。

一.基本概念:

每一個函式都具有prototype屬性。

此屬性指向一個物件,我們稱此物件為原型物件。

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160401qbzbc8sqe3vvv3s6.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

由列印效果可以看到,函式func具有prototype屬性,此屬性指向一個物件(原型物件)。

為了滿足實際需求,原型物件可能需要自定義,程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function func(){
  this.webName="螞蟻部落"
}
func.prototype.address="青島市南區";
func.prototype.age=6;
console.log(func.prototype);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160425eggggot5o0e5bggj.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

可以看到為原型物件新增了兩個屬性。

將函式作為建構函式建立的物件例項會繼承此原型物件中的成員。

程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function func(webName){
  this.webName=webName;
}
func.prototype.address="青島市南區";
func.prototype.age=6;
let one=new func("螞蟻部落一");
let two=new func("螞蟻部落二");
console.log(one.webName);
console.log(one.address);
console.log(one.age);
console.log("-------------");
console.log(two.webName);
console.log(two.address);
console.log(two.age);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160459w2bl0g49b49q7262.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

由上圖可見,物件例項one與tow都繼承了原型物件中的成員。

前面已經明確了物件例項可以繼承原型物件成員,再來分析一下具體是如何繼承原型物件成員的。

圖示如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160514kglokkpg189gozr9.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

圖示分析如下:

(1).func函式的prototype屬性指向原型物件。

(2).prototype原型物件具有兩個自定義屬性address與age。

(3).one與two是func建構函式建立的兩個物件例項。

(4).物件例項有內部屬性[[Prototype]],它指向函式的原型物件,__proto__屬性可以訪問此內部屬性。

總結如下:

(1).建構函式內定義的屬性/方法,物件例項獨立所有,也就是每一個例項都切切實實有一份。

(2).被繼承的原型物件中屬性/方法是共享的。

看如下程式碼例項:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function func(webName){
  this.webName=webName;
}
func.prototype.address="青島市南區";
func.prototype.age=6;
let one=new func("螞蟻部落一");
let two=new func("螞蟻部落二");
console.log(one.age);
console.log("-------------");
console.log(two.age);
// 修改原型物件age屬性值為8
func.prototype.age=8;
console.log("-------------");
//兩個例項物件age屬性值改變為8
console.log(one.age);
console.log("-------------");
console.log(two.age);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160549rzreztuhoa866mal.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

正式由於原型物件是共享的,所以改變原型物件的age屬性值,兩個例項物件的age屬性值也跟著改變。

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function func(webName){
  this.webName=webName;
}
func.prototype.address="青島市南區";
func.prototype.age=6;
let one=new func("螞蟻部落一");
let two=new func("螞蟻部落二");

// 重置原型物件
func.prototype={
  url:"http://www.softwhy.com"
}
// 列印結果
console.log(one.age);
console.log(one.url);
console.log("-------------");
console.log(two.age);
console.log(two.url);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/05/160617dn652y9bby5n5bnu.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

上面程式碼是重置原型物件,也就是說最初的原型物件被替換。

但是為什麼age屬性依然存在,反而新原型物件的url屬性卻沒有找到呢。這是因為在重置原型物件之前,物件例項one與two已經被建立,__proto__指向原來的原型物件,現在重置原型物件實質就是將prototype指向一個新的物件,但是並沒有人撥動__proto__指標指向這個新的原型物件,所以依然指向原來的原型物件。

相關文章