原型與原型鏈詳解

與大部分面嚮對象語言不一樣,ES6以前中並無引入類(class)的概念,JavaScript並不是經過類而是直接經過構造函數來建立實例。在介紹原型和原型鏈以前,咱們有必要先複習一下構造函數的知識。javascript

在這裏插入圖片描述

1、構造函數

構造函數模式的目的就是爲了建立一個自定義類,而且建立這個類的實例。構造函數模式中擁有了類和實例的概念,而且實例和實例之間是相互獨立的,即實例識別。
構造函數就是一個普通的函數,建立方式和普通函數沒有區別不一樣的是構造函數習慣上首字母大寫。 另外就是調用方式的不一樣,普通函數是直接調用,而構造函數須要使用new關鍵字來調用。java

function Person(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
        this.sayName = function () {
            alert(this.name);
        }
    }
    var per = new Person("孫悟空", 18, "男");
    function Dog(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
    }
    var dog = new Dog("旺財", 4, "雄")
    console.log(per);//當咱們直接在頁面中打印一個對象時,事件上是輸出的對象的toString()方法的返回值
    console.log(dog);

在這裏插入圖片描述
每建立一個Person構造函數,在Person構造函數中,爲每個對象都添加了一個sayName方法,也就是說構造函數每執行一次就會建立一個新的sayName方法。這樣就致使了構造函數執行一次就會建立一個新的方法,執行10000次就會建立10000個新的方法,而10000個方法都是一摸同樣的,爲何不把這個方法單獨放到一個地方,並讓全部的實例均可以訪問到呢?這就須要原型(prototype)node

2、原型

在JavaScript中,每當定義一個函數數據類型(普通函數、類)時候,都會天生自帶一個prototype屬性,這個屬性指向函數的原型對象,而且這個屬性是一個對象數據類型的值。web

讓咱們用一張圖表示構造函數和實例原型之間的關係:
在這裏插入圖片描述
原型對象就至關於一個公共的區域,全部同一個類的實例均可以訪問到這個原型對象,咱們能夠將對象中共有的內容,統一設置到原型對象中。shell

3、原型鏈

1. __proto__constructor

每個對象數據類型(普通的對象、實例、prototype......)也天生自帶一個屬性__proto__,屬性值是當前實例所屬類的原型(prototype)。原型對象中有一個屬性constructor, 它指向函數對象。svg

function Person() {}
    var person = new Person()
    console.log(person.__proto__ === Person.prototype)//true
    console.log(Person.prototype.constructor===Person)//true
    //順便學習一個ES5的方法,能夠得到對象的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype) // true

在這裏插入圖片描述

2. 何爲原型鏈

在JavaScript中萬物都是對象,對象和對象之間也有關係,並非孤立存在的。對象之間的繼承關係,在JavaScript中是經過prototype對象指向父類對象,直到指向Object對象爲止,這樣就造成了一個原型指向的鏈條,專業術語稱之爲原型鏈。函數

舉例說明:person → Person → Object ,普通人繼承人類,人類繼承對象類學習

當咱們訪問對象的一個屬性或方法時,它會先在對象自身中尋找,若是有則直接使用,若是沒有則會去原型對象中尋找,若是找到則直接使用。若是沒有則去原型的原型中尋找,直到找到Object對象的原型,Object對象的原型沒有原型,若是在Object原型中依然沒有找到,則返回undefined。測試

咱們能夠使用對象的hasOwnProperty()來檢查對象自身中是否含有該屬性;使用in檢查對象中是否含有某個屬性時,若是對象中沒有可是原型中有,也會返回truethis

function Person() {}
    Person.prototype.a = 123;
    Person.prototype.sayHello = function () {
      alert("hello");
    };
    var person = new Person()
    console.log(person.a)//123
    console.log(person.hasOwnProperty('a'));//false
    console.log('a'in person)//true

person實例中沒有a這個屬性,從 person 對象中找不到 a 屬性就會從 person 的原型也就是 person.__proto__,也就是 Person.prototype中查找,很幸運地獲得a的值爲123。那假如 person.__proto__中也沒有該屬性,又該如何查找?

當讀取實例的屬性時,若是找不到,就會查找與對象關聯的原型中的屬性,若是還查不到,就去找原型的原型,一直找到最頂層Object爲止。Object是JS中全部對象數據類型的基類(最頂層的類)在Object.prototype上沒有__proto__這個屬性。

console.log(Object.prototype.__proto__ === null) // true

在這裏插入圖片描述

使用node 進行測試

C:\Users\Lenovo>node
> function Person(){}
undefined
> let person = new Person();
undefined
> console.log(person == Person)
false
undefined
> console.log(person == Person.prototype)
false
undefined
> console.log(person.__proto__ == Person.prototype)
true
undefined
> console.log(person.constructor == Person)
true
undefined
> console.log(Person.prototype.constructor == Person)
true
undefined
> console.log(person.constructor == Person.prototype.constructor)
true
undefined
>

根據測試得出:原型對象(Person.prototype)是 構造函數(Person)的一個實例。
然而實例對象(person)與構造函數(Person)並不存在直接聯繫;
而是創建在實例對象(person)的__proto 與構造函數(Person)的原型對象(Person.prototype)之間,而後再進行對構造函數的訪問與操做

本文轉載之: https://www.jianshu.com/p/ddaa5179cda6

相關文章
相關標籤/搜索