簡述js原型鏈
基本概念
1.、js的物件可以分為函式物件和普通物件,每個物件都有proto屬性,但是隻有函式物件才有prototype屬性(prototype=原型物件)
2、Object是最高階的函式物件,Function、Array、RegExp、Date、Boolean、Number、String等等是第二高階的函式物件,我們自己手寫的function是再低一級的函式物件
3、proto是一個物件,它指向某一個prototype,並且有2個屬性:constructor和proto
原型鏈的作用
1、共享屬性(面向開發者)
先來看第一種寫法
function Person(name) { this.name = name } var p1 = new Person('x') p1.sayName = function() { console.log(this.name) } var p2 = new Person('y') p2.sayName = function() { console.log(this.name) }
我們聲明瞭一個建構函式Person,併為它的2個例項都定義了sayName方法
如果我們希望所有的例項都有sayName方法,減少重複的定義
可以像下面這麼寫:(第二種寫法)
function Person(name) {
this.name = name
this.sayName() = function() {
console.log(this.name)
}
}
var p1 = new Person('x')
var p2 = new Person('y')
我們在建構函式Person中定義了一個數據成員和一個函式成員
每當我們創造一個新的Person例項時,都會在記憶體中單獨為它分配私有的空間
也就是說,p1和p2都有自己的name屬性和sayName方法
這個name屬性和sayName方法是例項自己私有的
在控制檯直接列印p1得到如下結果:(第一、第二種寫法是等價的)
再來看第三種寫法:
function Person(name) {
this.name = name
}
Person.prototype.sayName = function(){
console.log(this.name)
}
var p1 = new Person('x')
var p2 = new Person('y')
這樣的話,每個Person例項依然都會有name屬性和sayName方法
不同的地方在哪呢?
在控制檯直接列印p1得到如下結果:
不難發現,當前這種寫法是將sayName定義在Person的原型物件上的
也就是說,sayName方法不再是每個Person例項私有的,而是所有Person例項共享的
這樣做 既不影響每個例項列印/輸出自己的name值,又可以節省記憶體
2、面向編譯器
function Person(name) {
this.name = name
}
Person.prototype.sayName = function(){
console.log(this.name)
}
var p1 = new Person('x')
p1.sayName()
還是相同的例子
當我們在程式中呼叫 p1.sayName方法時,編譯器會沿著原型鏈(自底向上)地尋找原型物件上是否有這個方法
如上圖所示,編譯器會先從p1自身(最外層)開始找
然後去 p1.proto(即Person的原型物件 = 外層紅色方框)裡面找
最後再到 p1.proto.proto(即Object的原型物件 = 內層紅色方框)裡面找