本文是筆者看完《JavaScript面向對象編程指南》後的一些理解與感悟,僅是對JavaScript原型與多種繼承進行思路上的梳理,並不是講解基礎知識,適合瞭解原型和繼承,卻不夠清晰透徹的開發者。
但願各位開發者可以經過閱讀這篇文章縷清原型和構造函數的脈絡javascript
觀察如下代碼java
function Person (){ this.age = 20; } Person.prototype.gender = 'male'; var tom = new Person(); tom.name = 'tom'; console.log(tom.name); // tom console.log(tom.age); // 20 console.lot(tom.gender); // male tom.constructor === Person; // true tom.__proto__ === Person.prototype; // true
function Dog(){ this.tail = true; } var benji = new Dog(); var rusty = new Dog(); // 給原型添加方法 Dog.prototype.say = function(){ return 'woof!'; } benji.say(); // "woof!" rusty.say(); // "woof!" benji.constructor === Dog; // true rusty.constructor === Dog; // true // 此時,一切正常 Dog.prototype = { paws: 4, hair: true }; // 徹底覆蓋 typeof benji.paws; // "undefined" benji.say(); // "woof!" typeof benji.__proto__.say; // "function" typeof benji.__proto__.paws; // "undefined" // 原型對象不能訪問原型的"新增屬性",但依然經過神祕的鏈接 __proto__ 與原有原型對象保持聯繫 // 新增實例 var lucy = new Dog(); lucy.say(); // TypeError: lucy.say is not a function lucy.paws; // 4 // 此時 __proto__ 指向了新的原型對象 // 因爲constructor是存儲在原型對象中的,因此新實例的constructor屬性就不能再保持正確了,此時它指向了Object() lucy.constructor; // function Object(){[native code]} // 舊實例的constructor仍是正確的 benji.constructor; /* function Dog(){ this.tail = true; }*/ // 若想讓constructor正確,必須在新的原型對象中設置constructor屬性爲Dog Dog.prototype.constructor = Dog;
constructor
屬性在Person.prototype
對象中,即原型對象中。__proto__
屬性是在 tom(實例)
被 new
的一瞬間創建的,指向原型對象即 Person.prototype
tom.constructor
等同於 tom.__proto__.constructor
訪問到的__proto__
屬性只能在學習或調試的環境下使用var tom = new Person()
執行時,首先開闢一個新的地址空間用來建立並存放tom對象
,再使Person
的this
指向tom對象而且執行Person
函數。constructor
屬性,不可控。