javascript之原型與原型鏈

flynike發表於2021-09-09

萬物皆物件

在JavaScript中除值型別之外,其他的都是物件,為了說明這點,我們舉幾個例子
我們可以使用typeof來做型別判斷

typeof a;             // undefinedtypeof 1;             // numbertypeof 'wclimb';      // stringtypeof true;          // booleantypeof function(){};  // functiontypeof [];            // objecttypeof null;          // objecttypeof {};            // object

除了undefinednumberstringboolean屬於值型別之外,其他都是物件。你可能要問了,不是還有一個是function嗎?要校驗他是不是應該物件可以這樣做:

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

由上面的例子所示,函式確實是物件,為什麼呢?我們看一下下面的例子

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

由此我們可以得知,物件都是透過函式建立的,這麼說你可能又會說不對,你看下面的就不是函式建立的

var person = {name:'wclimb'}

你咋就這麼飄呢?我竟無言以對,沒錯,這是個意外、意外、意外。但是歸根結底他還是透過函式建立的

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

so,現在你只要知道物件是透過函式建立的就可以了,來跟著我讀:
第一遍 物件都是透過函式建立的
第二遍 物件都是透過函式建立的
第三遍 物件都是透過函式建立的

建構函式(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 // trueperson2.constructor === Person // true

原型(prototype)

在JavaScript中,每定義一個函式都會產生一個prototype(原型)屬性,這個屬性指向函式的原型物件

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到底是什麼呢?跟建構函式有關係嗎?

圖片描述

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

  2. Person建構函式是由Function建立的,所以可以得出Person.__proto__ === Fucntion.prototype

  3. 我們上面說過Person.prototype其實是一個物件,而物件是由Object建立的,所以 Person.prototype.__proto__ === Object.prototype

  4. Object物件都是函式建立的,所以Object.__proto__ === Function.prototype

  5. 雖然Object.prototype是一個物件但是他的__proto__null

例項和原型

當我們要取一個值的時候,會先從例項中取,如果例項中存在,則取例項的值,如果例項不存在,則會順著原型裡找,直到找到

function Person(){}
Person.prototype.name = '我來自原型'var person = new Person()
person.name = '我來自例項'console.log(person.name); // 我來自例項delete person.nameconsole.log(person.name)); // 我來自原型

首先person例項中有這個屬性,返回我來自例項,然後將它刪除之後,會從原型中招,也就是person.__proto__,因為Person.prototype === person.__proto__,所以得到我來自原型

總結

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



作者:wclimb
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2618/viewspace-2814406/,如需轉載,請註明出處,否則將追究法律責任。

相關文章