物件
1 function f1(){ 2 }; 3 typeof f1 //"function"函式物件 4 5 6 var o1 = new f1(); 7 typeof o1 //"object"普通物件 8 9 var o2 = {}; 10 typeof o2 //"object"普通物件
JavaScript中將物件分為普通物件和函式物件。
使用函式物件可以建立普通物件,普通物件沒法建立函式物件。
凡是通過new Function建立的物件都是函式物件,其他都是普通物件(通常通過Object建立),可以通過typeof來判斷。
原型物件(prototype)
Prototype
Prototype有原型、藍本的意思,只有函式物件才會有原型(prototype)。
所謂原型,就是函式用來建立例項(普通)物件的藍本(原型)。
每個原型都有一個 constructor 屬性指向關聯的建構函式。
__proto__
每一個JavaScript物件(除了 null )都具有的一個屬性,叫__proto__,這個屬性會指向該物件的原型(prototype)。
constructor
建構函式,即用來建立例項的函式,即關聯的函式物件本身。
驗證
在火狐或者谷歌瀏覽器控制檯中新建一個普通物件,檢視他的屬性。
1 var o = {}; 2 console.log(o.prototype); //undefined 普通物件沒有prototype屬性 3 console.log(o instanceof Object); //true o是Object的例項 4 console.log(o.__proto__ === Object.prototype) //true o的__proto__指向Object的prototype 5 console.log(Object === Object.prototype.constructor) //true Object.prototype.constructor指向Object本身 6 console.log(Object.prototype.constructor) //function Object() 函式物件原型的建構函式指向這個函式 7 console.log(Object.prototype.__proto__); //null Object.prototype的__proto__為null,為原型鏈終點
新建一個函式物件,檢視他的屬性。
1 function Demo() { }; 2 var f1 = new Demo(); 3 console.log(f1.prototype); //undefined 通過函式物件穿建立的是普通物件,Demo本身是函式物件 4 console.log(f1 instanceof Demo); //true f1是Demo的例項 5 console.log(f1.__proto__ === Demo.prototype); //true 6 console.log(Demo === Demo.prototype.constructor);//true 7 console.log(Demo.prototype.__proto__ === Object.prototype);//true Demo原型的__proto__指向Object的原型prototype 8 console.log(Object.prototype.__proto__); //null
原型的重要功能就是用作繼承。
原型鏈(prototype chain)
javascript中,每個物件都會在內部生成一個__proto__ 屬性,當我們訪問一個物件屬性時,如果這個物件不存在就回去__proto__ 指向的物件裡面找,一層一層找下去,這就是javascript原型鏈的概念。
提升:
- 在原型鏈上查詢屬性比較耗時,對效能有副作用,這在效能要求苛刻的情況下很重要。另外,試圖訪問不存在的屬性時會遍歷整個原型鏈。
- 遍歷物件的屬性時,原型鏈上的每個可列舉屬性都會被列舉出來。要檢查物件是否具有自己定義的屬性,而不是其原型鏈上的某個屬性,則必須使用物件從Object.prototype繼承的 hasOwnProperty 方法。(使用 for in 遍歷物件時推薦總是使用 hasOwnProperty 方法)
繼承
JavaScript 並沒有其他基於類的語言所定義的“方法”。在 JavaScript 裡,任何函式都可以新增到物件上作為物件的屬性。函式的繼承與其他的屬性繼承沒有差別。
繼承意味著複製操作,在Java和C#中,繼承是完全複製生成新的物件。然而 JavaScript 預設並不會複製物件的屬性,相反,JavaScript 只是在兩個物件之間建立一個關聯,這樣,一個物件就可以通過委託訪問另一個物件的屬性和函式,所以與其叫繼承,委託的說法反而更準確些。
結論
在編寫使用它的複雜程式碼之前,理解原型繼承模型是至關重要的。此外,請注意程式碼中原型鏈的長度,並在必要時將其分解,以避免可能的效能問題。此外,原生原型不應該被擴充套件,除非它是為了與新的JavaScript特性相容。
參考文件: https://www.jb51.net/article/123976.htm
https://github.com/mqyqingfeng/Blog/issues/2
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain