幾張圖讓prototype與__proto__和原型對象再也不是咱們的煩惱!(圖解prototype...)

初衷

對於js新手來講,《JavaScript高級程序設計》的學習是必不可少的,這裏我總結了一下JavaScript難以理解的知識點,如今拿來在掘金分享一下吧bash

前言

  • 在面向對象js中,JavaScript的原型和原型鏈的理解絕對是一件很讓人頭疼的事情,prototype與__proto__也容易讓人混淆;咱們都知道JavaScript 是基於原型的,可是可能大部分js新手都不知道如何去理解,因此我本身也想嘗試理解一下,看看能不能把JavaScript 是基於原型的,用最簡單的方法說清楚。
  • 理解了JavaScript 是如何基於原型的,咱們就清楚了原型和原型鏈、prototype與__proto__;
  • 如下純屬我的看法,若是有任何不對的地方,歡迎下方評論告訴我

你必須知道的知識點

想要理解原型和原型鏈、prototype與__proto__,請先接受如下知識;函數

  • prototype(原型)學習

    1. 任何對象的都有一個prototype(原型),prototype(原型)是保存對象實例方法的所在。可是這裏的prototype與函數的prototype屬性不是同一種東西
    2. 任何函數都有一個prototype屬性,這個屬性指向函數的原型對象。這裏原型對象要與對象的原型區分開來
  • __proto__
    複製代碼
    1. 任何實例對象都有一個私有屬性__proto__([[Prototype]]),這是一個包含指針的私部屬性,這個指針指向它的構造函數的原型對象,後面都會使用__proto__而不使用[[Prototype]]
  • constructor(構造函數)
    複製代碼
    1. 原型對象都會自動得到一個constructor屬性,這個屬性包含一個指向 prototype 屬性所在函數的指針。
    2. 實例化的對象也必定有自身的constructor(構造函數),這裏constructor(構造函數)要與原型對象的constructor屬性區分開來
    3. 構造器其實就是一個普通的函數
    4. Object.create()方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。
    5. 注:大多數狀況下,__proto__能夠理解爲構造函數的原型對象,即:實例對象.___proto_ === 實例對象.constructor.prototype;可是經過Object.create()方法建立的新對象不適用此等式

搞懂prototype與__proto__

  • 因爲上方我說了對象的prototype和函數的prototype屬性不是同一種東西,因此咱們分兩種方式來理解prototype,如今讓咱們分別用兩張圖片來理解
  • 函數的prototype屬性

(顏色深的小圓圈表明的是屬性,後面將再也不贅述,默認各位看官都知道)

// "構造函數建立對象"
function Person() {}
// var Person = function () {};
Person.prototype.name = "ziyin";
Person.prototype.myFunc = function () {
    alert(this.name)
}

var person1 = new Person();
person1.myFunc();//"ziyin"

console.log(person1.__proto__ === Person.prototype)//true
console.log(Person.prototype.constructor) //function Person(){}(即構造器function Person)這裏是對象原型的constructor屬性
console.log(person1.constructor) //function Person(){}(即構造器function Person) 這裏是實例對象的constructor
複製代碼
  • 對象的prototype

// "對象字面量建立對象"
var Person = {};//等同於 var Person = new Object()

console.log(Person.__proto__ === Object.prototype)//true   
console.log(Person.__proto__ === Person.constructor.prototype)//true   
console.log(Person.constructor === Person.__proto__.constructor)//true  
"此處等於號前面的constructor是實例對象的constructor,後面的是對象原型的constructor屬性"
console.log(Person.constructor)//function Object()
複製代碼

幾乎全部 JavaScript 中的對象都是位於原型鏈頂端的 Object 的實例

// "Object.create()建立對象"
var person1 = {name:"ziyin"};//等同於 var Person = new Object()
var person2 = Object.create(person1);

