說實話js這門語言以前沒有仔細研究過,現在研究起來感覺好麻煩,對於原型鏈這個說法我也是剛接觸不久,就試着說說我的理解吧!
關於上一篇我們說了js整個函數體系結構,想了解的可以點擊這里,這里隨便找到一些對原型的小測試,你可以看看會不會,其中Person是一個構造函數,person1是構造函數的一個實例;
person1.__proto__ 是什么?//person1.__proto__ == Person.prototype
Person.__proto__ 是什么?//Person.__proto__ == Function.prototype
Person.prototype.__proto__ 是什么?//Person.prototype.__proto__ == Object.prototype
Object.__proto__ 是什么?//Object.__proto__ == Function.prototype
Object.prototype__proto__ 是什么?//Object.prototype__proto__ == null
知道了這些就差不多了,我們繼續看;
1.特殊的Math和JSON
這兩個內置對象有點不同,上次還沒有注意看,因為其他的內置對象都是Function的實例,比如Date,Number等,舉個例子:
Date instanceof Function //true Date.constructor == Function //true Date.__proto__ == Function.prototype //true
但是當我們用Math對象和JSON對象測試的時候確實false,其實可以把Math和JSON對象看作Object的實例:
//Math和JSON一樣,這里以Math為例
Math instanceof Object //true Math.constructor == Object //true Math.__proto__ == Object.prototype //true
這兩個對象比較特殊,注意一下和其他的內置對象一定要分開!!!
2.繼承
繼承可以說是每一個面向對象語言肯定有的,因為符合我們現實的想法,子承父業嘛!如果你爸比較有錢,你繼承了幾個億的家產肯定一生無憂;如果你爸是個普通人,那即使繼承了家產也沒有多少啊!還是要靠自己奮斗。
在js中的繼承也一個樣,如果一個構造函數設計得很好,那么兒子等后代就會很舒服啊!繼承的話,從Object開始,下圖所示,你看Object中你覺得哪個部分最重要,應該被繼承下去,當然是原型啊!所以說繼承就是指的是原型中的所有東西都會被繼承到后代中。。。。

我們可以驗證一下:
Object.prototype.say = function(){alert("你好!")}; var obj = new Object(); obj.say();//頁面會有彈窗“你好!“,說明在obj實例中調用的say方法其實就是調用的是Object中原型中的say方法 //還可以用另外一個方式,就是用Math或者JSON對象也會有同樣的效果 Object.prototype.say = function(){alert("你好!")}; Math.say();
這個可能有點晦澀難懂,不要緊我們繼續往下看!看了他們的調用機制就懂了;
3.js方法調用機制
簡單測試一下,我就是分別在Object原型內外,構造函數Person原型內外,以及per實例中寫了一些方法,可能很多人看着都頭暈了。。。
Object.say = function(){alert("object----say")} Object.listen = function(){alert("object----listen")} Object.prototype.say = function(){alert("Object.prototype---say")}; Object.prototype.listen = function(){alert("Object.prototype---listen")}; var Person = new Function(); Person.say = function(){alert("Person>>>>>>say")}; Person.run = function(){alert("Person>>>>>>run")};
Person.listen = function(){alert("Person>>>>>>listen")}; Person.prototype.say = function(){alert("Person.prototype>>>>>>say")}; Person.prototype.run = function(){alert("Person.prototype>>>>>>run")}; var per = new Person(); per.say = function(){alert("per+++++++say")}; per.say(); //per+++++++say per.listen(); //Object.prototype---listen per.run(); //Person.prototype>>>>>>run
上面的太繁瑣,沒耐心看就算了,我就說說我得出的結論:原型外面的函數(也可以叫做方法)不會被繼承,也就是說只要是在原型外面的函數只能自己用,不能給后代用;而對於原型里面的函數,對於后代來說是可見的,

注意:圖中我為了看起來簡潔,省略了一點東西,就是那么__proto__屬性,為什么實例能夠找到它爸爸構造函數的原型呢?就是通過這個屬性,而構造函數中也有一個__proto__屬性,指向Object的原型,通過這個原型的話,我們的實例就能夠慢慢往上找原型,一直可以找到Object的原型,這就是所謂的原型鏈。。。。
所以根據這個特性,js一開始就在Object的原型中放置了一些常用的函數,所以自定義構造函數的實例一開始就可以調用一些方法,這些方法不是我們定義的,而是官方幫你先放到Object的原型中的,當然你也可以在實例或構造函數中弄個同樣名字的函數,將官方那個給覆蓋掉。。。。。
4.js中方法類型
我js中的方法大概分為三種(對於js這樣的語言來說,沒有類的概念好不爽,我們就把構造函數看作類吧。。。。):類方法,實例方法,原型方法
那么這三種方法到底是干嘛的呢?我就隨便舉個例子:
var Person = function(name){ this.name = name; this.say = function(){alert("say.....")};//實例方法 } Person.say = function(){alert("Person say.....")}//類方法,只能通過構造函數名來調用 Person.prototype.say=function(){alert("prototype say.....")}//原型方法 var per = new Person(); per.say();//調用實例方法,注意當實例方法和原型方法同名的時候優先調用實例方法,如果實例方法沒有say方法,那就會調用原型中的say方法 Person.say();//調用類方法 Person.prototype.say();//調用原型方法
5總結
怎么說呢?感覺js結構太糟糕了,看了好久才知道一個大概的輪廓,還有很多的東西沒看到,比如我們知道原型其實是一個當前構造函數的實例,那么我們可不可以把其他對象的實例賦值過來呢?比如Student.prototype = new Person(),這樣行嗎?當然可以,這樣的話可以讓Student的實例訪問Person的原型的方法,實現了繼承。。。。
哎,有機會再來啃js吧,還有好多東西要看。。。。由於看js沒多久,有什么說得有誤的地方歡迎指出!
