從新認識javascript對象(三)——原型及原型鏈

1、原型檢測

javascript中提供Object.getPrototypeOf()方法來得到對象的直接原型。javascript

function Person() {
    this.name = 'sillywa'
}
var person1 = new Person()
Object.getPrototypeOf(person1)  // {constructor: ƒ Person()}
Object.getPrototypeOf(person1.__proto__)  // Object.prototype

var person = {
    name: 'sillywa'
}
var person2 = Object.create(person)
Object.getPrototypeOf(person2)  // {name: "sillywa"}
複製代碼

javascript有如下幾種方法檢測一個對象的原型:java

  1. isPrototypeOf():檢測一個對象是不是另外一個對象的原型
  2. obj.constructor.prototype:檢測非Object.create()建立的對象的原型
var obj1 = {
    name: 'sillywa'
}
var obj2 = Object.create(obj1)

// isPrototypeOf()方法
Object.prototype.isPrototypeOf(obj1)  // true
obj1.isPrototypeOf(obj2)  // true
Object.prototype.isPrototypeOf(obj2)  // true

// obj.constructor.prototype
obj1.constructor.prototype === Object.prototype  // true
// obj1是obj2的原型,如下等式應爲true
obj2.constructor.prototype === obj1  // false
// 而實際上
obj2.constructor.prototype === Object.prototype  // true
複製代碼

以上代碼中obj1obj2的原型,obj2.constructor.prototype === obj1應爲true可是實際上倒是false,由於obj2__proto__裏面並無一個constructor屬性,obj2.constructor其實是obj1__proto__裏面的constructor,因此obj2.constructor.prototype === Object.prototype瀏覽器

1、constructor__proto__prototype之間的關係

在javascript中咱們每建立一個對象,該對象都會得到一個__proto__屬性(該屬性是個對象),該屬性指向建立該對象的構造函數的原型prototype,同時__proto__對象有一個constructor屬性指向該構造函數。這裏咱們須要注意的是隻有函數纔有prototype,每一個對象(函數也是對象)都有__proto__Object自己是個構造函數。舉例來講:bash

var obj = new Object()
// 也可使用對象字面量建立,但使用Object.create()狀況會不同
// Object自己是個構造函數
Object instanceof Function  // true
obj.__proto__ === Object.prototype  // true
obj.__proto__.constructor === Object  // true
// 咱們通常習慣這樣寫
obj.constructor === Object  // true
複製代碼

當咱們訪問obj.constructor的時候,obj自己是沒有constructor屬性的,但屬性訪問會沿着__proto__向上查找,即在obj.__proto__裏面尋找constructor屬性,若是找到了就返回值,若是未找到則繼續向上查找直到obj.__proto__.__proto__...(__proto__) === null爲止,沒有找到則返回undefined。這樣由__proto__構成的一條查找屬性的線稱爲‘原型鏈’。函數

2、進一步探討

咱們知道JS是單繼承的,Object.prototype是原型鏈的頂端,全部對象從它繼承了包括toString等等方法和屬性。this

前面咱們說到Object自己是構造函數,那麼它繼承了Function.prototype;Function也是對象,繼承了Object.prototype。這裏就有一個雞和蛋的問題:spa

Object instanceof Function  // true
Function instanceof Object  // true
複製代碼

如下是ES規範的解釋:prototype

Function自己就是函數,Function.__proto__是標準的內置對象Function.prototypeFunction.prototype.__proto__是標準的內置對象Object.prototypecode

function Person(name) {
    this.name = name
}
var person1 = new Person('sillywa')
複製代碼

總的來講:先有Object.prototype(原型鏈頂端),Function.prototype繼承Object.prototype而產生,最後,FunctionObject和其它構造函數繼承Function.prototype而產生。cdn

3、Object.create()

咱們知道經過Object.create()建立的對象實際上等於將該對象的__proto__指向Object.create()裏面的參數對象,那麼當涉及到原型時它是怎麼工做的呢?

var a = {
    name: 'sillywa'
}
var b = Object.create(a)

b.__proto__ === Object.prototype  // false
b.__proto__ === a  // true
b.__proto__.constructor === Object  // true
b.__proto__.hasOwnProperty('constructor')  // false
複製代碼

下面咱們來具體看一看當var b = Object.create(a)到底發生了什麼,如下實在瀏覽器中的結果:

咱們能夠看到當 var b = Object.create(a)其實是把 b__proto__指向了 a。當訪問 b.constructor時,實際上訪問的是 b.__proto__.__proto__.constructor

4、實例與總結

function Person(name) {
    this.name = name
}
var person1 = new Person('sillywa')

person1.__proto__ === Person.prototype
person1.__proto__.__proto__ === Person.prototype.__proto__
person1.__proto__.__proto__ === Object.prototype
Person.prototype.__proto__ === Object.prototype 
person1.__proto__.__proto__.__proto__ === null

Person.__proto__ === Function.prototype
複製代碼

以上均返回true,前五個等式和第一部份內容相關,最後一個等式爲第二部份內容,須要注意的是IE瀏覽器裏面並無實現__proto__,爲了便於理解咱們能夠這樣解釋,可是最好不要在實際中使用

相關文章
相關標籤/搜索