JavaScript中的對象原型是什么?怎么用?針對這些問題,今天小編總結(jié)了這篇文章,希望能幫助更多想解決這些問題的朋友找到更加簡單易行的辦法。
澧縣網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、自適應(yīng)網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護(hù)。創(chuàng)新互聯(lián)自2013年創(chuàng)立以來到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。介紹
javascript中一切皆對象,而每個對象都有一個原型(Object除外),這個原型,大概就像Java中的父類,所以,基本上你可以認(rèn)為原型就是這個對象的父對象,即每一個對象(Object除外)內(nèi)部都保存了它自己的父對象,這個父對象就是原型。一般創(chuàng)建的對象如果沒有特別指定原型,那么它的原型就是Object(這就很類似Java中所有的類默認(rèn)繼承自O(shè)bject類)。
JavaScript原型
JavaScript中的每個對象都有一個稱為[[Prototype]]的內(nèi)部屬性。我們可以通過創(chuàng)建一個新的空對象來演示這一點。
let x = {};
這是我們通常創(chuàng)建對象的方法,但是請注意,另一種實現(xiàn)方法是使用對象構(gòu)造函數(shù):
let x = new object()
包圍[[Prototype]]的雙方括號表示它是一個內(nèi)部屬性,不能在代碼中直接訪問。
要找到這個新創(chuàng)建對象的[[Prototype]],我們將使用getPrototypeOf()方法。
Object.getPrototypeOf(x);
輸出將由幾個內(nèi)置屬性和方法組成。
輸出:
{constructor: ?, __defineGetter__: ?, __defineSetter__: ?, …}
找到的另一種方法[[Prototype]]是通過__proto__財產(chǎn)。__proto__是一個公開[[Prototype]]對象內(nèi)部的屬性。
需要注意的是,. _proto__是一個遺留特性,不應(yīng)該在生產(chǎn)代碼中使用,而且它也不是在每個現(xiàn)代瀏覽器中都存在。但是,我們可以在本文中使用它來進(jìn)行演示。
x.__proto__;
輸出將與使用getPrototypeOf()相同。
輸出
{constructor: ?, __defineGetter__: ?, __defineSetter__: ?, …}
重要的是JavaScript中的每個對象都有一個[[Prototype]],因為它為任何兩個或多個對象創(chuàng)建了鏈接的方法。
您創(chuàng)建的對象和內(nèi)置對象(如Date和Array)一樣具有[[Prototype]]??梢酝ㄟ^prototype屬性將這個內(nèi)部屬性從一個對象引用到另一個對象,我們將在本教程的后面看到這一點。
原型繼承
原型鏈的末尾是Object.prototype。所有對象都繼承對象的屬性和方法。任何超出鏈末端的搜索都會導(dǎo)致null。
在我們的示例中,x是一個從object繼承而來的空對象。x可以使用對象具有的任何屬性或方法,比如toString()。
x.toString();
輸出
[object Object]
這個原型鏈只有一個鏈長。x - > Object。我們知道這一點,因為如果我們試圖將兩個[[Prototype]]屬性鏈接在一起,它將為null。
x.__proto__.__proto__;
輸出
null
讓我們看看另一種類型的對象。如果您有使用JavaScript處理數(shù)組的經(jīng)驗,就會知道它們有許多內(nèi)置方法,比如pop()和push()。創(chuàng)建新數(shù)組時可以訪問這些方法的原因是,創(chuàng)建的任何數(shù)組都可以訪問array .prototype上的屬性和方法。
我們可以通過創(chuàng)建一個新的數(shù)組來測試它。
let y = [];
請記住,我們也可以把它寫成數(shù)組構(gòu)造函數(shù),讓y = new array()。
如果我們查看新y數(shù)組的[[Prototype]],我們將看到它比x對象具有更多的屬性和方法。它繼承了Array.prototype中的所有內(nèi)容。
y.__proto__;
[constructor: ?, concat: ?, pop: ?, push: ?, …]
您將注意到原型上的構(gòu)造函數(shù)屬性被設(shè)置為Array()。構(gòu)造函數(shù)屬性返回對象的構(gòu)造函數(shù),這是一種用于從函數(shù)構(gòu)造對象的機(jī)制。
我們現(xiàn)在可以將兩個原型鏈接在一起,因為在這種情況下,我們的原型鏈更長。它看起來像y -> Array -> Object。
y.__proto__.__proto__;
{constructor: ?, __defineGetter__: ?, __defineSetter__: ?, …}
這個鏈現(xiàn)在引用Object.prototype。我們可以根據(jù)構(gòu)造函數(shù)的Prototype屬性測試內(nèi)部的[[Prototype]],以確定它們引用的是相同的東西。
y.__proto__ === Array.prototype; // true y.__proto__.__proto__ === Object.prototype; // true
我們還可以使用isPrototypeOf()方法來實現(xiàn)這一點。
Array.prototype.isPrototypeOf(y); // true Object.prototype.isPrototypeOf(Array); // true
我們可以使用instanceof操作符來測試構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在對象原型鏈中的任何位置。
y instanceof Array; // true
總而言之,所有JavaScript對象都具有隱藏的內(nèi)部[[Prototype]]屬性(可能__proto__在某些瀏覽器中公開)。對象可以擴(kuò)展,并將繼承[[Prototype]]其構(gòu)造函數(shù)的屬性和方法。
這些原型可以被鏈接,并且每個額外的對象將繼承整個鏈中的所有內(nèi)容。鏈以O(shè)bject.prototype結(jié)束。
構(gòu)造器函數(shù)
構(gòu)造函數(shù)是用來構(gòu)造新對象的函數(shù)。new操作符用于基于構(gòu)造函數(shù)創(chuàng)建新實例。我們已經(jīng)看到了一些內(nèi)置的JavaScript構(gòu)造函數(shù),比如new Array()和new Date(),但是我們也可以創(chuàng)建自己的自定義模板來構(gòu)建新對象。
例如,我們正在創(chuàng)建一個非常簡單的基于文本的角色扮演游戲。用戶可以選擇一個角色,然后選擇他們將擁有的角色類別,例如戰(zhàn)士、治療者、小偷等等。
由于每個字符將共享許多特征,例如具有名稱、級別和生命值,因此創(chuàng)建構(gòu)造函數(shù)作為模板是有意義的。然而,由于每個角色類可能有非常不同的能力,我們希望確保每個角色只能訪問自己的能力。讓我們看看如何使用原型繼承和構(gòu)造函數(shù)來實現(xiàn)這一點。
首先,構(gòu)造函數(shù)只是一個普通函數(shù)。當(dāng)使用new關(guān)鍵字的實例調(diào)用它時,它將成為一個構(gòu)造函數(shù)。在JavaScript中,我們按照慣例將構(gòu)造函數(shù)的第一個字母大寫。
// Initialize a constructor function for a new Hero function Hero(name, level) { this.name = name; this.level = level; }
我們創(chuàng)建了一個名為Hero的構(gòu)造函數(shù),它有兩個參數(shù):name和level。因為每個字符都有一個名稱和一個級別,所以每個新字符都有這些屬性是有意義的。this關(guān)鍵字將引用創(chuàng)建的新實例,因此將this.name設(shè)置為name參數(shù)將確保新對象具有name屬性集。
現(xiàn)在我們可以用new創(chuàng)建一個新的實例。
let hero1 = new Hero('Bjorn', 1);
如果我們在控制臺輸出hero1,我們將看到已經(jīng)創(chuàng)建了一個新對象,其中新屬性按預(yù)期設(shè)置。
輸出
Hero {name: "Bjorn", level: 1}
現(xiàn)在,如果我們得到hero1的[[Prototype]],我們將能夠看到構(gòu)造函數(shù)Hero()。(記住,它的輸入與hero1相同。,但這是正確的方法。)
Object.getPrototypeOf(hero1);
輸出
constructor: ? Hero(name, level)
您可能注意到,我們只在構(gòu)造函數(shù)中定義了屬性,而沒有定義方法。在JavaScript中,為了提高效率和代碼可讀性,通常在原型上定義方法。
我們可以使用prototype向Hero添加一個方法。我們將創(chuàng)建一個greet()方法。
// Add greet method to the Hero prototype Hero.prototype.greet = function () { return `${this.name} says hello.`; }
因為greet()在Hero的原型中,而hero1是Hero的一個實例,所以這個方法對hero1是可用的。
hero1.greet();
輸出
"Bjorn says hello."
如果檢查Hero的[[Prototype]],您將看到greet()現(xiàn)在是一個可用選項。
這很好,但是現(xiàn)在我們想要為英雄創(chuàng)建角色類。將每個類的所有功能都放到Hero構(gòu)造函數(shù)中是沒有意義的,因為不同的類具有不同的功能。我們希望創(chuàng)建新的構(gòu)造函數(shù),但也希望它們連接到原始的Hero。
我們可以使用call()方法將屬性從一個構(gòu)造函數(shù)復(fù)制到另一個構(gòu)造函數(shù)。讓我們創(chuàng)建一個戰(zhàn)士和一個治療構(gòu)造器。
// Initialize Warrior constructor function Warrior(name, level, weapon) { // Chain constructor with call Hero.call(this, name, level); // Add a new property this.weapon = weapon; }// Initialize Healer constructor function Healer(name, level, spell) { Hero.call(this, name, level); this.spell = spell; }
兩個新的構(gòu)造函數(shù)現(xiàn)在都具有Hero和unqiue的屬性。我們將把a(bǔ)ttack()方法添加到Warrior中,而heal()方法添加到Healer中。
Warrior.prototype.attack = function () { return `${this.name} attacks with the ${this.weapon}.`; } Healer.prototype.heal = function () { return `${this.name} casts ${this.spell}.`; }
此時,我們將使用兩個可用的新字符類創(chuàng)建字符。
const hero1 = new Warrior('Bjorn', 1, 'axe'); const hero2 = new Healer('Kanin', 1, 'cure');
hero1現(xiàn)在被認(rèn)為是擁有新屬性的戰(zhàn)士。
輸出
Warrior {name: "Bjorn", level: 1, weapon: "axe"}
我們可以使用我們在戰(zhàn)士原型上設(shè)置的新方法。
hero1.attack();
Console "Bjorn attacks with the axe."
但是如果我們嘗試使用原型鏈下面的方法會發(fā)生什么呢?
hero1.greet();
輸出
Uncaught TypeError: hero1.greet is not a function
使用call()鏈接構(gòu)造函數(shù)時,原型屬性和方法不會自動鏈接。我們將使用Object.create()來鏈接原型,確保在創(chuàng)建并添加到原型的任何其他方法之前將其放置。
Warrior.prototype = Object.create(Hero.prototype); Healer.prototype = Object.create(Hero.prototype); // All other prototype methods added below…
現(xiàn)在我們可以在一個戰(zhàn)士或治療者的實例上成功地使用Hero的原型方法。
hero1.greet();
輸出
"Bjorn says hello."
這里是我們的角色創(chuàng)建頁面的完整代碼。
// Initialize constructor functions function Hero(name, level) { this.name = name; this.level = level; } function Warrior(name, level, weapon) { Hero.call(this, name, level); this.weapon = weapon; } function Healer(name, level, spell) { Hero.call(this, name, level); this.spell = spell; } // Link prototypes and add prototype methods Warrior.prototype = Object.create(Hero.prototype); Healer.prototype = Object.create(Hero.prototype); Hero.prototype.greet = function () { return `${this.name} says hello.`; } Warrior.prototype.attack = function () { return `${this.name} attacks with the ${this.weapon}.`; } Healer.prototype.heal = function () { return `${this.name} casts ${this.spell}.`; } // Initialize individual character instances const hero1 = new Warrior('Bjorn', 1, 'axe'); const hero2 = new Healer('Kanin', 1, 'cure');
使用這段代碼,我們已經(jīng)用基本屬性創(chuàng)建了Hero類,從原始構(gòu)造函數(shù)創(chuàng)建了兩個名為Warrior和Healer的字符類,向原型添加了方法,并創(chuàng)建了單獨的字符實例。
關(guān)于JavaScript中的對象原型就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。