JavaScript之原型與原型鏈

我的博客原文地址git

萬物皆對象

在JavaScript中除值類型以外,其餘的都是對象,爲了說明這點,咱們舉幾個例子
咱們可使用typeof來作類型判斷github

typeof a;             // undefined
typeof 1;             // number
typeof 'wclimb';      // string
typeof true;          // boolean

typeof function(){};  // function
typeof [];            // object
typeof null;          // object
typeof {};            // object

除了undefinednumberstringboolean屬於值類型以外,其餘都是對象。你可能要問了,不是還有一個是function嗎?要校驗他是否是應該對象能夠這樣作:函數

var fn = function(){}
fn instanceof Object // true

由上面的例子所示,函數確實是對象,爲何呢?咱們看一下下面的例子this

function Person(name){
    this.name = name; 
}
var person = new Person('wclimb');
console.log(person) // Person {name: "wclimb"}

由此咱們能夠得知,對象都是經過函數建立的,這麼說你可能又會說不對,你看下面的就不是函數建立的spa

var person = {name:'wclimb'}

你咋就這麼飄呢?我竟無言以對,沒錯,這是個意外、意外、意外。可是歸根結底他仍是經過函數建立的prototype

var person = new Object()
    person.name = 'wclimb'

so,如今你只要知道對象是經過函數建立的就能夠了,來跟着我讀:
第一遍 對象都是經過函數建立的
第二遍 對象都是經過函數建立的
第三遍 對象都是經過函數建立的code

構造函數(constructor)

function Person(name){
    this.name = name
}
var person1 = new Person('wclimb 1')
var person2 = new Person('wclimb 2')

上面Person就是一個構造函數,咱們經過new的方式建立了一個實例對象person
咱們來看看person1和person2的constructor(構造函數)是否是指向Person的對象

person1.constructor === Person // true
person2.constructor === Person // true

原型(prototype)

在JavaScript中,每定義一個函數都會產生一個prototype(原型)屬性,這個屬性指向函數的原型對象blog

function Person(){}
Person.prototype.name = 'wclimb'
Person.prototype.age = '24'
Person.prototype.sayAge = function(){
    console.log(this.age)
}
var person = new Person()
person.sayAge(); //  24

那麼這個prototype究竟是什麼呢?跟構造函數有關係嗎?ip

image

上圖就能夠反映出他們之間的關係

其實函數的prototype指向函數的原型對象,每一個對象都會關聯另一個對象,也就是原型,上面的例子改爲:

Person.prototype = {
    name: 'wclimb',
    age: 24,
    satAge: function(){
        console.log(this.age)
    }
}

隱式原型(__proto__)

上面咱們說到每定義一個函數都會產生一個原型,每一個函數它不止有原型,還有一個__proto__(隱式原型)
每一個對象都有一個__proto__屬性,指向建立該對象函數的prototype,咱們能夠來試試,仍是上面的例子:

function Person(){}
var person = new Person()
person.__proto__ === Person.prototype // true

如今他們的關係圖以下

image

由上圖咱們能夠知道:

Person.prototype.constructor = Person
person.__proto__ = Person.prototype
person.constructor = Person

咱們能夠看到person.__proto__指向構造函數的原型,那麼構造函數的原型即Person__proto__指向哪裏呢?
咱們知道構造函數其實就是由Function來建立的,由此得出:

Person.__proto__ === Function.prototype

那麼構造函數的原型即Person.prototype__proto__指向哪裏呢?
原型對象實際上是經過Object生成的,天然而然的得出:

Person.prototype.__proto__ === Object.prototype

那麼Object.prototype__proto__指向哪裏呢?答案是null,最終獲得下面的圖

image

拋開這張圖,來看看下面幾道題

  1. person.__proto__
  2. Person.__proto__
  3. Person.prototype.__proto__
  4. Object.__proto__
  5. Object.prototype.__proto__

解:

  1. 每一個對象都有一個__proto__屬性,指向建立該對象函數的prototype,由於Person是person的構造函數

Person === person.constructortrue,因此:person.__proto__ === Person.prototype

  1. Person構造函數是由Function建立的,因此能夠得出Person.__proto__ === Fucntion.prototype
  2. 咱們上面說過Person.prototype實際上是一個對象,而對象是由Object建立的,因此 Person.prototype.__proto__ === Object.prototype
  3. Object對象都是函數建立的,因此Object.__proto__ === Function.prototype
  4. 雖然Object.prototype是一個對象可是他的__proto__null

實例和原型

當咱們要取一個值的時候,會先從實例中取,若是實例中存在,則取實例的值,若是實例不存在,則會順着原型裏找,直到找到

function Person(){}
Person.prototype.name = '我來自原型'

var person = new Person()
person.name = '我來自實例'
console.log(person.name); // 我來自實例
delete person.name
console.log(person.name)); // 我來自原型

首先person實例中有這個屬性,返回我來自實例,而後將它刪除以後,會從原型中招,也就是person.__proto__,由於Person.prototype === person.__proto__,因此獲得我來自原型

總結

原型和原型鏈基本已經講解完,不過還有待完善,若有錯誤,還望指正

GitHub:wclimb

相關文章
相關標籤/搜索