构造函数、实例、原型对象、继承
一、構造函數與原型對象之間的關系:
有一個Star構造函數,每一個構造函數里面都有一個原型對象,是通過構造函數的prototype指向這個原型對象的
同樣在這個原型對象里面也有一個屬性叫constructor,它又指回了構造函數
可以把構造函數看為是父親,父親通過prototype指向兒子原型對象,告訴別人看我有一個厲害的兒子叫原型對象,而原型對象里面又有一個屬性constructor,又指回了構造函數說,看我有一個厲害的老爹,兩人互相吹捧了一番
二、構造函數、實例對象與原型對象之間的關系:
我們可以通過構造函數創建一個實例對象,只要new了構造函數就可以產生一個實例對象,所以構造函數又可以指向這個對象實例,我們知道在這個實例對象中也有一個原型__proto__,這個__proto__指向的是Star原型對象,當然了我們對象實例里面也有一個constructor,它可以指回構造函數
三、原型鏈
只要是對象就有__proto__原型,指向原型對象
原型對象里面的__proto__原型指向的是Object.prototype
function Star(uname,age){this.uname = uname;this.age = age; } Star.prototype.sing = function(){console.log("我會唱歌"); } var zxz = new Star('張信哲',18); // 只要是對象就有__proto__原型,指向原型對象 console.log(Star.prototype); console.log(Star.prototype.__proto__ === Object.prototype);// true // 我們Star原型對象里面的__proto__原型指向的是Object.prototype console.log(Object.prototype.__proto__); // 我們的Object.prototype原型對象里面的__proto__原型 指向為null四、JavaScript對象成員查找機制(規則)
-
當訪問一個對象的屬性(包含方法)時,首先查找這個對象自身有沒有該屬性
-
如果沒有就查找它的原型(也就是__proto__指向的prototype原型對象)
-
如果還沒有就查找原型對象的原型(Object的原型對象)
-
依次類推一直找到Object為止(null)
-
__proto__對象原型的意義就在于為對象成員查找機制提供一個方向或者說一條路線。
五、利用原型對象擴展內置對象
可以通過原型對象,對原來的內置對象進行擴展自定義的方法。比如給數組增加自定義求偶數和的功能。
注:數組和字符串內置對象不能給原型對象覆蓋操作Array.prototype = {},只能是Array.prototype.xxx = function(){}的方式。
Array.prototype.sum = function(){var total = 0for(var i=0;i<this.length;i++){total += this[i]}return total; } var arr = [5,6,7]; arr.sum(); // 18六、繼承
ES6之前并沒有給我們提供extends繼承,我們可以通過構造函數+原型對象模擬實現繼承,被稱為組合繼承,用原型鏈實現對原型屬性和方法的繼承,借用構造函數技術來實現實例屬性的繼承。
1、借用構造函數繼承父類型屬性
核心原理:通過call()把父類型的this指向子類型的this,這樣就可以實現子類型繼承父類型的屬性。
call() 作用:調用這個函數并且修改函數運行時this的指向
fun.call(thisArg,arg1,arg2,...)thisArg:當前調用函數this的指向對象
arg1,arg2:傳遞的其他參數
function fn(x,y){console.log(this);console.log("我想出去玩");console.log(x+y) } var obj = {name:"萌小七" } fn();// this指向的是window,我想出去玩 // call()可以調用函數 fn.call();// this指向的是window,我想出去玩 // call() 可以改變這個函數的this指向,此時這個函數的this就指向了obj這個對象 fn.call(obj,1,2);// {name: "萌小七"} 我想出去玩 3舉例說明:借用父構造函數繼承屬性
function Father(name,age){// this指向父構造函數的對象實例this.name = namethis.age = age } function Son(name,age,score){// this指向子構造函數的對象實例Father.call(this,name,age)this.score = score } var son = new Son("小丸子",18,98) console.log(son); // 輸出:Son {name: "小丸子", age: 18, score: 98}此時子構造函數繼承了父構造函數的屬性
2、利用原型對象繼承方法: Son.prototype = new Father();
function Father(name,age){// this指向父構造函數的對象實例this.name = namethis.age = age } function Son(name,age,score){// this指向子構造函數的對象實例,構造函數來復制父類的屬性給Son實例Father.call(this,name,age)this.score = score } Father.prototype.money = function(){console.log("父親要掙錢") } // Son.prototype = Father.prototype // 這樣直接賦值會有問題,如果修改了子原型對象,父原型對象也會跟著一起改變 Son.prototype = new Father(); // 如果利用對象的形式修改了原型對象,別忘了利用constructor指回原來的原型對象 Son.prototype.constructor = Son Son.prototype.school = function(){console.log("孩子要上學") } var son = new Son("小丸子",18,98) console.log(son); console.log(Father.prototype);
優點:
父類的方法可以被復用
父類的引用屬性不會被共享
子類構建實例時可以向父類傳遞參數
缺點:
第一次調用Father():給Son.prototype寫入兩個屬性name,age。
第二次調用Father():給instance1寫入兩個屬性name,age。
實例對象son上的兩個屬性就屏蔽了其原型對象Son.prototype的兩個同名屬性。所以,組合模式的缺點就是在使用子類創建實例對象時,其原型中會存在兩份相同的父類實例的屬性/方法。這種被覆蓋的情況造成了性能上的浪費。
寄生組合繼承(最優方案)
組合繼承會有兩次調用父類的構造函數而造成浪費的缺點,寄生組合繼承就可以解決這個問題。
核心在于inheritPrototype(son, father),讓子類的prototype指向父類原型的拷貝,這樣就不會調用父類的構造函數,進而引發內存的浪費問題。
function inheritPrototype(son, father) {// 修正子類原型對象指針,指向父類原型的一個副本 (用object()也可以) son.prototype = Object.create(father.prototype)// 增強對象,彌補因重寫原型而失去的默認的constructor屬性son.prototype.constructor = son } function Father(name,age){ // this指向父構造函數的對象實例 this.name = name this.age = age } function Son(name,age,score){ // this指向子構造函數的對象實例,構造函數來復制父類的屬性給Son實例Father.call(this,name,age) this.score = score } Father.prototype.money = function(){console.log("父親要掙錢") } inheritPrototype(Son, Father) Son.prototype.school = function(){ console.log("孩子要上學") } var son = new Son("小丸子",18,98) console.log(son); console.log(Father.prototype);
【轉載】https://mp.weixin.qq.com/s/FZTgakDp-jQc1Ic4NT7WYg
總結
以上是生活随笔為你收集整理的构造函数、实例、原型对象、继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蟑螂也可以入药?!
- 下一篇: Linux里怎么进行路由跟踪,[Linu