深入瞭解javascript原型和原型鏈

一、什麼是原型

原型:每一個javascript對象(除null外)創建的時候,都會與之關聯另一個對象,這個對象就是我們所說的原型,每一個對象都會從原型中“繼承”屬性。

例如

var obj = new Object();

創建一個對象的時候都會同時關聯一個對象,如圖,關聯的這個對象就是新建的對象obj的原型

二、prototype

在JavaScript中,每個函數都有一個prototype屬性,這個屬性指向函數的原型對象。(ps:函數其實也是一個對象,所以與上述一、中的例子不沖突)

var obj = new Object();

所謂的prototype其實就是對象與對象的原型關聯的屬性,如圖

例如:

 function Animal(weight) {
   this.weight = weight
 }

如圖表示對象與原型的關聯:

每一個對象都會從原型中“繼承”屬性

例如:cat1和cagt2實例化瞭Animal,在cat1和cagt2本身是沒有hieght屬性的,但是能打印出height的值均為10,其實是在cat1和cagt2繼承瞭原型Animal.prototype中的height屬性

 function Animal(weight) {
    this.weight = weight
  }
  Animal.prototype.height = 10
  var cat1 = new Animal()
  var cat2 = new Animal()
  console.log('cat1',cat1.height)//10
  console.log('cat2',cat2.height)//10

三、__proto__

這是每個對象(除null外)都會有的屬性,叫做__proto__,這個屬性會指向該對象的原型。

  function Animal(weight) {
     this.weight = weight
  }
  Animal.prototype.height = 10
  var cat1 = new Animal()
  var cat2 = new Animal()
 console.log('cat1.__proto__ === Animal.prototype',cat1.__proto__ === Animal.prototype)
 console.log('cat2.__proto__ === Animal.prototype',cat2.__proto__ === Animal.prototype)

__proto__和prototype

  • __proto__是實例指向原型的屬性
  • prototype是對象或者構造函數指向原型的屬性

四、constructor

每個原型都有一個constructor屬性,指向該關聯的構造函數。

  function Animal(weight) {
     this.weight = weight
  }
  Animal.prototype.height = 10
  var cat1 = new Animal()
  var cat2 = new Animal()
 console.log('cat1.__proto__ === Animal.prototype',cat1.__proto__ === Animal.prototype)
 console.log('Animal===Animal.prototype.constructor',Animal===Animal.prototype.constructor)
// 獲取原型對象
 console.log('Object.getPrototypeOf(cat1) === Animal.prototype',Object.getPrototypeOf(cat1) === Animal.prototype)

更新關系圖

cat1.__proto__ === Animal.prototype

Animal === Animal.prototype.constructor

那麼cat1.constructor === Animal為true 嗎?答案是true,因為每一個對象都會從原型中“繼承”屬性,cat1中並沒有屬性constructor ,但是它的原型cat1.__proto__ 指向的是Animal.prototype,然而Animal.prototype原型中是有屬性constructor的,於是cat1的constructor屬性繼承與原型中的constructor屬性。這裡便能看出一點點原型鏈的影子瞭,我們接著看

因此cat1.constructor === Animal 也是 true

五、實例與原型

 當讀取實例的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層為止。這樣就形成瞭原型鏈

function Animal(weight) {
   this.weight = weight
}
 Animal.prototype.name = 'animal'
 var cat1 = new Animal()
 cat1.name = 'littleCat'
 console.log('cat1.name',cat1.name)
 delete cat1.name;
 console.log('cat1.name',cat1.name)

可以看見,刪除屬性前,那麼是littleCat,刪除那麼屬性後,該實例沒有瞭name屬性,找不到name屬性的時候,它就會去 它的對象原型中去找也就是去cat1.__proto__中也就是Animal.prototype中去尋找,而Animal.prototype中的name屬性的值是animal,所以刪除name屬性後的值變成瞭原型中屬性name的值animal

那麼接著來看,如果cat1的原型中也沒有name屬性呢?會怎麼辦?去原型的原型中找?那麼原型的原型是什麼?

六、原型的原型

我們說原型是對象創建的時候關聯的另一個對象,那麼原型也是一個對象,既然是對象那麼原型也應該關聯一個對象是原型的原型

那麼原型對象創建的時候也會關聯一個對象

var obj = new Object();

看關系圖

那麼Object.prototype的原型呢?

也就是 Object.prototype.__proto__是什麼呢

console.log('Object.prototype.__proto__ === null',Object.prototype.__proto__ === null)

可以看到結果

也就說Object.prototype.__proto__ 的值為 null 即 Object.prototype 沒有原型,所以可以想象在原型鏈中,當屬性找到頂層原型都沒有屬性那就是沒有這個屬性

七、原型鏈

綜上所述 ,將原型的實例賦值給另一個對象,另一個對象再賦值給其他的對象,在實際的代碼中對對象不同的賦值,就會形成一條原型鏈。這樣說可能很抽象,我們來看個例子

 function Animal(weight) {
     this.weight = weight
 }
 Animal.prototype.name = 'animal'
 var cat1 = new Animal()
 var pinkCat = cat1
 console.log('pinkCat.name',pinkCat.name)
 console.log('pinkCat.__proto__ === cat1.__proto__ == Animal.prototype',pinkCat.__proto__ === cat1.__proto__ == Animal.prototype)
 var samllPinkCat = pinkCat
 console.log('samllPinkCat.name',samllPinkCat.name)
 console.log(samllPinkCat.__proto__ == pinkCat.__proto__ === cat1.__proto__ == Animal.prototype)

以上就是原型鏈一層一層鏈接上去形成一條鏈條就是所謂的原型鏈;以上cat1實例化瞭Animal,cat1賦值給瞭pinkCat,pinkCat又賦值給瞭samllPinkCat,就形成看原型鏈,從samllPinkCat,pinkCat到cat1最後到Animal

以上所述是小編給大傢介紹的深入瞭解javascript原型和原型鏈,希望對大傢有所幫助。在此也非常感謝大傢對WalkonNet網站的支持!

推薦閱讀: