国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

學(xué)習(xí)javascript面向?qū)ο?理解javascript原型和原型鏈

2019-11-20 10:52:13
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

先看一張圖,梳理梳理。

一、基本概念  
【原型鏈】每個(gè)構(gòu)造函數(shù)都有一個(gè)對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。那么,如果原型對(duì)象等于另一個(gè)原型的實(shí)例,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)地,另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。如果另一個(gè)原型又是另一個(gè)原型的實(shí)例,那么上述關(guān)系依然成立。如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條。
【原型對(duì)象】這個(gè)對(duì)象包含可以由特定類(lèi)型的所有實(shí)例共享的屬性和方法。所有引用類(lèi)型默認(rèn)都繼承了Object,而這個(gè)繼承也是通過(guò)原型鏈實(shí)現(xiàn)的。所有函數(shù)的默認(rèn)原型都是Object的實(shí)例,因此默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針,指向Object.prototype,這也正是所有自定義類(lèi)型都會(huì)繼承toString()、valueOf()方法的原因
【構(gòu)造函數(shù)】構(gòu)造函數(shù)與其他函數(shù)的區(qū)別在于調(diào)用它們的方式不同。一般來(lái)說(shuō),函數(shù)只要通過(guò)new操作符來(lái)調(diào)用,那它就可以作為構(gòu)造函數(shù);如果不通過(guò)new操作符來(lái)調(diào)用,那它跟普通函數(shù)也不會(huì)有什么兩樣。
[注意]用戶自定義的函數(shù)和javascript中內(nèi)置的構(gòu)造函數(shù)可以當(dāng)成構(gòu)造函數(shù)使用
【構(gòu)造函數(shù)的寫(xiě)法】構(gòu)造函數(shù)始終應(yīng)該以一個(gè)大寫(xiě)字母開(kāi)頭,而非構(gòu)造函數(shù)以一個(gè)小寫(xiě)字母開(kāi)頭。這個(gè)做法借鑒自其他OO語(yǔ)言,主要是為了區(qū)別于ECMAScript中的其他函數(shù);因?yàn)闃?gòu)造函數(shù)本身也是函數(shù),只不過(guò)可以用來(lái)創(chuàng)建對(duì)象而已
【構(gòu)造函數(shù)的三種使用場(chǎng)景】
[a]當(dāng)作構(gòu)造函數(shù)使用

var person = new Person("Nicholas",29,"software Engineer");person.sayName();

[b]當(dāng)作普通函數(shù)調(diào)用

Person("greg",27,"doctor");//添加到windowwindow.sayName();//"Greg"

[c]在另一個(gè)對(duì)象的作用域中調(diào)用

var o = new Object();Person.call(o,"Kristen",25,"Nurse");o.sayName();//"Kristen"

【prototype屬性】只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。
[注意]只有函數(shù)才有prototype屬性,object沒(méi)有prototype屬性
【constructor屬性】在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向prototype屬性所在函數(shù)的指針
[注意]創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得constructor屬性,至于其他方法則都是從Object繼承而來(lái)的
【_proto_和[[prototype]]】當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象。ECMA-262第5版管這個(gè)指針叫[[prototype]]。雖然在腳本中標(biāo)準(zhǔn)的方式訪問(wèn)[[prototype]],但firefox/safari/chrome在每個(gè)對(duì)象上都支持一個(gè)屬性_proto_;而在其他實(shí)現(xiàn)中,這個(gè)屬性對(duì)腳本則是完全不可見(jiàn)的。這個(gè)連接存在于實(shí)例與構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在于實(shí)例與構(gòu)造函數(shù)之間
二、基本操作  
【原型鏈查詢】每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索首先從對(duì)象實(shí)例本身開(kāi)始,如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值;如果沒(méi)有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性,如果找到了這個(gè)屬性,則返回該屬性的值。
【添加實(shí)例屬性】當(dāng)為對(duì)象實(shí)例添加一個(gè)屬性時(shí),這個(gè)屬性就會(huì)屏蔽原型對(duì)象中保存的同名屬性;換句話說(shuō),添加這個(gè)屬性只會(huì)阻止我們?cè)L問(wèn)原型中的那個(gè)屬性,但不會(huì)修改那個(gè)屬性,即使將這個(gè)屬性設(shè)置為null,也只會(huì)在實(shí)例中設(shè)置這個(gè)屬性,而不會(huì)恢復(fù)其指向原型的連接。不過(guò),使用delete操作符則可以完全刪除實(shí)例屬性,從而讓我們能夠重新訪問(wèn)原型中的屬性。
【原型的動(dòng)態(tài)性】由于在原型中查找值的過(guò)程是一次搜索,因此我們對(duì)原型對(duì)象所做的任何修改都能立即從實(shí)例上反映出來(lái),即使是先創(chuàng)建了實(shí)例后修改原型也照樣如此。
[注意]不推薦在產(chǎn)品化的程序中修改原生對(duì)象的原型

function Person(){};var friend = new Person();Person.prototype.sayHi = function(){  alert('hi');}friend.sayHi();//"hi"  

