說實話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沒多久,有什麼說得有誤的地方歡迎指出!