1. 程式人生 > >JS面向物件(二)——成員屬性、靜態屬性、原型屬性與JS原型鏈

JS面向物件(二)——成員屬性、靜態屬性、原型屬性與JS原型鏈

前  言

上一篇部落格(https://blog.csdn.net/caseywei/article/details/86298732 )中,我們介紹了JS中的面向物件,並詳細的解釋了this的指向問題。本篇部落格,我們繼續來學習JS的面向物件。來深入理解一下JavaScript OOP中的成員屬性/方法、靜態屬性/方法、原型屬性/方法,並且一起來探討一下JS中的原型與原型鏈。

 

一、 成員屬性與成員方法

在建構函式中,通過this.屬性宣告。或者例項化出物件後,通過“物件.屬性”追加的。都屬於成員屬性、或成員方法;也叫例項屬性與例項方法

成員屬性/方法,是屬於例項化出的這個物件。通過"物件.屬性"呼叫

程式碼例項:

function Person(name){

this.name = name;//宣告成員屬性

this.say =function(){}//宣告成員方法

}

var zhangsan =new Person("張三");

zhangsan.age= 14;//追加成員屬性
alert(zhangsan.name);//呼叫成員屬性
zhangsan.say();//呼叫成員方法

 

二 、靜態屬性與靜態方法

通過"類名.屬性名","類名.方法名"宣告的變數,成為靜態屬性、靜態方法;也叫類屬性、類方法

類屬性/類方法,是屬於類的(屬於建構函式的),這類屬性或方法必須通過"類名.屬性"呼叫,而不同通過物件名呼叫。

程式碼例項:

function Person(name){

}

Person.sex= "男";//宣告類屬性
alert(Person.age);//呼叫類屬性
var zhangsan = new Person("張三");

alert(zhangsan.sex);//無法呼叫。類屬性只能用類名呼叫。

 

三 、私有屬性與私有方法

在建構函式中,通過var宣告的屬性,成為私有屬性。

私有屬性的作用域,僅在當前函式有效。對外不公開,即通過物件/類都無法呼叫到。

程式碼示例:

function Person(name){
    var sex = "男";

    alert(sex);//私有屬性只能在類內容使用。
}

alert(Person.sex);//無法呼叫。私有屬性只能在類內容使用。

var zhangsan =new Person("張三");

alert(zhangsan.sex);//無法呼叫。私有屬性只能在類內容使用。

 

四 、原型屬性與原型方法

寫在了建構函式的prototype上。當使用建構函式例項化物件事,該屬性方法會進入新物件的__proto__上。

程式碼示例:

function Person(){

}

Person.prototype.name4= "name4";//宣告原型屬性Person.prototype.say = function(){

}//宣告原型方法

var zhangsan =new Person();

alert(zhangsan.name4);//可以使用物件呼叫原型屬性
zhangsan.say();//可以使用物件呼叫原型方法

 

通過上述程式碼示例,我們可以發現:原型屬性和原型方法、成員屬性和成員方法,都可以使用物件名呼叫。那麼,成員屬性和原型屬性到底有什麼不同。我們先來看這樣的一幅圖:

 

看出點門道了嗎?成員屬性是直接宣告在物件自身上!!而原型屬性是宣告在物件的__proto__上!!!在我們使用“物件名.屬性名”訪問一個屬性時,會先訪問成員屬性,如果成員屬性中找不到,JS會沿著物件的原型鏈,繼續通過__proto__向上查詢,也就找到了原型屬性。 這就是我們可以使用“物件名.屬性名”訪問成員屬性和原型屬性的原因。

但是,說了這麼多,什麼是__proto__?什麼是prototype?什麼又是原型鏈?接下來,我們就講解一下JS面向物件中最重要的一環——原型與原型鏈。

 

五、 原型與原型鏈

1、__proto__ 與 prototype

