js原型鏈

java小新人發表於2019-06-29

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

相關文章