简单了解原型原型链
一、基本概念
?1.什么是原型
?這里會設計到兩個概念:構造函數和原型對象。
?構造函數:在 JavaScript 中,用 new 關鍵字來調用的函數,稱為構造函數。構造函數首字母一般大寫。
?原型對象:初始化一個構造函數,它有一個 prototype 屬性,該屬性值指向的就是構造函數的原型對象
function Person (name, age) {this.name = namethis.age = age } ? console.log(Person.prototype)比如上文的Person.prototype指向的就是Person的原型
當然了,只有構造函數才有 prototype 這個屬性,其他對象是沒有的
我們來看看原型的定義:
原型本質是一個對象,原型對象是為了給其他實例對象提供共享屬性的
2.訪問原型對象
首先通過構造函數初始化一個實例對象
const person1 = new Person('高啟強', 38) console.log(person1);左邊紅色框表示調用的哪個,右邊是對象實例。
?可以看到 person1 只具有構造函數中初始化的兩個默認屬性 name 和 age
上面說到構造函數可以通過prototype屬性訪問到原型對象,那么這個構造函數的實例對象如何訪問到這個原型對象呢?
我們可以使用__proto__屬性
console.log(person1.__proto__ === Person.prototype)看一下控制臺打印:
?我們可以看到這兩個是完全等價的
__proto__最初是由各個瀏覽器廠商獨立實現的 hack 方法,目前已收入到ES6規范中,可以放心使用
當然,更推薦的還是使用 ES6 規定的獲取原型的方法Object.getPrototypeOf()
console.log(Object.getPrototypeOf(person1) === Person.prototype) // true反過來,如何通過原型對象訪問到構造函數呢?原型對象有個 constructor 屬性:
console.log(Person.prototype.constructor === Person) // true每個原型對象都有一個 constructor 屬性指向關聯的構造函數
3.共享屬性
如果我們訪問一個構造函數沒有定義過的屬性會怎么樣?
console.log(person1.work) // undefined當然是 undefined 了,沒定義就沒有,我們找不到它。
那我們嘗試在原型對象上定義它,再次記住原型對象的作用:給實例對象提供共享屬性
Person.prototype.work= '殺魚'OK,我們嘗試在實例對象上訪問這個屬性
console.log(person1.work) // 殺魚看一下控制臺打印:
成功了!
那么 person1 會有什么變化嗎?打印下看看
console.log(person1) // Person {name: 'Jason', age: 21}person1 是沒有 work屬性,因為它并沒有在 person1 或者構造函數中定義過
那?person1.work的值哪來的?答案已經呼之欲出
從 person1 的原型對象上拿到的
person1.work=== person1.__proto__.work所以我們可以得出第一個結論,當找不到對象的某個屬性時,它會繼續往這個對象的原型對象上找
我們再用這個構造函數初始化一個對象
const person2 = new Person('高啟盛', 22)看一看這個 person2 長啥樣
console.log(person2) // Person {name: '高啟盛', age: 22}person2 同樣也沒有 work 屬性
console.log(person2.name +"的工作是"+ person2.work)看一下控制臺打印:
可以看到我們聲明的第二個人物同樣拿到了work這個屬性,說明雖然沒有這個屬性,但是也能訪問到原型對象上的共享屬性 work,簡單說只要是這個對象new出來的都可以使用它。
console.log(person2.__proto__.work=== person2.work) // true沒錯,這倆個就是完全等價的!
我們通過 person2 改變這個綁定在原型上的屬性值試試,注意看我這里改變的是person2原型上的work變成了白金瀚的老板,打印出來person1的work也變成白金瀚的老板。也就是原型對象上的work屬性是全部實例對象所共享的,一有俱有,一改俱改
這樣我們應該就理解了,原型對象是用來提供共享屬性這句話了
person2.__proto__.work = '白金瀚老板' console.log("現在"+person1.name +"的工作是"+ person1.work)看一下控制臺打印:
二、原型鏈
1.訪問對象的某個屬性當找不到時?
我們知道了訪問對象的某個屬性當找不到時,會往它的原型對象上找,如果原型對象上也找不到呢?
首先看看 person1 原型對象目前長啥樣
console.log(person1.__proto__)看一下控制臺打印:
?我們應該可以猜到,原型對象也是對象,在原型對象上沒找到,那就繼續往上去找!
我們來看看原型的原型是什么
console.log(person1.__proto__.__proto__)看一下控制臺打印:
?這一眼看過去,好像也不知道是什么,但你是否記得上面提到過的:
每個原型對象都有一個 constructor 屬性指向關聯的構造函數
我們訪問原型的原型的 constructor 屬性試試
console.log(person1.__proto__.__proto__.constructor) // ? Object()沒想到吧,實例對象原型的原型就是 Object 的原型對象,其實Object是原型的頂層原型對象
因為是頂層原型對象,它的__proto__指向null。
console.log(person1.__proto__.__proto__.__proto__) // null借用冴羽老師的一張圖就清楚其中的關系了:
圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線。
簡單來說就是,找 person1 對象某個屬性沒找到,就通過__proto__訪問原型一層一層地找,直到找到這個屬性或者到 null 位置結束,相互關聯的原型就構成了原型鏈。這樣是不是也不難理解。
三.擴展
通過上面的知識我們知道了,構造函數 Person 的prototype也被稱為顯式原型,實例對象 person 的__proto__也被稱為隱式原型
即構造函數的顯式原型和實例對象的隱式原型是同一個對象
function Person() { } const person = new Person() ? Person.prototype === person.__proto__ // true那么構造函數的隱式原型__proto__指向什么呢?
指向Function的原型,即
Person.__proto__ === Function.prototype // true Object.__proto__ === Function.prototype // true大家有時間可以看看這篇文章:https://juejin.cn/post/7064188728704499726
里面這位老哥有更詳細的解讀,本文如果有錯誤的話也歡迎大家來指正。
總結
- 原型對象的本質其實就是一個對象
- 原型的作用是給其他對象提供共享屬性,即用來實現基于原型的繼承與屬性的共享
- 相互關聯的原型組成的鏈狀結構就是原型鏈
- 原型鏈的頂級原型對象是Object,且最終一定指向 null
總結
- 上一篇: Socket中EndPoint只获取ip
- 下一篇: iOS流量精灵完结版