若是你們想深刻學習Javascript編程語言,Javascript中的原型及原型鏈是必須掌握的。當初我在學習原型及原型鏈的時候,就遇到過很多阻礙,但願經過個人這篇文章,可以讓你真正的掌握JavaScript中的原型及原型鏈。好啦,開始咱們的原型及原型鏈的旅途吧~
在介紹Javascript原型以前,咱們先來了解一段歷史。chrome
1994年,網景公司發佈了Navigator瀏覽器0.9版,當時這個版本的瀏覽器只能用來瀏覽,並不具備與用戶用戶進行互動的功能,好比說,要判斷用戶是否填寫了表單數據,只能經過服務器來進行判斷,這樣會帶來一個弊端:極大的浪費了帶寬以及服務器資源。在這種狀況下,就須要一種腳本語言,這種語言可以與瀏覽器進行交互,Brendan Eich負責開發這種腳本語言(也就是Javascript),當時,這位工程師認爲這種腳本語言不須要設計的太複雜,只需完成簡單操做便可,好比判斷用戶是否填寫了表單數據。此時,咱們還要了解下當時的編程語言背景,在1994年的時候,C++是最興盛的面向對象的編程語言,Java1.0也將於第二年推出,Brendan Eich也將Javascript設計爲面向對象的語言,在Javascript中一切皆對象。當時,他遇到了一個難題,到底需不須要將繼承機制引入Javascript中?最終的結果是,也許他受到了C++和Java的影響,繼承機制最終被引入到Javascript編程語言中。編程
下面咱們來看看在C++中生成一個對象的方法:瀏覽器
A *a=new A(param);
而在Java中生成一個對象的方法:服務器
Foo foo=new Foo();
咱們再來看看Javascript生成一個對象的方法:微信
function Dog(name){ this.name=name; }
var dogA = new Dog("旺旺");
alert(dogA.name);//旺旺
咱們再來看看Javascript中另一種寫法:編程語言
function Dog(name){ this.name=name; this.species ="犬科"; } var dogA = new Dog("旺旺"); dogA.species="貓科"; var dogB = new Dog("旺旺2"); alert(dogB.species);//犬科
在這個例子中,生成了兩個對象dogA與dogB,dogA修改了species,可是咱們訪問dogB的species,仍是原來的值。因而,咱們能夠看出經過這種方法生成的實例對象,每一個對象都有本身的屬性和方法的副本,實例對象間不能作到屬性的方法的共享,這樣帶來的一個缺點就是極大的浪費了系統的資源。有沒有改進的方法呢?有,確定有!函數
考慮到上面的不足,這位工程師決定給每一個構造函數添加一個prototype屬性,這個屬性指向一個對象,稱爲prototype對象。在Javascript中,一切皆對象,對象能夠分爲三類:實例對象(經過new和構造函數建立出來的對象)、函數對象(通常也稱爲函數)、原型對象(函數對象的prototype屬性所指向的對象)。咱們首先來看下實例對象中的屬性和方法,以下圖:學習
實例一旦建立,將自動引用prototype對象的方法和屬性,也就是說,針對實例對象而言,它的屬性和方法能夠分爲兩種:一種是本地的,另一種是引用的。this
prototype、_proto_和constructor三角關係spa
我將用下面的一副圖來描述三者的關係:
我將上幅圖總結爲下面幾點內容:
任何對象都有一個隱藏的_proto屬性,它是對原型對象的引用;
必定要牢記上面的幾點內容,它將對後面的內容很是重要。
說明:後面的實例,若是看不懂,能夠再看看前面的內容,好好理解下前面的內容,必定能夠理解後面的例子的。同時,下面的例子運行結果我會有必定的解釋。
step1:查看對象的原型
function Person(name, age){ this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } } var will = new Person("Will", 28); console.log(will.__proto__); console.log(will.constructor);
運行結果:
解釋:will對象自己並無"constructor"這個屬性,可是經過原型鏈查找,找到了will原型(will.__proto__)的"constructor"屬性,並獲得了Person函數
對象之間的關係:
step2:查看對象will原型的原型
function Person(name, age){ this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } } console.log(will.__proto__ === Person.prototype); console.log(Person.prototype.__proto__); console.log(Person.prototype.constructor); console.log(Person.prototype.constructor === Person);
運行結果:
對象之間的關係
step3:查看對象Object的原型
function Person(name, age){ this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } } console.log(Person.prototype.__proto__ === Object.prototype); console.log(typeof Object); console.log(Object); console.log(Object.prototype); console.log(Object.prototype.__proto__); console.log(Object.prototype.constructor);
運行結果:
對象之間的關係:
step4:查看函數對象的原型
function Person(name, age){ this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } } console.log(Person.__proto__ === Function.prototype); console.log(Person.constructor === Function) console.log(typeof Function); console.log(Function); console.log(Function.prototype); console.log(Function.prototype.__proto__); console.log(Function.prototype.constructor);
運行結果:
對象之間的關係:
step1:最老的方式
function Person(name, age){ this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } } var will = new Person('Will',28); var wilber = new Person("Will", 20);
對象之間的關係:
step2:經過原型prototype實現繼承
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); }
對象之間的關係:
什麼是原型鏈?
因爲_proto_是任何對象都有的屬性,而Javascript中萬物皆對象,因此會造成一條_proto_鏈接起來的鏈條,遞歸訪問_proto_必須最終到頭,而且值爲null。
原型鏈有什麼做用?
屬性查找與隱藏:當Javascript引擎查找對象的屬性時,先查找對象自己是否存在該屬性,若是不存在,再沿着_proto_這條鏈向上查找,但不會查找自身的prototype。
var A = function(){}; var a = new A();
以上面的這幅圖爲例,查找某個屬性的時候,會沿着這條原型鏈進行查找,直到爲null。
原型鏈之屬性查找
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.MaxNumber = 9999; Person.__proto__.MinNumber = -9999; var will = new Person("Will", 28); console.log(will.MaxNumber);// 9999 console.log(will.MinNumber);//undefined
原型鏈之屬性隱藏
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); } var will = new Person("Will", 28); will.getInfo = function(){ console.log("getInfo method from will instead of prototype");// }; will.getInfo();
對象建立方式影響原型鏈的構成
var July = { name: "July", age: 28, getInfo: function(){ console.log(this.name + " is " + this.age + " years old"); }, } console.log(July.getInfo());
hasOwnProperty
var will = new Person('Will',28); var wilber = new Person("Will", 20); for(var attr in will){ console.log(attr); } console.log('---------------'); for(var attr in wilber){ if(will.hasOwnProperty(attr)){ console.log(attr); } }
歡迎關注個人微信公衆號。您的支持將鼓勵我繼續創做!