JavaScript中的原型(Prototype)機制是其面向對象編程的核心特性之一,它允許對象之間共享屬性和方法,從而實現(xiàn)繼承。本文將從淺入深地解析原型、原型鏈、以及一些特殊情況下的應用,旨在讓你對這一概念有更清晰的理解。
原型(顯示原型)
每個JavaScript函數(shù)都有一個名為prototype
的屬性,這是一個對象,用于存儲所有通過該函數(shù)構造出的對象所共享的屬性和方法。當使用new
關鍵字基于某個構造函數(shù)創(chuàng)建一個實例化對象時,這個實例化對象會自動鏈接到構造函數(shù)的prototype
對象上,這便是原型繼承的基礎。而該原型指的是函數(shù)的原型prototype
。
function Person() {}
Person.prototype.say = function() { console.log('Hello'); };
在這個例子中,所有通過new Person()
創(chuàng)建的實例化對象都會繼承構造函數(shù)的原型上的say
方法。
隱式原型和原型鏈
每個JavaScript對象(除null
外)都有一個內部屬性[[Prototype]]
,通常可以通過__proto__
訪問(隱式原型__proto__
指向的是對象的顯示原型prototype
)。當訪問一個對象的屬性或方法時,如果對象本身沒有,則引擎會繼續(xù)在其[[Prototype]]
指向的對象中尋找,這一過程形成了一條鏈,即原型鏈。
對于p
來說,其原型鏈上首先查找自身的屬性,若未找到,則會沿著p.__proto__ -> Person.prototype -> Object.prototype -> null
這條鏈進行查找。
也就是說,v8在查找對象的屬性時,如果沒找到,就會順著對象的隱式原型往上查找,如果還找不到,再順著隱式原型的隱式原型往上找,直到找到null為止,在這個過程中,但凡有一個步驟能找到,就會返回值。這個鏈狀的查找過程稱為原型鏈
是不是所有的對象都有原型??
答案當然是,并非所有對象都有原型。使用Object.create(null)
可以創(chuàng)建一個沒有原型(__proto__
會指向null
)的對象,這樣的對象不會繼承任何默認的Object方法。
修改原型的屬性
實例化對象是不可以修改原型上的屬性的
Person.prototype.like = '聽歌';
let p = new Person();
p.like = '擼鐵';
let s = new Person()
console.log(p)
console.log(s.like)
由后面實例化出來的s
對象中可以看出,當執(zhí)行p.like
的時候,并不是修改原型上的屬性,而是在p
對象上添加一個like
屬性并賦值為擼鐵
。
多級繼承示例
多級繼承展示了如何通過原型鏈實現(xiàn)深層次的屬性和方法繼承,每個子類通過其原型鏈連接到父類的原型。
Grand.prototype.lastname = '張';
function Grand(){
this.name='三'
}
Father.prototype=new Grand()
function Father(){
this.age=40
}
Son.prototype=new Father()
function Son(){
this.like='coding'
}
let son = new Son();
// console.log(son.like)
// console.log(son.age)
console.log(son.name)
下面我將描述出輸出son.name
時的查找路線:
原型鏈的實踐與注意事項
修改數(shù)組的push
方法展示了原型鏈上方法覆蓋的原理。
// var arr=[1,2,3]
// arr.push(4)//1,2,3,4
// 原型鏈
Array.prototype.push = function(){
this[0]='a'
}
var arr=[1,2,3] // new Array() --> this
arr.push(4)
console.log(arr)//4,2,3
Number.prototype.toString
等內建原型方法的調用,說明了即使是最基本的數(shù)據(jù)類型也是基于原型鏈實現(xiàn)方法訪問的。
var num=1// new Number()
console.log(num.toString())
構造函數(shù)與原型對象的區(qū)分
構造函數(shù)本身也是一個對象,它有自己的屬性和方法,這些不通過原型鏈傳遞給實例。例如,Foo.b=2
設置的是構造函數(shù)的靜態(tài)屬性,而非原型屬性。
Foo.prototype.a=1
function Foo() {
// this={
// }
// this.__proto__ = Foo.prototype
// return this
// b=2
}
Foo.b=2
console.log(Foo);//{b:2}
let f = new Foo();
console.log(f.b);//undefined
最后
總的來說,JavaScript的原型和原型鏈機制提供了一種靈活而強大的對象繼承方式。理解這一機制對于深入掌握JavaScript的面向對象編程至關重要。通過上述示例的逐步分析,我們不僅看到了原型如何讓對象共享屬性和方法,還見識到了原型鏈如何構建起對象間屬性查找的路徑。這將會使我們更好的理解為什么可以調用不屬于他身上的屬性和方法,便于我們更好的掌握這一門編程語言!!
作者:常樂hhh
鏈接:https://juejin.cn/post/7379897208532926518
來源:稀土掘金
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。
該文章在 2024/6/17 16:32:31 編輯過