上一篇隨筆主要講了變量提升的問題,今天我們來講講很多前端er在初期很長一段時間內都沒有完全搞明白的原型鏈和構造函數。
1,什么是構造函數
那么要講到構造函數,必須要有一個函數,所以我們建立一個函數
function Person(){}
ok,既然是構造函數,那么久要有參數和返回值
Person = function(name,age,force){
this.name = name; this.age = age; this.force = force; }
一個函數就出來了,接下來我們來看一下這個Person的__proto__和prototype
Person.prototype //Object {constructor:function(name,age,force),__proto__:Object}
Person.__proto__ //function(){}
好的,我們的構造函數完成了,現在我們來通過構造函數創建一個對象
var mike = new Person('mike',23,'strong');
mike //Person {name: "mike", age: 23, force: "strong"}
mike.prototpe //undefined
mike.__proto__ //Object {constructor:function(name,age,force),__proto__:Object}
在上面2段代碼,我們可以發現很多,仔細觀看mike.__proto__和Person.prototype,是不是發現,這兩者其實是一個東西,我們待會驗證一下,並且發現mike.prototype是undefined
alert(mike.__proto__ === Person.prototype) //true
這樣我們大概就了解了,構造函數new Person()發生時候的一個過程
創建mike對象;
mike.__proto__ = Person.prototype;
Person.call(mike,'mike',23,'strong');
2,__proto__和prototype
__proto__按照定義來講,是對象自帶的一個屬性,這個__proto__它本身又是一個對象,__proto__的屬性,可以被mike讀取到,但不會顯示在mike對象里,當然__proto__對象中的屬性讀取優先級要低於mike本身
而prototype呢,則是函數的一個自帶屬性,其中prototype又有兩個元素,1,constructor指向函數本身,2,__proto__同對象中的__proto__
構造函數在創建對象是最大的特點就是會把自身的prototype按值傳遞給被構造對象的__proto__,因為prototype可以當做對象來看,所以是按引用傳遞//糾正上次的一個錯誤
暫時我知道的prototype的作用,就是在構造對象時,將自身的prototype(引用)傳遞給新函數的__proto__
3,原型鏈
這里我可以舉個例子
1 mike //Person {name: "mike", age: 23, force: "strong"}; 2 mike.__proto__face = 'handsome'; 3 mike //Person {name: "mike", age: 23, force: "strong"} 4 mike.face //'handsome'
mike對象中沒有face屬性,所以往mike.__proto__中找face,找到了,顯示出來,找不到的話,往mike.__proto__.__proto__中找face,如此往復,直到某一個__proto__返回null
4,多次繼承
function One(){ this.sayOne = function(){ alert('nameOne'); } } function Two(){}; Two.prototype = new One(); Two.prototype.sayTwo = function(){ alert('nameTwo'); } var say = new Two(); say.sayOne() //‘nameOne’ say.sayTwo() //‘nameTwo’ two.prototype //one(sayOne:function(){},sayTwo:function(){})
原理很簡單 Two.prototype = new One(); 這一步得到 Two.prototype.__proto__ = One.prototype;
say.__proto__ = Two.prototype;
所以say.__proto__.__proto__ = One.prototype;
所以say.sayTwo = say.__proto__.sayTwo = Two.prototype.sayTwo ;
One.call(Two.prototype);
say.sayOne = say.__proto__.sayTwo = Two.prototype.sayOne;
要完成多次繼承,只要將上一層的屬性實例化到下一層的prototype即可,因為prototype是可以作為對象的__proto__直接使用的!