原型、原型链和继承
一、原型 prototype 和 proto
- 每個(gè)對象都有一個(gè)__proto__屬性,并且指向它的prototype原型對象。
- 每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype原型對象 prototype原型對象里的constructor指向構(gòu)造函數(shù)本身
prototype 和 __proto__有什么用呢?
實(shí)例對象的__proto__指向構(gòu)造函數(shù)的prototype,從而實(shí)現(xiàn)繼承。(只有對象才有__proto__)
prototype對象相當(dāng)于特定類型所有實(shí)例對象都可以訪問的公共容器。
二、原型鏈
var arr = [5,6,7]
arr.valueOf() // [5,6,7]
查找valueOf方法的過程當(dāng)試圖訪問一個(gè)對象的屬性時(shí),它不僅僅在該對象上搜尋,還會(huì)搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾。查找valueOf大致流程當(dāng)前實(shí)例對象obj,查找obj的屬性或方法,找到后返回沒有找到,通過obj. proto,找到obj構(gòu)造函數(shù)的prototype并且查找上面的屬性和方法,找到后返回沒有找到,把Array.prototype當(dāng)做obj,重復(fù)以上步驟當(dāng)然不會(huì)一直找下去,原型鏈?zhǔn)怯薪K點(diǎn)的,最后查找到Object.prototype時(shí)Object.prototype.proto === null,意味著查找結(jié)束.
arr.__proto__ === Array.prototype // true Array.prototype.__proto__ === Object.prototype //true arr.__proto__.__proto__ === Object.prototype // true// 原型鏈的終點(diǎn) Object.prototype.__proto__ === null // true**原型鏈如下:
arr ---> Array.prototype ---> Object.prototype ---> null這就是傳說中的原型鏈,層層向上查找,最后還沒有就返回undefined
三、JavaScript 中的繼承
3.1 什么是繼承?
繼承是指一個(gè)對象直接使用另外一個(gè)對象的屬性和方法
由此可見只要實(shí)現(xiàn)屬性和方法的繼承,就達(dá)到繼承的效果
- 得到一個(gè)對象的屬性
- 得到一個(gè)對象的方法
3.2 屬性如何繼承?
我們先創(chuàng)建一個(gè)Person類
此時(shí)我想創(chuàng)建一個(gè)Teacher類,我希望它可以繼承Person所有的屬性,并且額外添加屬于自己特定的屬性;
一個(gè)新的屬性,subject——這個(gè)屬性包含了教師教授的學(xué)科。
定義Teacher的構(gòu)造函數(shù)
function Teacher(name,age,subject){Person.call(this,name,age)this.subject = subject }屬性的繼承是通過再一個(gè)類內(nèi)執(zhí)行另一個(gè)類的構(gòu)造函數(shù),通過call指定this為當(dāng)前執(zhí)行環(huán)境,這樣就可以得到另一個(gè)類的所有屬性。
Person.call(this, name, age)實(shí)例化
var teacher = new Teacher('jack', 25, Math)teacher.age 25 teacher.name "jack"很明顯Teacher成功繼承了Person的屬性
3.3 方法如何繼承?
我們需要讓Teacher從Person的原型對象里繼承方法。我們要怎么做呢?我們都知道類的方法都定義在prototype里,那其實(shí)我們只需要把Person.prototype的備份賦值給Teacher.prototype即可Teacher.prototype = Object.create(Person.prototype) Object.create簡單說就是新建一個(gè)對象,使用現(xiàn)有的對象賦值給新建對象的__proto__可能有人會(huì)問為什么是備份呢?
因?yàn)槿绻苯淤x值,那會(huì)是引用關(guān)系,意味著修改Teacher. prototype,也會(huì)同時(shí)修改Person.prototype,這是不合理的。另外注意一點(diǎn)就是,在給Teacher類添加方法時(shí),應(yīng)該在修改prototype以后,否則會(huì)被覆蓋掉,原因是賦值前后的屬性值是不同的對象。最后還有一個(gè)問題,我們都知道prototype里有個(gè)屬性constructor指向構(gòu)造函數(shù)本身,但是因?yàn)槲覀兪菑?fù)制其他類的prototype,所以這個(gè)指向是不對的,需要更正一下。如果不修改,會(huì)導(dǎo)致我們類型判斷出錯(cuò)
繼承方法的最終方案:
Teacher.prototype = Object.create(Person.prototype) Teacher.prototype.constructor = Teacher3.4 hasOwnProperty
在原型鏈上查詢屬性比較耗時(shí),對性能有影響,試圖訪問不存在的屬性時(shí)會(huì)遍歷整個(gè)原型鏈。遍歷對象屬性時(shí),每個(gè)可枚舉的屬性都會(huì)被枚舉出來。
要檢查是否具有自己定義的屬性,而不是原型鏈上的屬性,必須使用hasOwnProperty方法。
hasOwnProperty 是JavaScript 中唯一處理屬性并且不會(huì)
遍歷原型鏈的方法。
四、總結(jié)
prototype 和__proto__
每個(gè)對象都有一個(gè)__proro__屬性,并且指向它的prototype原型對象。
每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype原型對象,prototype原型對象里的constructor指向構(gòu)造函數(shù)本身。
原型鏈
每個(gè)對象都有一個(gè)__proto__。它指向它的prototype原型對象,而prototype原型對象又具有一個(gè)自己的prototype對象,就這樣層層往上直到一個(gè)對象的prototype為 null.
這個(gè)查詢的路徑就是原型鏈。
JavaScript 中的繼承
- 屬性繼承
- 方法繼承
總結(jié)
- 上一篇: 煤矿三维可视化_三维激光扫描建模_BIM
- 下一篇: AD09 DXP保姆级教程系列——006