JS中原型和原型鏈深刻理解

首先要搞明白幾個概念:java

  1. 函數(function)
  2. 函數對象(function object)
  3. 本地對象(native object)
  4. 內置對象(build-in object)
  5. 宿主對象(host object)

函數

function foo(){
    
}
var foo = function(){
    
}

前者爲函數聲明,後者爲函數表達式。typeof foo
的結果都是function。函數

函數對象

函數就是對象,表明函數的對象就是函數對象ui

官方定義, 在Javascript中,每個函數實際上都是一個函數對象.

JavaScript代碼中定義函數,或者調用Function建立函數時,最終都會以相似這樣的形式調用Function函數:var newFun = new Function(funArgs, funBody)this

其實也就是說,咱們定義的函數,語法上,都稱爲函數對象,看咱們如何去使用。若是咱們單純的把它當成一個函數使用,那麼它就是函數,若是咱們經過他來實例化出對象來使用,那麼它就能夠當成一個函數對象來使用,在面向對象的範疇裏面,函數對象相似於類的概念。spa

var foo = new function(){
    
}
typeof foo // object

或者

function Foo (){
    
}
var foo = new Foo();

typeof foo // object

上面,咱們所創建的對象prototype

本地對象

ECMA-262 把本地對象(native object)定義爲「獨立於宿主環境的 ECMAScript 實現提供的對象」。簡單來講,本地對象就是 ECMA-262 定義的類(引用類型)。它們包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.

咱們不能被他們起的名字是本地對象,就把他們理解成對象(雖然是事實上,它就是一個對象,由於JS中萬物皆爲對象),經過code

typeof(Object)
typeof(Array)
typeof(Date)
typeof(RegExp)
typeof(Math)

返回的結果都是function對象

也就是說其實這些本地對象(類)是經過function創建起來的,繼承

function Object(){
    
}
function Array(){
    
}
...

能夠看出Object本來就是一個函數,經過new Object()以後實例化後,建立對象。相似於JAVA中的類。ip

內置對象

ECMA-262 把內置對象(built-in object)定義爲「由 ECMAScript 實現提供的、獨立於宿主環境的全部對象,在 ECMAScript 程序開始執行時出現」。這意味着開發者沒必要明確實例化內置對象,它已被實例化了。ECMA-262 只定義了兩個內置對象,即 Global 和 Math (它們也是本地對象,根據定義,每一個內置對象都是本地對象)。

理清楚了這幾個概念,有助於理解咱們下面要講述的原型和原型鏈。

prototype

prototype屬性是每個函數都具備的屬性,可是不是一個對象都具備的屬性。好比

function Foo(){
    
}

var foo = new Foo();

其中Foo中有prototype屬性,而foo沒有。可是foo中的隱含的__proto__屬性指向Foo.prototype。

foo.__proto__ === Foo.prototype

爲何會存在prototype屬性?

Javascript裏面全部的數據類型都是對象,爲了使JavaScript實現面向對象的思想,就必需要可以實現‘繼承’使全部的對象鏈接起來。而如何實現繼承呢?JavaScript採用了相似C++,java的方式,經過new的方式來實現實例。

舉個例子,child1,child2都是Mother的孩子,且是雙胞胎。(雖然不是很好,可是仍是很能說明問題的)

function Mother(name){
    this.name = name;
    this.father = 'baba';
}
var child1 = new Mother('huahua');
var child2 = new Mother('huahua');

若是有一天,發現孩子的父親實際上是Baba,那麼就要修改每個孩子的father屬性。

child1.father ='Baba';
console.log(child2.father) // baba

也就是說修改了其中一個孩子的father屬性不會影響到下一個,屬性的值沒法共享。

正是這個緣由才提出來prototype屬性,把須要共享的屬性放到構造函數也就是父類的實例中去。

__proto__

__proto__屬性是每個對象以及函數都隱含的一個屬性。對於每個含有__proto__屬性,他所指向的是建立他的構造函數的prototype。原型鏈就是經過這個屬性構件的。

想像一下,若是一個函數對象(也稱爲構造函數)a的prototype是另外一個函數對象b構建出的實例,a的實例就能夠經過__proto__與b的原型鏈起來。而b的原型其實就是Object的實例,因此a的實例對象,就能夠經過原型鏈和object的prototype連接起來。

function a(){
    
}
function b(){
    
}
var b1 = new b();
a.prototype = b1;
var a1 = new a();
console.log(a1.__proto__===b1);//true
console.log(a1.__proto__.__proto__===b.prototype) //true
console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true

若是要理清原型和原型鏈的關係,首先要明確一下幾個概念:
1.JS中的全部東西都是對象,函數也是對象, 並且是一種特殊的對象

2.JS中全部的東西都由Object衍生而來, 即全部東西原型鏈的終點指向Object.prototype

3.JS對象都有一個隱藏的__proto__屬性,他指向建立它的構造函數的原型,可是有一個例外,Object.prototype.__proto__指向的是null。

4.JS中構造函數和實例(對象)之間的微妙關係

構造函數經過定義prototype來約定其實例的規格, 再經過 new 來構造出實例,他們的做用就是生產對象.

function Foo(){
    
}
var foo = new Foo();
foo實際上是經過Foo.prototype來生成實例的。

構造函數自己又是方法(Function)的實例, 所以也能夠查到它的__proto__(原型鏈)

function Foo(){
    
}
等價於
var Foo= new Function();

而Function其實是

function Function(){
    Native Code
}
也就是等價於
var Function= new Function();

因此說Function是經過本身建立出來的。正常狀況下對象的__proto__是指向建立它的構造函數的prototype的.因此Function的__proto__指向的Function.prototype

Object 實際上也是經過Function建立出來的

typeof(Object)//function
因此,
function Object(){
    Native Code
}
等價於
var Object = new Function();

那麼Object的__proto__指向的是Function.prototype,也便是

Object.__proto__ === Function.prototype //true

下面再來看Function.prototype的__proto__指向哪裏

由於JS中全部的東西都是對象,那麼,Function.prototype 也是對象,既然是對象,那麼Function.prototype確定是經過Object建立出來的,因此,

Function.prototype.__proto__ === Object.prototype //true

綜上所述,Function和Object的原型以及原型鏈的關係能夠概括爲下圖。

2016102714775006823199.jpg

對於單個的對象實例,若是經過Object建立,

var obj = new Object();

那麼它的原型和原型鏈的關係以下圖
20161027147749990054513.jpg

若是經過函數對象來建立,

function Foo(){
    
}
var foo = new Foo();

那麼它的原型和原型鏈的關係以下圖

20161027147750059948187.jpg

那JavaScript的總體的原型和原型鏈中的關係就很清晰了,以下圖所示

20161027147750055267571.jpg

相關文章
相關標籤/搜索