【重寫(xiě)原型】調(diào)用構(gòu)造函數(shù)時(shí)會(huì)為實(shí)例添加一個(gè)指向最初原型的[[prototype]]指針,而把原型修改為另外一個(gè)對(duì)象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。實(shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。
三、基本方法  
[1]isPrototypeOf():判斷實(shí)例對(duì)象和原型對(duì)象是否存在于同一原型鏈中,只要是原型鏈中出現(xiàn)過(guò)的原型,都可以說(shuō)是該原型鏈所派生的實(shí)例的原型

function Person(){};var person1 = new Person();var person2 = new Object();console.log(Person.prototype.isPrototypeOf(person1));//trueconsole.log(Object.prototype.isPrototypeOf(person1));//trueconsole.log(Person.prototype.isPrototypeOf(person2));//falseconsole.log(Object.prototype.isPrototypeOf(person2));//true

[2]ECMAScript5新增方法Object.getPrototypeOf():這個(gè)方法返回[[Prototype]]的值

function Person(){};var person1 = new Person();var person2 = new Object();console.log(Object.getPrototypeOf(person1)); //Person{}console.log(Object.getPrototypeOf(person1) === Person.prototype); //trueconsole.log(Object.getPrototypeOf(person1) === Object.prototype); //falseconsole.log(Object.getPrototypeOf(person2)); //Object{}  

[3]hasOwnProperty():檢測(cè)一個(gè)屬性是否存在于實(shí)例中

function Person(){  Person.prototype.name = 'Nicholas';}var person1 = new Person();//不存在實(shí)例中,但存在原型中console.log(person1.hasOwnProperty("name"));//false//不存在實(shí)例中,也不存在原型中console.log(person1.hasOwnProperty("no"));//falseperson1.name = 'Greg';console.log(person1.name);//'Greg'console.log(person1.hasOwnProperty('name'));//truedelete person1.name;console.log(person1.name);//"Nicholas"console.log(person1.hasOwnProperty('name'));//false  

[4]ECMAScript5的Object.getOwnPropertyDescriptor():只能用于取得實(shí)例屬性的描述符,要取得原型屬性的描述符,必須直接在原型對(duì)象上調(diào)用Object.getOwnPropertyDescription()方法

function Person(){  Person.prototype.name = 'Nicholas';}var person1 = new Person();person1.name = 'cook';console.log(Object.getOwnPropertyDescriptor(person1,"name"));//Object {value: "cook", writable: true, enumerable: true, configurable: true}console.log(Object.getOwnPropertyDescriptor(Person.prototype,"name"));//Object {value: "Nicholas", writable: true, enumerable: true, configurable: true}

[5]in操作符:在通過(guò)對(duì)象能夠訪問(wèn)給定屬性時(shí)返回true,無(wú)論該屬性存在于實(shí)例還是原型中

function Person(){}var person1 = new Person();person1.name = 'cook';console.log("name" in person1);//trueconsole.log("name" in Person.prototype);//falsevar person2 = new Person();Person.prototype.name = 'cook';console.log("name" in person2);//trueconsole.log("name" in Person.prototype);//true

[6]同時(shí)使用hasOwnProperty()方法和in操作符,來(lái)確定屬性是否存在于實(shí)例中

//hasOwnProperty()返回false,且in操作符返回true,則函數(shù)返回true,判定是原型中的屬性function hasPrototypeProperty(object,name){  return !object.hasOwnProperty(name) && (name in object);}function Person(){  Person.prototype.name = 'Nicholas';}var person1 = new Person();console.log(hasPrototypeProperty(person1,'name'));//trueperson1.name = 'cook';console.log(hasPrototypeProperty(person1,'name'));//falsedelete person1.name;console.log(hasPrototypeProperty(person1,'name'));//truedelete Person.prototype.name;console.log(hasPrototypeProperty(person1,'name'));//false

[7]ECMAScript5的Object.keys()方法:接收一個(gè)對(duì)象作為參數(shù),返回一個(gè)包含所有可枚舉屬性的字符串?dāng)?shù)組
[注意]一定要先new出實(shí)例對(duì)象再使用該方法,否則為空

function Person(){  Person.prototype.name = 'Nicholas';  Person.prototype.age = 29;  Person.prototype.job = 'Software Engineer';  Person.prototype.sayName = function(){    alert(this.name);  }  };var keys = Object.keys(Person.prototype);console.log(keys);//[]var p1 = new Person();p1.name = "Rob";p1.age = 31;var keys = Object.keys(Person.prototype);console.log(keys);//["name","age","job","sayName"]var p1Keys = Object.keys(p1);console.log(p1Keys);//["name","age"]

[8]ECMAScript5的Object.getOwnPropertyNames()方法:接收一個(gè)對(duì)象作為參數(shù),返回一個(gè)包含所有屬性的字符串?dāng)?shù)組
[注意]一定要先new出實(shí)例對(duì)象再使用該方法,否則只有constructor

function Person(){  Person.prototype.name = 'Nicholas';  Person.prototype.age = 29;  Person.prototype.job = 'Software Engineer';  Person.prototype.sayName = function(){    alert(this.name);  }  };var keys = Object.getOwnPropertyNames(Person.prototype);console.log(keys);//["constructor"]var p1 = new Person();var keys = Object.getOwnPropertyNames(Person.prototype);console.log(keys);//["constructor", "name", "age", "job", "sayName"]

希望本文所述對(duì)大家學(xué)習(xí)javascript程序設(shè)計(jì)有所幫助。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 广宁县| 青田县| 天津市| 佛山市| 徐水县| 镇江市| 霍州市| 英德市| 莱阳市| 时尚| 方山县| 隆化县| 荣昌县| 小金县| 姚安县| 石家庄市| 云浮市| 安远县| 青阳县| 西畴县| 凤凰县| 金华市| 乌鲁木齐县| 友谊县| 静乐县| 自治县| 普兰店市| 丹棱县| 博湖县| 松滋市| 安陆市| 泰宁县| 浮山县| 黑河市| 洪雅县| 堆龙德庆县| 武鸣县| 翼城县| 休宁县| 专栏| 绍兴市|