深入瞭解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網站的支持!
推薦閱讀:
- 一文徹底理解js原生語法prototype,__proto__和constructor
- JavaScript深入淺出__proto__和prototype
- 如何利用JavaScript 實現繼承
- JS中的六種繼承方式以及優缺點總結
- JavaScript兩張圖搞懂原型鏈