摘要:不理解沒關(guān)系,下面會(huì)結(jié)合圖例分析上一篇高級(jí)程序設(shè)計(jì)筆記創(chuàng)建對(duì)象下一篇高級(jí)程序設(shè)計(jì)筆記繼承參考之原型鏈的解讀三張圖搞懂的原型對(duì)象與原型鏈繼承與原型鏈
文章直接從原型圖解開始的,如果對(duì)一些概念不太清除,可以結(jié)合后面幾節(jié)查看1. 圖解原型鏈 1.1 “鐵三角關(guān)系”(重點(diǎn))
function Person() {}; var p = new Person();
這個(gè)圖描述了構(gòu)造函數(shù),實(shí)例對(duì)象和原型三者之間的關(guān)系,是原型鏈的基礎(chǔ):
(1)實(shí)例對(duì)象由構(gòu)造函數(shù)new產(chǎn)生;
(2)構(gòu)造函數(shù)的原型屬性與實(shí)例對(duì)象的原型對(duì)象均指向原型
(3)原型對(duì)象中有一個(gè)屬性constructor指向?qū)?yīng)的構(gòu)造函數(shù)
原型鏈:p --> Person.prototype
描述:實(shí)例對(duì)象能夠訪問到 Person.prototype 中不同名的屬性和方法
驗(yàn)證:
p instanceof Person; // true p.__proto__ === Person.prototype; // true Person.prototype.constructor === Person; // true1.2 以原型為構(gòu)造函數(shù)
原型鏈:p --> Person.prototype --> Object.prototype --> null
描述:
(1)由于構(gòu)造函數(shù)的原型也是對(duì)象,因此:它也有原型對(duì)象,指向Object.__proto__
(2)由于構(gòu)造函數(shù)的原型的原型也是對(duì)象,因此:它也有原型對(duì)象,指向null(特例)
驗(yàn)證:
p instanceof Person; // true p instanceof Object; // true Person.prototype instanceof Object; // true1.3 深入研究,引出Function構(gòu)造函數(shù)
1、原型鏈1:見1.2中的原型
2、原型鏈2:Person --> Function.prototype --> Object.prototype --> null
描述:
(1)構(gòu)造函數(shù)Person作為實(shí)例對(duì)象時(shí),Person = new Function()隱式調(diào)用,因此Person --> Function.prototype
(2)由于Function.prototype也是對(duì)象,Function.prototype = new Object()隱式調(diào)用,因此Function.prototype --> Object.prototype
驗(yàn)證:
Person instanceof Function; // true Person instanceof Object; // true Function.prototype instanceof Object; // true
3、原型鏈3:Function --> Function.prototype --> Object.prototype --> null
描述:
構(gòu)造函數(shù)Function作為實(shí)例對(duì)象時(shí),Function = new Function()隱式調(diào)用,因此Function --> Function.prototype
Function 這條原型鏈?zhǔn)亲顬樘厥獾摹拌F三角關(guān)系”,理解Function = new Function()就非常好理解了
驗(yàn)證:
Function.__proto__ === Function.prototype; // true Function instanceof Function; // true Function instanceof Object; // true1.4 完整的原型鏈
圖中新增了Object = new Function()的邏輯
驗(yàn)證:
Object instanceof Function;// true
幾個(gè)結(jié)論:
(1)對(duì)象都有原型對(duì)象,對(duì)象默認(rèn)繼承自其原型對(duì)象
(2)所有的函數(shù)都是 Function 的實(shí)例
(3)所有的原型鏈尾端都會(huì)指向Object.prototype
下面提幾個(gè)問題:
(1)上圖有幾條原型鏈?分別列出來(上面已給出)
(2)如何在代碼層面驗(yàn)證原型鏈上的繼承關(guān)系?(見第四節(jié))
(3)圖中有幾個(gè)“鐵三角”關(guān)系?分別列出來
當(dāng)實(shí)例對(duì)象被創(chuàng)建時(shí),其原型鏈就已經(jīng)確定了,當(dāng)其對(duì)應(yīng)的原型屬性指向改變時(shí),也無法改變?cè)玩?/pre>function Person({name="小A", age=21}={}) { this.name = name; this.age = age; }; // 情況1:在修改原型屬性前實(shí)例化對(duì)象 var p1 = new Person(); // 添加原型屬性(方法) Person.prototype.sayName = function() { console.log(this.name); } // Person.prototype.SayHi = function() {} // 情況2:在修改原型屬性后實(shí)例化對(duì)象 var p2 = new Person(); p1.sayName(); // "小A" p2.sayName(); // "小A"實(shí)例對(duì)象p1和實(shí)例對(duì)象p2的原型鏈相同,為 p1(p2) --> Person.prototype --> Object.prototype
=> 由于是在原有原型對(duì)象上添加的方法,相當(dāng)于對(duì)象的擴(kuò)展,故兩個(gè)實(shí)例對(duì)象均能執(zhí)行該方法function Person({name="小A", age=21}={}) { this.name = name; this.age = age; }; // 情況1:在修改原型屬性前實(shí)例化對(duì)象 var p1 = new Person(); // 重寫原型對(duì)象 Person.prototype = { sayName: function() { console.log(this.name); } } // 情況2:在修改原型屬性后實(shí)例化對(duì)象 var p2 = new Person(); p2.sayName(); // "小A" p1.sayName(); // p1.sayName is not a function重寫原型對(duì)象的方式,會(huì)改變實(shí)例對(duì)象的原型鏈,如下圖所示:
但是,為什么p1的原型鏈沒有變,而p2的原型鏈變了呢?
當(dāng)實(shí)例對(duì)象被創(chuàng)建時(shí),其原型鏈就已經(jīng)確定了,當(dāng)其對(duì)應(yīng)的原型屬性指向改變時(shí),也無法改變?cè)玩?/strong>
原型鏈?zhǔn)且詫?shí)例對(duì)象為核心的,不能被原型對(duì)象的改變而誤導(dǎo)重寫原型對(duì)象的方式會(huì)在原型鏈繼承中經(jīng)常使用到?。?!
3. 對(duì)象與函數(shù)(重點(diǎn))看到這里,我們可能已經(jīng)分不清函數(shù)與對(duì)象了,思考30秒,函數(shù)與對(duì)象是什么關(guān)系?
官方定義: 在Javascript中,每一個(gè)函數(shù)實(shí)際上都是一個(gè)函數(shù)對(duì)象function fn() {}; var obj = {}; fn instanceof Object; // true fn instanceof Function; // true obj instanceof Object; // true obj instanceof Function; // false原型鏈解釋:
fn對(duì)應(yīng)的原型鏈:fn --> Function.prototype --> Object.prototype
obj對(duì)應(yīng)的原型鏈:obj --> Object.prototype從函數(shù)的定義來說: 在javascript中一切函數(shù)實(shí)際都是函數(shù)對(duì)象,但對(duì)象不一定是函數(shù)
Function instanceof Object; // true Object instanceof Function; // true Function instanceof Function; // true原型鏈解釋:
Function對(duì)應(yīng)的原型鏈(Function作為實(shí)例對(duì)象):Function --> Function.prototype --> Object.prototype
Object對(duì)應(yīng)的原型鏈(Object作為實(shí)例對(duì)象):Object --> Function.prototype --> Object.prototype由于Function和Object都是構(gòu)造函數(shù),在內(nèi)置對(duì)象中,均會(huì)調(diào)用new Function()的方法
結(jié)論:
(1)函數(shù)一定是對(duì)象,但是對(duì)象不一定是函數(shù)
(2)對(duì)象都是由函數(shù)來創(chuàng)建的針對(duì)第一點(diǎn),這兩個(gè)原型鏈可驗(yàn)證:
fn --> Function.prototype --> Object.prototype
obj --> Object.prototype針對(duì)第二點(diǎn),可這樣驗(yàn)證:
var obj = { a: 1, b: 2} var arr = [2, "foo", false] // 實(shí)際過程 var obj = new Object() obj.a = 1 obj.b = 2 var arr = new Array() arr[0] = 2 arr[1] = "foo" arr[2] = false //typeof Object === "function" //typeof Array === "function4. 幾個(gè)定義 4.1 原型的定義和作用function Person() {}; var p = new Person();構(gòu)造函數(shù)的prototype屬性的值(Person.prototype),也可以說成通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建出來的那個(gè)實(shí)例對(duì)象的原型對(duì)象(p.__proto__)只要是函數(shù)就有 prototype 屬性,即函數(shù)的原型屬性(由于對(duì)象是由函數(shù)創(chuàng)建的,因此對(duì)象也有prototype屬性)
函數(shù)的原型屬性也是對(duì)象(因此,這個(gè)對(duì)象也有對(duì)應(yīng)的prototype屬性)
由構(gòu)造函數(shù)創(chuàng)建出來的對(duì)象會(huì)默認(rèn)鏈接到其構(gòu)造函數(shù)的這個(gè)屬性上(constructor)
構(gòu)造函數(shù)的 prototype 屬性的作用是:實(shí)現(xiàn)數(shù)據(jù)共享(繼承)
4.2 幾個(gè)術(shù)語實(shí)例對(duì)象中有一個(gè)屬性叫 __proto__ ,它是非標(biāo)準(zhǔn)屬性,指向構(gòu)造函數(shù)的原型屬性
Person.prototype 構(gòu)造函數(shù)的原型屬性
p.__proto__ 實(shí)例對(duì)象的原型對(duì)象構(gòu)造函數(shù)的原型屬性與實(shí)例對(duì)象的原型對(duì)象是一個(gè)東西,只是從不同的角度訪問原型
5. 屬性搜索原則和屬性來源判斷 5.1 屬性搜索原則(重點(diǎn))當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索先從對(duì)象實(shí)例本身開始,如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值;如果沒有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性。如果在原型對(duì)象中找到了這個(gè)屬性,則返回這個(gè)屬性,如果沒有找到,則繼續(xù)在這個(gè)原型對(duì)象的原型對(duì)象中查找,直到找到這個(gè)屬性,否則返回undefined簡言之,沿著對(duì)象的原型鏈查找屬性,返回最近的屬性,這就是屬性搜索原則
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg" 來自實(shí)例 alert(person2.name); //"Nicholas" 來自原型同樣的,這也是屬性屏蔽的原則
// 接著上面的例子 delete person1.namel; alert(person1.name); // "Nicholas" 來自原型5.2 hasOwnProperty()方法與in操作符使用hasOwnProperty()方法可以檢測一個(gè)屬性是存在于實(shí)例中,還是在原型中,這個(gè)方法只在給定屬性存在于對(duì)象實(shí)例中時(shí),才會(huì)返回truefunction Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false person1.name = "Greg"; alert(person1.name); //"Greg" 來自實(shí)例 alert(person1.hasOwnProperty("name")); //true alert(person2.name); //"Nicholas" 來自原型 alert(person2.hasOwnProperty("name")); //false delete person1.name; alert(person1.name); //"Nicholas" 來自原型 alert(person1.hasOwnProperty("name")); //false有兩種方式使用in操作符:多帶帶使用和在for-in循環(huán)中使用。在多帶帶使用時(shí),in操作符會(huì)在通過對(duì)象能夠訪問給定屬性時(shí)返回true,無論該屬性存在于實(shí)例中還是原型中因此,同時(shí)使用hasOwnProperty()和in操作符,就可以確定某個(gè)屬性到底是存在于對(duì)象中還是存在于原型中
function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object); }順便一提,由于in操作符會(huì)在整個(gè)原型鏈上查找屬性,處于性能考慮,在使用for-in循環(huán)時(shí),建議多加一層判別
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; var p = new Person(); p.sex = "fale"; for(key in p) { console.log(key); // sex name age } // 實(shí)際上,我們一般只是在查找實(shí)例中的屬性 for(key in p) { if(p.hasOwnProperty(key)) { console.log(key); // sex 屏蔽了原型中的屬性 } }5.3 instanceof操作符instanceof 用來判斷一個(gè)構(gòu)造函數(shù)的prototype屬性所指向的對(duì)象是否存在另外一個(gè)要檢測對(duì)象的原型鏈上更形象來說,對(duì)于 A instanceof B來說,它的判斷規(guī)則是:沿著A的__proto__這條線來找,同時(shí)沿著B的prototype這條線來找,如果兩條線能找到同一個(gè)引用,即同一個(gè)對(duì)象,那么就返回true。如果找到終點(diǎn)還未重合,則返回false。不理解沒關(guān)系,下面會(huì)結(jié)合圖例分析
function Person() {} var p = new Person(); console.log(p instanceof Object);//true console.log(p instanceof Person);//true上一篇:《javascript高級(jí)程序設(shè)計(jì)》筆記:創(chuàng)建對(duì)象
下一篇:《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承參考:
JavaScript之原型鏈的解讀
三張圖搞懂JavaScript的原型對(duì)象與原型鏈
繼承與原型鏈
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89571.html
摘要:繼承和前面兩篇文章中的知識(shí)非常相關(guān),如果對(duì)函數(shù)創(chuàng)建原理和原型鏈不熟悉,請(qǐng)猛戳高級(jí)程序設(shè)計(jì)筆記創(chuàng)建對(duì)象高級(jí)程序設(shè)計(jì)筆記原型圖解繼承,通俗的說,就是將自身不存在的屬性或方法,通過某種方式為自己所用文章分別介紹原型鏈繼承繼承借用構(gòu)造函數(shù)繼承組合繼 繼承和前面兩篇文章中的知識(shí)非常相關(guān),如果對(duì)函數(shù)創(chuàng)建原理和原型鏈不熟悉,請(qǐng)猛戳:《javascript高級(jí)程序設(shè)計(jì)》筆記:創(chuàng)建對(duì)象《javascri...
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響年是向上的一年在新的城市穩(wěn)定連續(xù)堅(jiān)持健身三個(gè)月早睡早起游戲時(shí)間大大縮減,學(xué)會(huì)生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響2018年是向上的一年:在新的城市穩(wěn)定、...
摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當(dāng)我們?cè)诔绦蛑袆?chuàng)建一個(gè)對(duì)象時(shí),這個(gè)對(duì)象將被保存到運(yùn)行時(shí)數(shù)據(jù)區(qū)中,以便反復(fù)利用因?yàn)閷?duì)象的創(chuàng)建成本通常較大,這個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承近幾篇博客都會(huì)圍繞著圖中的知識(shí)點(diǎn)展開 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...
摘要:探索是如何判斷的表達(dá)式如果函數(shù)的顯式原型對(duì)象在對(duì)象的隱式原型鏈上,返回,否則返回是通過自己產(chǎn)生的實(shí)例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測試題測試題報(bào)錯(cuò)對(duì)照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數(shù)的 prototype 屬性(圖) 每個(gè)函數(shù)都有一個(gè)prototype屬性,它默認(rèn)指向一個(gè)Object空對(duì)象(即稱為:原型對(duì)象) 原型對(duì)象中有...
摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包。作用域鏈的頂端是全局對(duì)象,在全局環(huán)境中定義的變量就會(huì)綁定到全局對(duì)象中。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第6天。 本...
閱讀 719·2021-11-11 16:55
閱讀 2248·2021-11-11 16:55
閱讀 2049·2021-11-11 16:55
閱讀 2418·2021-10-25 09:46
閱讀 1689·2021-09-22 15:20
閱讀 2447·2021-09-10 10:51
閱讀 1794·2021-08-25 09:38
閱讀 2701·2019-08-30 12:48