您好,登錄后才能下訂單哦!
這篇文章主要介紹“JavaScript原型與原型鏈是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“JavaScript原型與原型鏈是什么”文章能幫助大家解決問題。
什么是原型?原型是 JS 基礎學習中我們沒有提及的概念,原型它是一個泛指,主要包含了 原型對象 (prototype) , 對象原型 (__proto__), 原型鏈 等等。
我們學習過很多面向對象的語言,例如 java c++ 等等,但是 JavaScript 是個例外,在 ES6 之前,是沒有類的概念的,那在之前我們如何創建對象呢?原來在 ES6 之前,我們是利用 構造函數 來創建實例化對象的,構造函數是一種特殊的函數,包含了對象的公共特征,要配合 new 一起使用才有意義。
構造函數名的首字母要大寫
構造函數要配合 new 一起使用
<script> function Animal(name,age){ //構造函數名首字母大寫 this.name=name; this.age=age; this.eat=function(){ console.log('我在吃東西'); } } var dog=new Animal('旺財',3) //要配合 new 一起使用創建對象 console.log(dog.name); console.log(dog.age); dog.eat() </script>
new 的時候會創建一個空對象
構造函數內的 this 指向這個空對象
執行構造函數內的代碼給空對象賦值,添加屬性方法
返回這個對象
實例成員就是觀戰屬內部用 this 添加的成員
實例成員只能通過實例化的對象調訪問,不能通過構造函數名訪問
<script> function Animal(name,age){ this.name=name; this.age=age; } var dog=new Animal('旺財',3) console.log(dog.name); console.log(Animal.name); </script>
靜態成員就是通過構造函數本身創建的成員
靜態成員只能通過構造函數名訪問,不能通過實例化對象訪問
<script> function Animal(name,age){ this.name=name; this.age=age; } var dog=new Animal('旺財',3) Animal.color='黑色' console.log(Animal.color); console.log(dog.color); </script>
在開始將原型對象是什么前,我們先說明一個案例,還是剛才的那個 Animal 類,我們創建了多個實例化對象,輸出其實例化對象的兩個方法的比較,我們發現輸出了 false,即二者的這個復雜數據類型的地址不同,什么原因呢?
<script> function Animal(name,age){ this.name=name; this.age=age; this.eat=function(){ console.log('我在吃東西'); } } var dog=new Animal('旺財',3) var cat=new Animal('咪咪',3) var pig=new Animal('哼哼',3) var fish=new Animal('咕嚕',3) var sheep=new Animal('咩咩',3) console.log(dog.eat==cat.eat); </script>
在我們創建實例化對象的過程中,new 的過程首先會創建一個新對象,但是復雜數據類型會領開辟一塊空間存放(對象,方法),這就造成了構造函數內同樣的方法被開辟了無數塊內存,造成了內存的極度浪費
構造函數原型 prototype 是構造函數內的一個屬性,其屬性是一個指針,指向一個對象,這個對象內存放的就是公共的方法,存在這個對象里的方法,再通過構造函數創建實例化對象時就可以公共利用這一個方法了,不需要再對多個相同的復雜數據類型開辟多個重復的內存空間。就是為了解決上述存在的內存浪費的問題,其也可以直接稱為原型對象。
解決方案我們使用原型對象存放公共方法,并且讓實例化對象調用該方法,并且比較二者的地址是否相同
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype.eat=function(){ console.log('我在吃東西'); } var dog=new Animal('旺財',3) var cat=new Animal('咪咪',3) dog.eat() cat.eat() console.log(dog.eat==cat.eat); </script>
我們發現不但成功調用了這個方法,而且二者調用方法的地址是相同的,這就證明了,其公共的復雜數據類型只開辟了一塊內存空間,減少了之前公共方法寫在構造函數內部資源浪費的問題。
對象原型__proto__的作用是讓你搞清楚一個問題:為什么給構造函數的prototype屬性添加的方法,實例化對象卻可以使用?這是因為每一個對象都有一個 __proto__屬性(注意前后都是兩個下劃線),這個屬性也是一個指針,指向的是其對應構造函數的原型對象 prototype,這就解釋了為什么實例化的對象可以去調用原型對象里的方法。
原型對象prototype 等價于 對象原型 __proto__
我們要注意對象原型__protp__的作用僅僅是為了給查找原型對象內的內容提供一個方向,我們不需要使用它,只需要記住它指向對應的構造函數的原型對象 prototype 即可
首先去找實例化自身的構造函數身上有沒有目標方法,有則調用
如果自身構造函數身上沒有,由于因為對象自身有屬性__protp__,其指向構造函數的原型對象prototype,則會去找原型對象身上有沒有該方法
對象原型 __proto__ 身上和構造函數的原型對象 prototype 身上都有一個 constructor 屬性,之所以叫 constructor 叫構造函數,是因為這個屬性指向的是對應的構造函數本身,其主要用于記錄實例化的對象引用于哪一個構造函數
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype.eat=function(){ console.log('我在吃東西'); } var dog=new Animal('旺財',4) console.log(dog.__proto__.constructor); console.log(Animal.prototype.constructor); </script>
我們發現打印出來結果確實為構造函數本身
更多時候我們需要手動返回 constructor 指向的哪個構造函數,例如構造函數的原型對象中以對象的形式存入多個公共方法時,就會出現以下情況:
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype={ eat:function(){ console.log('我在吃東西'); }, run:function(){ console.log('我在跑'); } } var dog=new Animal('wangchai',3) console.log(Animal.prototype.constructor); console.log(dog.__proto__.constructor); </script>
我們發現其找不到對應的構造函數了,這是因為我們給其原型對象添加方法的添加方式導致的,這錢我們采取的以.方式添加,是在原有基礎上追加添加的,不會覆蓋掉內部原有的內容。而我們采用=的方法以對象形式添加,其實是一個賦值的過程,將原有內容也給覆蓋掉了,這就導致 prototype 內部原有的 constructor 方法被覆蓋掉了
這時就需要我們手動返回 constructor 來找到返回的是哪個的構造函數
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype={ constructor:Animal, eat:function(){ console.log('我在吃東西'); }, run:function(){ console.log('我在跑'); } } var dog=new Animal('wangchai',3) console.log(Animal.prototype.constructor); console.log(dog.__proto__.constructor); </script>
這樣我們就可以成功拿到其 constructor 指向的哪個構造函數了
constructor : 構造函數名
關于“JavaScript原型與原型鏈是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。