console.log(person2.constructor)// function Object()  
console.log(person1.constructor)// function Object()  
"console.log(person2.__proto__ === person1)// true console.log(person2.__proto__ === person2.constructor.prototype)// false __proto__失效"
console.log(person1.constructor === Object)// true  
console.log(person1.__proto__ === Object.prototype)// true __proto__ 未失效

複製代碼

理解原型鏈與原型

ECMAScript 中描述了原型鏈的概念,並將原型鏈做爲實現繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。簡單回顧一下構造函數、原型和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。那麼,假如咱們讓原型對象等於另外一個類型的實例,結果會怎麼樣呢?顯然,此時的原型對象將包含一個指向另外一個原型的指針,相應地,另外一個原型中也包含着一個指向另外一個構造函數的指針。假如另外一個原型又是另外一個類型的實例,那麼上述關係依然成立,如此層層遞進,就構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念this

  • 上面這一段巴拉巴拉的是否是看的有點頭暈?事實上這正是原型鏈最詳細的解釋,看吧!這對你理解原型鏈有很大的幫助~
  • 看完上面一段文字,如今讓咱們用更爲簡單一點的方法來理解原型鏈;
    1. 咱們都知道__proto__是任何對象都有的屬性,每一個實例對象(object)的__proto__指向它的構造函數的原型對象(prototype)。該原型對象也有一個本身的原型對象(_proto_),層層向上直到一個對象的原型對象爲null而偏偏在JS的世界裏萬物皆對象,因此在JS中會有一條由__proto__鏈接起來的一個鏈條,每一個對象能夠經過訪問__proto__遞歸訪問這個鏈條並且訪問的最終值會是null;
    2. 當JS引擎開始在對象中查找屬性和方法時,會先查找自身是否存在該屬性,存在則中止查找,不存在則沿着__proto__鏈接起來的原型鏈上查找。若是自己與原型鏈上存在相同屬性,js引擎會在查找到該屬性後中止在原型鏈上查找。
    3. 如今讓咱們用一張圖片來看看原型鏈是個什麼東西?
// 原型鏈
var Person = function () {} // function Person() {}
var person = new Person()

console.log(person.__proto__ === Person.prototype)//true  
console.log(person.__proto__)//Object {} 這個是一個函數  constructor指向"Person()函數"
console.log(person.__proto__.__proto__)//Object  這裏是一個對象,constructor指向"Object()函數"
console.log(person.__proto__.__proto__.__proto__)//null
複製代碼

總結

  • 好啦!到這裏相信各位看官都知道prototype與__proto__、原型對象是什麼東西了,如今我再來對這篇文章總結一下要點。(qiao黑板劃重點了)
    • 任何對象都有一個prototype(原型) ,任何函數都有一個prototype屬性,它指向這個函數的原型對象。
    • 任何實例對象都有一個私有屬性__proto__,__proto__指向它的構造函數的原型對象;大多數狀況下,__proto__能夠理解爲構造函數的原型對象,即:實例對象.___proto_ ===實例對象.constructor.prototype;可是經過Object.create()方法建立的新對象不適用此等式
    • 原型對象都會自動得到一個constructor屬性,它指向prototype 屬性所在函數即實例化對象的constructor(構造函數)。
    • 原型鏈是一條由__proto__鏈接起來的一個鏈條,鏈條上的每一個對象能夠經過訪問__proto__遞歸訪問這個鏈條並且訪問的最終值會是null;

以上文章純屬我的看法,文中若有錯誤,歡迎評論區指正spa

但願看完本篇文章能對你理解JavaScript是基於原型的有所幫助!固然最重要的仍是理解了本文所說的prototype與__proto__、原型對象,若是本文幫助到了你,歡迎點贊關注!prototype

文章參考了《JavaScript高級程序設計(第三版)》、《你不知道的JavaScript上卷》、掘金做者水乙、"developer.mozilla.org/zh-CN/docs/…"設計

相關文章
相關標籤/搜索