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

JavaScript面向對象(二)——成員屬性、靜態屬性、原型屬性與JS原型鏈

清晰 property origin .com 所有 擴展方法 進入 https lock

前 言

上一篇博客(https://www.cnblogs.com/qdjianghao/p/10177360.html )中,我們介紹了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();//調用成員方法

二 靜態屬性與靜態方法

通過"類名.屬性名","類名.方法名"聲明的變量,成為靜態屬性、靜態方法;也叫類屬性、類方法

類屬性/類方法,是屬於類的(屬於構造函數的),這類屬性或方法必須通過"類名.屬性"調用,而不同通過對象名調用。

代碼實例:

functionPerson(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__上。

代碼示例:

functionPerson(){

}

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

}//聲明原型方法

var zhangsan =new Person();

alert(zhangsan.name);//可以使用對象調用原型屬性
zhangsan.say();//可以使用對象調用原型方法

通過上述代碼示例,我們可以發現:原型屬性和原型方法、成員屬性和成員方法,都可以使用對象名調用。那麽,成員屬性和原型屬性到底有什麽不同。我們先來看這樣的一幅圖:

技術分享圖片

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

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

五 原型與原型鏈

1__proto__ 與 prototype

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

① prototype(函數的原型對象):函數才有prototype,而且所有函數必有prototype。prototype是一個對象,指向了當前構造函數的引用地址呢。

② __proto__(對象的原型):對象才有__proto__,而且所有對象必有__proto__屬性(這裏的對象除了我們理解的狹義對象,也包括了函數、數組等對象)。當用構造函數實例化(new)一個對象時,會將新對象的__proto__屬性,指上構造函數的prototype。

來看個案例:

functionPerson(){

}varzhangsan =newPerson();

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

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

代碼:

functionPerson(){

}

varzhangsan =newPerson();

就是這樣一個簡單的類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面向對象中非常重要的一個環節——原型與原型鏈。你都學會了嗎? 如果有問題歡迎大家評論留言哦~~我們下次課再見吧!

JavaScript面向對象(二)——成員屬性、靜態屬性、原型屬性與JS原型鏈