要講解原型與原型鏈,首先,我們要了解兩個基本概念——__proto__和prototype。

①  prototype(函式的原型物件):函式才有prototype,而且所有函式必有prototype。prototype是一個物件,指向了當前建構函式的引用地址呢。

②  __proto__(物件的原型):物件才有__proto__,而且所有物件必有__proto__屬性(這裡的物件除了我們理解的狹義物件,也包括了函式、陣列等物件)。當用建構函式例項化(new)一個物件時,會將新物件的__proto__屬性,指上建構函式的prototype。

來看個案例:

function Person(){

}varzhangsan =new Person();

console.log(zhangsan.__proto__== Person.prototype);//true//【解釋】上例中,我們使用函式Person,new出了一個物件zhangsan。 那麼物件zhangsan的__proto__就等於函式Person的prototype。

2、原型鏈

上面我們介紹了物件的__proto__和函式的prototype。知道了物件的__proto__指向了函式的prototype。那麼,我們也說了,函式的prototype本身也是個物件,是物件肯定也有__proto__,那他的__proto__指向了誰? 順著這個問題,我們延著一個物件__proto__向上查詢,這條線路就是我們所說的原型鏈。

所以,要研究原型鏈的走向,其實就是研究各種型別物件的__proto__到底指向誰。還記得上篇部落格的“飛魚老師this五大準則”嗎? 這次,貼心的飛魚老師老師又為大家準備了“飛魚老師原型鏈四大法則”,一起來看看吧!

【飛魚老師原型鏈四大準則】

① 通過建構函式,new出的物件,新物件的__proto__指向建構函式的prototype

② 所有函式的__proto__指上Function()的prototype

③ 非建構函式new出的物件( {}  new Object()物件的prototype)的__proto__指向Object的prototype

④Object的prototype的__proto__指向null

字不如表,表不如圖。我們一起以一段程式碼為例,探討一下原型鏈。

程式碼:

function Person(){

}

varzhangsan =new Person();

 

就是這樣一個簡單的類new出物件,我們來探討一下原型鏈吧~上圖!!!

原型鏈圖(飛魚老師親情手繪,親,點個讚唄!):

 

六 、成員屬性與原型方法

說了這麼多,我們應該能夠理解原型與原型鏈,也深刻的理解了原型屬性、原型方法。那麼問題來了,既然成員屬性/方法和原型屬性/方法,都能通過物件名訪問。我們到底用那種比較好呢?

習慣上,我們會將屬性寫為成員屬性,而方法寫為原型方法

原因如下:

① 例項化出物件後,所有屬性直接在物件上,所有方法都在__proto__上,非常直觀清晰。

② 方法寫到prototype上,要更加節省記憶體;

③ 使用for in迴圈時,會將物件以及物件原型鏈上的所有屬性和方法打印出來,而方法往往是不需要展示的。 將方法寫到__proto__上,可以使用hasOwnProperty將原型上的方法過濾掉、不顯示。

④ 官方都這麼寫。

 

七 、prototype擴充套件內建函式

那原型還有什麼作用呢?還有一個最常用的,就是我們使用prototype擴充套件內建函式的方法。可以直接使用內建函式的物件,呼叫我們擴充套件的方法;

比如,為Array類新增一個find(val)方法,當一個Array物件呼叫該方法的時候,如果能找到val值,則返回其下標,否則返回-1。

Array.prototype.find =function(val){
//在Array類的原型上新增擴充套件方法

}

var arr =new Array(1,2,3,4,5);

alert(arr.find(1));//直接使用Array類的物件,也就是陣列,就可以呼叫這個方法

 

好了,今天的課程就先到這裡吧?我們學習了JS中的成員屬性、靜態屬性、原型屬性、私有屬性等各種學習。 也學習了JS面向物件中非常重要的一個環節——原型與原型鏈。你都學會了嗎? 如果有問題歡迎大家評論留言哦~~我們下次課再見吧!