這裏討論下對象的內部原型(__proto__)和構造器的原型(prototype)的關係。
一、所有構造器/函數的__proto__都指向Function.prototype,它是一個空函數(Empty function)
1
2
3
4
5
6
7
8
9
|
Number.__proto__
=== Function.prototype //
true Boolean.__proto__
=== Function.prototype //
true String.__proto__
=== Function.prototype //
true Object.__proto__
=== Function.prototype //
true Function.__proto__
=== Function.prototype //
true Array.__proto__
=== Function.prototype //
true RegExp.__proto__
=== Function.prototype //
true Error.__proto__
=== Function.prototype //
true Date.__proto__
=== Function.prototype //
true |
JavaScript中有內置(build-in)構造器/對象共計12個(ES5中新加了JSON),這裏列舉了可訪問的8個構造器。剩下如Global不能直接訪問,Arguments僅在函數調用時由JS引擎創建,Math,JSON是以對象形式存在的,無需new。它們的__proto__是Object.prototype。如下
1
2
|
Math.__proto__
=== Object.prototype //
true JSON.__proto__
=== Object.prototype //
true |
上面說的“所有構造器/函數”當然包括自定義的。如下
1
2
3
4
5
6
|
//
函數聲明 function Person()
{} //
函數表達式 var Man
= function ()
{} console.log(Person.__proto__
=== Function.prototype) //
true console.log(Man.__proto__
=== Function.prototype) //
true |
這說明什麼呢?
所有的構造器都來自於Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了Function.prototype的屬性及方法。如length、call、apply、bind(ES5)。
Function.prototype也是唯一一個typeof XXX.prototype爲 “function”的prototype。其它的構造器的prototype都是一個對象。如下
1
2
3
4
5
6
7
8
9
10
|
console.log( typeof Function.prototype) //
function console.log( typeof Object.prototype) //
object console.log( typeof Number.prototype) //
object console.log( typeof Boolean.prototype) //
object console.log( typeof String.prototype) //
object console.log( typeof Array.prototype) //
object console.log( typeof RegExp.prototype) //
object console.log( typeof Error.prototype) //
object console.log( typeof Date.prototype) //
object console.log( typeof Object.prototype) //
object |
噢,上面還提到它是一個空的函數,alert(Function.prototype) 下看看。
知道了所有構造器(含內置及自定義)的__proto__都是Function.prototype,那Function.prototype的__proto__是誰呢?
相信都聽說過JavaScript中函數也是一等公民,那從哪能體現呢?如下
1
|
console.log(Function.prototype.__proto__
=== Object.prototype) //
true |
這說明所有的構造器也都是一個普通JS對象,可以給構造器添加/刪除屬性等。同時它也繼承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。
最後Object.prototype的__proto__是誰?
1
|
Object.prototype.__proto__
=== null //
true |
已經到頂了,爲null。
二、所有對象的__proto__都指向其構造器的prototype
上面測試了所有內置構造器及自定義構造器的__proto__,下面再看看所有這些構造器的實例對象的__proto__指向誰?
先看看JavaScript引擎內置構造器
1
2
3
4
5
6
7
8
9
10
11
|
var obj
= {name: 'jack' } var arr
= [1,2,3] var reg
= /hello/g var date
= new Date var err
= new Error( 'exception' ) console.log(obj.__proto__
=== Object.prototype) //
true console.log(arr.__proto__
=== Array.prototype) //
true console.log(reg.__proto__
=== RegExp.prototype) //
true console.log(date.__proto__
=== Date.prototype) //
true console.log(err.__proto__
=== Error.prototype) //
true |
再看看自定義的構造器,這裏定義了一個Person
1
2
3
4
5
|
function Person(name)
{ this .name
= name } var p
= new Person( 'jack' ) console.log(p.__proto__
=== Person.prototype) //
true |
p是Person的實例對象,p的內部原型總是指向其構造器Person的prototype。
每個對象都有一個constructor屬性,可以獲取它的構造器,因此以下打印結果也是恆等的
1
2
3
4
5
|
function Person(name)
{ this .name
= name } var p
= new Person( 'jack' ) console.log(p.__proto__
=== p.constructor.prototype) //
true |
上面的Person沒有給其原型添加屬性或方法,這裏給其原型添加一個getName方法
1
2
3
4
5
6
7
8
|
function Person(name)
{ this .name
= name } //
修改原型 Person.prototype.getName
= function ()
{} var p
= new Person( 'jack' ) console.log(p.__proto__
=== Person.prototype) //
true console.log(p.__proto__
=== p.constructor.prototype) //
true |
可以看到p.__proto__與Person.prototype,p.constructor.prototype都是恆等的,即都指向同一個對象。
如果換一種方式設置原型,結果就有些不同了
1
2
3
4
5
6
7
8
9
10
|
function Person(name)
{ this .name
= name } //
重寫原型 Person.prototype
= { getName: function ()
{} } var p
= new Person( 'jack' ) console.log(p.__proto__
=== Person.prototype) //
true console.log(p.__proto__
=== p.constructor.prototype) //
false |
這裏直接重寫了Person.prototype(注意:上一個示例是修改原型)。輸出結果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。
這也很好理解,給Person.prototype賦值的是一個對象直接量{getName: function(){}},使用對象直接量方式定義的對象其構造器(constructor)指向的是根構造器Object,Object.prototype是一個空對象{},{}自然與{getName: function(){}}不等。如下
1
2
3
4
|
var p
= {} console.log(Object.prototype) //
爲一個空的對象{} console.log(p.constructor
=== Object) //
對象直接量方式定義的對象其constructor爲Object console.log(p.constructor.prototype
=== Object.prototype) //
爲true,不解釋 |
上面代碼中用到的__proto__目前在IE6/7/8/9中都不支持。IE9中可以使用Object.getPrototypeOf(ES5)獲取對象的內部原型。
1
2
3
|
var p
= {} var __proto__
= Object.getPrototypeOf(p) console.log(__proto__
=== Object.prototype) //
true |
轉自點擊打開鏈接