我如何搞懂Javascript系列之原型和原型鏈

理解原型

JavaScript 常被描述爲一種基於原型的語言——每一個對象擁有一個原型對象,對象以其原型爲模板、從原型繼承方法和屬性。原型對象也可能擁有原型,並從中繼承方法和屬性,一層一層、以此類推。這種關係常被稱爲原型鏈。瀏覽器

構造函數建立對象

JavaScript 中使用 new 操做符,經過構造函數初始化新對象。咱們先使用構造函數建立一個對象。函數

function Ninja() { 
    this.swung = true;
}

const ninja = new Ninja()
console.log(ninja.swung) // true

在上面例子中,簡單的經過 Ninja 構造器實例一個對象。接下來咱們經過這個例子詳細展開。this

prototype

在 JavaScript 中,函數能夠有屬性。每一個函數都有一個特殊的屬性叫做原型(prototype)。例如:spa

function Ninja() { 
  
}

Ninja.prototype.swung = true
const ninja = new Ninja()
console.log(ninja.swung) // true

上面例子中 Ninja 函數的 prototype 屬性指向的是一個對象,被構建的實例對象 ninja 的原型也指向這個對象。關於 ninja 原型則在下面詳細展開:prototype

proto

在 JavaScript 中,實例對象的原型屬性是內置屬性(使用標記 [[prototype]])。ES6以前 ECMAScript 標準沒有提供接口訪問這個屬性的,可是許多瀏覽器都實現了 JavaScript 非標準的內置屬性__proto__來訪問對象屬性。3d

function Ninja() { 
    this.swung = true;
}

const ninja = new Ninja()
console.log(ninja.__proto__ === Ninja.prototype) // true

每個JavaScript對象(除了null)都具備__proto__屬性,這個屬性會指向該對象的原型。code

接着在看下面這個例子:對象

function Ninja() { 
    this.swung = true;
}

const ninja = new Ninja()
console.log(Object.getPrototypeOf(ninja) === Ninja.prototype) // true

ES6開始,ECMAScript 標準提供了 Object.getPrototypeOf() 和 Object.setPrototypeOf() 訪問器來訪問和設置原型。__proto__它本質上是一個內部屬性,而不是一個正式的對外的 API,只是因爲瀏覽器普遍支持,才被加入了 ES6,因此建議不要使用。blog

上面例子中構造函數原型和實例對象原型是相同的,它們的原型中還包含一個特殊的屬性 constructor 用於指向構造函數。繼承

constructor

每一個原型都有一個 constructor 屬性指向關聯的構造函數。

function Ninja() { 
  
}

console.log(Ninja.prototype.constructor === Ninja) // true

構造函數、實例對象和 constructor 關係圖

原型鏈

當讀取實例的屬性時,若是找不到,就會查找與對象關聯的原型中的屬性,若是還查不到,就去找原型的原型,一直找到最頂層爲止。

舉個例子:

function Ninja() { 
  
}

Ninja.prototype.swung = true
const ninja = new Ninja()
ninja.swung = false
console.log(ninja.swung) // false

delete ninja.swung
console.log(ninja.swung) // true

原型鏈的最頂層即原型鏈的終點Object.prototype爲null,咱們能夠打印:

console.log(Object.prototype.__proto__) // null
null 表示「沒有對象」,即該處不該該有值。

因此 Object.prototype.__ proto__ 的值爲 null 跟 Object.prototype 沒有原型,其實表達了一個意思。

因此查找屬性的時候查到 Object.prototype 就中止查找了。

相關文章
相關標籤/搜索