摘要:給添加屬性給的原型對象添加屬性原型鏈在中,每個對象都有一個屬性,其保存著的地址就構(gòu)成了對象的原型鏈。實(shí)例變量實(shí)例函數(shù)原型鏈繼承有了原型鏈,就可以借助原型鏈實(shí)現(xiàn)繼承。是中唯一一個處理屬性但是不查找原型鏈的函數(shù)。
前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總
歡迎提issues斧正:原型&原型鏈&原型繼承
JavaScript-原型&原型鏈&原型繼承JavaScript的原型是一個重要的知識點(diǎn),很多擴(kuò)展應(yīng)用都是從原型出發(fā)的。要說原型,我們先簡單說一下函數(shù)創(chuàng)建過程。上一篇文章用閉包實(shí)現(xiàn)類和繼承中用的是原型繼承,今天就講一講原型繼承。更多繼承在后面的文章中更新。
函數(shù)創(chuàng)建過程function Xzavier() {};
1.創(chuàng)建一個對象(有constructor屬性及[[Prototype]]屬性),其中[[Prototype]]屬性不可訪問、不可枚舉。
2.創(chuàng)建一個函數(shù)(有name、prototype屬性),再通過prototype屬性 引用第1步創(chuàng)建的對象。
3.創(chuàng)建變量Xzavier,同時(shí)把函數(shù)的引用賦值給變量Xzavier。
構(gòu)造函數(shù)是用來新建同時(shí)初始化一個新對象的函數(shù),所以,任何一個函數(shù)都可以是構(gòu)造函數(shù)。只是我們在寫代碼的時(shí)候一般首字母大寫以便區(qū)分使用。
原型每個函數(shù)在創(chuàng)建的時(shí)候js都自動添加了prototype屬性,這就是函數(shù)的原型,原型就是函數(shù)的一個屬性,類似一個指針。原型在函數(shù)的創(chuàng)建過程中由js編譯器自動添加。
function Xzavier() { this.name = "xzavier"; this.sex = "boy"; this.job = "jser"; } //給A添加屬性 Xzavier.age = 23; //給A的原型對象添加屬性 Xzavier.prototype.sports = function() {console.log("basketball")} Xzavier.prototype = { hobbit1: function() {console.log("basketball");}, hobbit2: function() {console.log("running");} };原型鏈
在JavaScript中,每個對象都有一個[[Prototype]]屬性,其保存著的地址就構(gòu)成了對象的原型鏈。
[[Prototype]]屬性是js編譯器在對象被創(chuàng)建時(shí)自動添加的,其取值由new運(yùn)算符的右側(cè)參數(shù)決定。字面量的方式可轉(zhuǎn)化為new Obejct();
var x = new Xzavier(); vae o = {}; //var o = new Obejct();
通過對象的[[Prototype]]保存對另一個對象的引用,通過這個引用往上進(jìn)行屬性的查找,這就是原型鏈查找機(jī)制。
對象在查找某個屬性的時(shí)候,會首先遍歷自身的屬性,如果沒有則會繼續(xù)查找[[Prototype]]引用的對象,如果再沒有則繼續(xù)查找[[Prototype]].[[Prototype]]引用的對象,依次類推,直到[[Prototype]].….[[Prototype]]為undefined
var str = new String("xzavier"); str
Object.prototype的[[Prototype]]就是undefined
function Xzavier() { this.name = "xzavier"; } var x = new Xzavier(); x.age = 23; console.log(x.job); // 獲取x的job屬性 undefined
1、遍歷x對象本身,結(jié)果x對象本身沒有job屬性
2、找到x的[[Prototype]],也就是其對應(yīng)的對象Xzavier.prototype,同時(shí)進(jìn)行遍歷。 Xzavier.prototype也沒有job屬性
3、找到Xzavier.prototype對象的[[Prototype]],指向其對應(yīng)的對象Object.prototype。Object.prototype也沒有job屬性
4、尋找Object.prototype的[[Prototype]]屬性,返回undefined。
說了函數(shù)的原型鏈,這里需要說一下的變量和內(nèi)部函數(shù)。
私有變量和內(nèi)部函數(shù)私有成員,即定義函數(shù)內(nèi)部的變量或函數(shù),外部無法訪問。
function Xzavier(){ var name = "xzavier"; //私有變量 var sports = function() {console.log("basketball")}; //私有函數(shù) } var x = new Xzavier(); x.name; //undefined
如果要訪問,需要對外提供接口。
function Xzavier(){ var name = "xzavier"; //私有變量 var sports = function() {console.log("basketball")}; //私有函數(shù) return{ name: name, sports: sports } } var x = new Xzavier(); x.name; //"xzavier"靜態(tài)變量和內(nèi)部函數(shù)
用點(diǎn)操作符定義的靜態(tài)變量和內(nèi)部函數(shù)就是實(shí)例不能訪問到的變量和內(nèi)部函數(shù)。只能通過自身去訪問。
function Xzavier(){ Xzavier.name = "xzavier"; //靜態(tài)變量 Xzavier.sports = function() {console.log("basketball")}; //靜態(tài)函數(shù) } Xzavier.name; //"xzavier" var x = new Xzavier(); x.name; //undefined實(shí)例變量和內(nèi)部函數(shù)
通過this定義給實(shí)例使用的屬性和方法。
function Xzavier(){ this.name = "xzavier"; //實(shí)例變量 this.sports = function() {console.log("basketball");}; //實(shí)例函數(shù) } Xzavier.name; //undefined var x = new Xzavier(); x.name; //"xzavier"原型鏈繼承
有了原型鏈,就可以借助原型鏈實(shí)現(xiàn)繼承。
function Xzavier() { this.name = "xzavier"; this.sex = "boy"; this.job = "jser"; } function X() {};
X的原型X.prototype原型本身就是一個Object對象。F12打開控制臺輸入函數(shù),再打印X.prototype:
Object { constructor: X() __proto__: Object }
prototype本身是一個Object對象的實(shí)例,所以其原型鏈指向的是Object的原型。
X.prototype = Xzavier.prototypeX.prototype = Xzavier.prototype;
這樣相當(dāng)于把X的prototype指向了Xzavier的prototype;
這樣只是繼承了Xzavier的prototype方法,Xzavier中的自定義方法則不繼承。
X.prototype.love = "dog";
這樣也會改變Xzavier的prototype,所以這樣基礎(chǔ)就不好。
X.prototype = new Xzavier()X.prototype = new Xzavier();
這樣產(chǎn)生一個Xzavier的實(shí)例,同時(shí)賦值給X的原型,也即X.prototype相當(dāng)于對象:
{ name: "xzavier", sex: "boy", job: "jser", [[Prototype]] : Xzavier.prototype }
這樣就把Xzavier的原型通過X.prototype.[[Prototype]]這個對象屬性保存起來,構(gòu)成了原型的鏈接。
不過,這樣X產(chǎn)生的對象的構(gòu)造函數(shù)發(fā)生了改變,因?yàn)樵赬中沒有constructor屬性,只能從原型鏈找到Xzavier.prototype,讀出constructor:Xzavier。
var x = new X; console.log(x.constructor); 輸出: Xzavier() { this.name = "xzavier"; this.sex = "boy"; this.job = "jser"; }
手動改正:
X.prototype.constructor = X;
這是X的原型就多了個屬性constructor,指向X。這樣就OK。
function Xzavier() { this.name = "xzavier"; this.sex = "boy"; this.job = "jser"; } function X(){} X.prototype = new Xzavier(); var x = new X() x.name // "xzavier"[[Prototype]],__proto__,prototype
關(guān)于我們經(jīng)常遇到的[[Prototype]],__proto__,prototype:
我們在控制臺打印 var str = new String("xzavier"),展開查看屬性時(shí),只會看到__proto__,所以起作用的是__proto__,__proto__是對象的內(nèi)置屬性,是每個對象都有的屬性,但是這個屬性使用不標(biāo)準(zhǔn),所以不建議直接使用。但是,我們的原型鏈就是基于 __proto__的。通過構(gòu)造函數(shù)得到的實(shí)例的 __proto__ 屬性,指向其對應(yīng)的原型對象 String.prototype,這正如文中我們打印 var str = new String("xzavier") 中看到的一樣。
[[Prototype]]是一個隱藏屬性,指向的是這個對象的原型。幾乎每個對象有一個[[prototype]]屬性。
而prototype是每個函數(shù)對象都具有的屬性,指向原型對象,如果原型對象被添加屬性和方法,那么由應(yīng)的構(gòu)造函數(shù)創(chuàng)建的實(shí)例會繼承prototype上的屬性和方法,這也是我們在代碼中經(jīng)常遇到的。構(gòu)造函數(shù)產(chǎn)生實(shí)例時(shí),實(shí)例通過其對應(yīng)原型對象的 constructor 訪問對應(yīng)的構(gòu)造函數(shù)對象。所以,我們繼承出來的實(shí)例往往沒有constructor,只是通過原型鏈查找,會讓我們產(chǎn)生錯覺,可參見本系列原型鏈文章。
hasOwnPropertyhasOwnProperty是Object.prototype的一個方法,判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性。
hasOwnProperty 是JavaScript中唯一一個處理屬性但是不查找原型鏈的函數(shù)。
function Xzavier() { this.name = "xzavier"; this.sex = "boy"; this.job = "jser"; } //給A的原型對象添加屬性 Xzavier.prototype.sports = function() {console.log("basketball");}; var x = new Xzavier(); x.name; // "xzavier" "sex" in x; // true x.hasOwnProperty("job"); // true x.hasOwnProperty("sports"); // false
當(dāng)檢查對象上某個屬性是否存在時(shí),hasOwnProperty 是非常推薦的方法。
繼承在js中使用頻繁。ES6也設(shè)計(jì)了專門的CLASS語法糖供開發(fā)者使用。
更多繼承方法在新的文章中更新...
難得周末,應(yīng)該運(yùn)動O(∩_∩)O~ 打打籃球,運(yùn)動運(yùn)動,有代碼,有籃球,有生活。。。
長時(shí)間不動肩膀(其實(shí)身體各地方都是),還真疼啊。希望程序猿們都健健康康的?。?!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/90946.html
摘要:該對象包含了函數(shù)的所有局部變量命名參數(shù)參數(shù)集合以及,然后此對象會被推入作用域鏈的前端。如果整個作用域鏈上都無法找到,則返回。此時(shí)的作用域鏈包含了兩個對象的活動對象和對象。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:閉包 JavaScript-閉包 閉包(closure)是一個讓人又愛又恨的somet...
摘要:對象創(chuàng)建字面量方式構(gòu)造函數(shù)方式也可以這樣不過這樣的話,為何不選擇字面量方式字面量方式和方式的寫法是等價(jià)的,返回的結(jié)果是同種類的對象。構(gòu)造函數(shù)產(chǎn)生實(shí)例時(shí),實(shí)例通過其對應(yīng)原型對象的訪問對應(yīng)的構(gòu)造函數(shù)對象。 前端學(xué)習(xí):教程&模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試資源匯總 歡迎提issues斧正:對象&對象使用 Object對象 在 JavaScript 中,對...
之前也有和大家講過有關(guān)JS的對象創(chuàng)建和對象繼承,本篇文章主要為大家做個匯總和梳理?! S中其實(shí)就是原型鏈繼承和構(gòu)造函數(shù)繼承的毛病,還有就是工廠、構(gòu)造、原型設(shè)計(jì)模式與JS繼承。 JS高級程序設(shè)計(jì)4:class繼承的重點(diǎn),不只是簡簡單單的語法而已?! ο髣?chuàng)建 不難發(fā)現(xiàn),每一篇都離不開工廠、構(gòu)造、原型這3種設(shè)計(jì)模式中的至少其一! 那JS為什么非要用到這種3種設(shè)計(jì)模式了呢?? 我們先從對...
摘要:創(chuàng)建數(shù)組數(shù)組字面量數(shù)組構(gòu)造函數(shù)參數(shù)為數(shù)組建議使用數(shù)組字面量方式,性能好,代碼少,簡潔,畢竟代碼少。數(shù)組判斷方法用來判斷某個值是否為。的這是最簡潔最直接的遍歷數(shù)組元素的語法。把數(shù)組轉(zhuǎn)換為本地?cái)?shù)組,并返回結(jié)果。 前端學(xué)習(xí):前端教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:數(shù)組&數(shù)組方法使用詳解 Array對象 之前一...
閱讀 2259·2021-11-22 09:34
閱讀 2031·2021-09-22 15:22
閱讀 2026·2019-08-29 15:05
閱讀 2118·2019-08-26 10:43
閱讀 3417·2019-08-26 10:26
閱讀 895·2019-08-23 18:29
閱讀 3527·2019-08-23 16:42
閱讀 2004·2019-08-23 14:46