1. 程式人生 > >原型是什麼?原型和原型鏈的一些心得體會

原型是什麼?原型和原型鏈的一些心得體會

最近在複習原型,感覺有很多要重點對待的,對面向物件的理解很有幫助。遂記。

我的理解:

原型的主要作用:共享資料,節省空間!

一、為什麼要用原型?

例如:有一個建構函式  Person :

function Person(name)  { 
    
    this.name = name;

    this.eat= function () {
        console.log("eat");
    }
    
}

var per1 = new Person( 'zs' );

對於這個建構函式的例項物件 per1 來說,可以呼叫方法 eat 。由此看來是沒有任何問題。但由於函式也是物件,會在記憶體中單獨開闢一個空間,因此,當例項物件多的時候,就會出現記憶體空間被很多重複的函式佔用。

如:有100個 Person 的例項物件,那麼在記憶體空間裡就會有100個eat方法佔用的空間,這些方法分別指向不同的例項物件。但是他們的執行結果卻都是一樣的。這就造成了記憶體空間的浪費!

為解決這個問題,我們需要一個共享的空間,在裡面存放一些公共的方法,屬性,這就是原型。

二、什麼是原型?

1、對於建構函式Person 來說,他有一個prototype的屬性,prototype是一個物件,他叫顯式原型。

prototype是給程式設計師使用的,是標準的屬性,且只有函式有這個屬性。

在prototype中有預設的幾個屬性,如constructor構造器等

2、對於一個例項物件per1來說,他有一個__proto__的屬性,__proto__是一個物件

,他叫隱式原型。

__proto__是給瀏覽器使用的,不是標準的屬性,且IE8不支援。

當我們在建構函式的 prototype 中新增屬性或者方法的時候,其例項物件均可以使用這些屬性或者方法且不會單獨的開闢空間。這就完成了資料的共享!

如程式碼:

function Person(name) {
    this.name = name;
}
Person.prototype.eat = function () {
    console.log("eat");
}

var per1 = new Person( 'zs' );

對於例項物件per1來說,他有一個屬性name,且有一個方法 eat ,由於eat方法是寫在其建構函式的原型裡面的,因此他在例項化的時候,不會單獨為eat再開一個空間,而是直接使用eat方法。

這樣如果有100個例項物件的話,大家使用的都是同一個eat方法,不會單獨為eat開闢空間,大大節省了記憶體空間。

那麼,為什麼 例項物件per1可以呼叫寫在建構函式(person) 的 prototype 中的 方法或者 屬性呢?

因為Person 建立了per1,因此,per1中的 __proto__ 指向了  Person中的prototype,所以prototype中的屬性和方法,per1都可以通過__proto__呼叫。

即使用per1.__proto__.eat();就可以呼叫了,通常情況下我們省略__proto__不寫--->  寫 per1.eat() 即可

三、原型中的this指向?

原型中的this指向  為  呼叫這個方法的例項物件。就是哪個例項物件呼叫這個方法,this就指向哪個例項物件!

四、原型的指向可以改變嗎?

原型是一個建構函式中的一個屬性,同時他也是一個物件!物件中存放的是地址,他指向一塊記憶體空間。在這個記憶體空間中存放著公共的屬性和方法。

例如:

1  function Person(name) {
2     this.name = name;
3  }
4
5  Person.prototype.eat = function () {
6     console.log("eat");
7  }
8
9  Person.prototype = {
10     sayHi : function () {
11         console.log("Hello");
12     }
13 }

我們可以看到在程式碼的第5行時,我們在建構函式的原型中添加了一個方法,而當第9行的時候,我們重新宣告一個物件,並把物件給了原型,且新的物件裡面有一個方法sayHi。

當我們再次呼叫eat的時候,會發現無法呼叫,因為eat 在以前指向的那塊記憶體空間裡面,而原型指向已經發生了改變,不再指向之前的那塊空間了,現在指向的是有sayHi的那塊記憶體空間。

因此原型的指向是可以改變的。

五、原型鏈是什麼?

在瞭解原型鏈之前。我們要知道,任何物件中都有__proto__屬性,其指向某個建構函式的prototype物件。

建構函式的prototype屬性,也是物件,因此他也有__proto__屬性。

而我們知道,例項物件的__proto__指向的是其建構函式的 prototype物件。那麼,我們是不是可以推出--->prototype物件因為有__proto__屬性,所以,他也是一個例項物件,其__proto__屬性的指向為某個建構函式的prototype物件。同樣某個建構函式的prototype物件也有__proto__屬性,他也有指向的prototype物件,因此就會形成一條原型鏈!

如圖: