每一個函數對象都有一個顯示的prototype屬性,它代表了函數對象的原型(Function.prototype函數對象是個例外,沒有prototype屬性,)。
每個普通對象都有一個名為__proto__的內部隱藏屬性,指向于它所對應的構造函數的原型對象(Chrome、Firefox中名稱為__proto__,并且可以被訪問到)。原型鏈正是基于__proto__才得以形成(note:不是基于函數對象的屬性prototype)。
所有構造器/函數對象(包括自定義的)都是有Function構造的,所以其__proto__都指向Function.prototype,它是一個空函數(Empty function)。
<script type="text/javascript"> console.log(Number.__proto__ === Function.prototype) // true console.log(Boolean.__proto__ === Function.prototype) // true console.log(String.__proto__ === Function.prototype) // true console.log(Object.__proto__ === Function.prototype) // true console.log(Function.__proto__ === Function.prototype) // true console.log(Array.__proto__ === Function.prototype) // true console.log(RegExp.__proto__ === Function.prototype) // true console.log(Error.__proto__ === Function.prototype) // true console.log(Date.__proto__ === Function.prototype) // true var Employee = function (){ }; function Person(){ } console.log(Employee.__proto__ === Function.prototype);//true console.log(Person.__proto__ === Function.prototype);//true </script>Javascript中有內置(build-in)構造器/對象共計12個(ES5中新加了JSON),這里列舉了可訪問的8個構造器。剩下如Global不能直接訪問,Arguments僅在函數調用時由JS引擎創建,Math,JSON是以對象形式存在的,無需new。它們的__proto__是Object.prototype。如下:<script type="text/javascript"> console.log(Math.__proto__ === Object.prototype);//true console.log(JSON.__proto__ === Object.prototype);//true </script>由以上測試得出,所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了Function.prototype的屬性及方法。如length、call、apply、bind(ES5)。另,Function.prototype也是唯一一個typeof XXX.prototype為 “function”的prototype。其它的構造器的prototype都是一個普通對象,下面來測試下:<script type="text/javascript"> 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 </script>所有普通對象的__proto__都指向其構造器的prototype
<script type="text/javascript"> function Foo(){ } var foo = new Foo();//對象實例化 console.log(foo.__proto__ === Foo.prototype);//true var obj = new Object(); console.log(obj.__proto__ === Object.prototype);//true</script>constuctor
每個函數對象都有名為“prototype”的屬性(上面提到過Function.prototype函數對象是個例外,沒有prototype屬性),用于引用原型對象。此原型對象又有名為“constructor”的屬性,它反過來引用函數本身。這是一種循環引用。<script type="text/javascript"> var arr = ["aaa", "bbb"], console.log(arr.constructor === Array);//true function Foo(){ } console.log(Foo.prototype.constructor === Foo);//true </script>Function、Object、Prototype、__proto__內存關系圖
堆區圖說明:
Function.prototype函數對象圖內部表示prototype屬性的紅色虛框,只是為了說明這個屬性不存在。通過上面這張圖可以得出以下幾點:所有對象,包括函數對象的原型鏈最終都指向了Object.prototype,而Object.prototype.__proto__===null,原型鏈至此結束。Animal.prototype是一個普通對象。Object是一個函數對象,也是Function構造的,Object.prototype是一個普通對象。Object.prototype.__type__指向null。Function.prototype是一個函數對象,前面說函數對象都有一個顯示的prototype屬性,但是Function.prototype卻沒有prototype屬性,Function.prototype.prototype===undefined,所以Function.prototype函數對象是一個特例,沒有prototype屬性。
函數與對象的關系
函數也是對象(函數對象),普通對象是由函數對象創建的,從前面的描述可以知道所有的函數對象中只有Function.prototype沒有prototype,可以認為所有的構造器(函數對象)都是由Function創建的,Function是頂級構造器。Function.prototype是一個特殊的函數對象,其__proto__指向的是Object.prototype。Function.prototype這個特殊的函數對象主要用來給函數對象定義一些系統內置的函數和屬性,如apply,call,length,arguments等。<script type="text/javascript"> console.log(Function.prototype);//function(){},空函數 console.log(Function.prototype.constructor);//function Function(){ [native code] },Function構造器 console.log(Function.prototype.__proto__);//Object{} console.log(Object.prototype);//Object{} console.log(Object.prototype.constructor);function Obeject(){},Object構造器 console.log(Object.prototype.__proto__);//null</script>普通對象的創建過程
<script type="text/javascript"> function Foo(num){}; var foo = new Foo(1);</script> 當執行new Foo(1)時:javascript引擎在內存中開辟一塊新的內存,一個新對象被創建。修改新對象的__proto__,指向Foo.prototype,它繼承自Foo.prototype。構造函數 Foo 被執行。執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定為這個新實例。new Foo 等同于 new Foo(), 只能用在不傳遞任何參數的情況。如果構造函數返回了一個“對象”,那么這個對象會取代整個new出來的結果。如果構造函數沒有返回對象,那么new出來的結果為步驟1創建的對象。<script type="text/javascript"> function Foo1(num){ return 1; }; var foo1 = new Foo1(1); console.log(foo1.__proto__);Foo1{} function Foo2(){ return {};//返回對象,會覆蓋new出來的對象 }; var foo2 = new Foo2; console.log(foo2.__proto__);//Object{}</script>instaceof操作符
語法object instanceof constructor描述instanceof 運算符用來檢測 constructor.prototype 是否存在于參數 object 的原型鏈上
<script type="text/javascript"> console.log(Function.__proto__);//function(){} console.log(Function.prototype);//function(){} console.log(Function.prototype.__proto__);//Object對象 console.log("-----------------------"); console.log(Object.__proto__);//function(){} console.log(Object.prototype);//Object對象 console.log(Object.prototype.__proto__);//null console.log(Function.__proto__==Object.__proto__);//true console.log(Object.prototype == Function.prototype.__proto__);//true console.log(Function instanceof Object);//true console.log(Function.prototype == Object.__proto__);//true console.log(Object instanceof Function);//true console.log(Function.prototype == Function.__proto__);//true console.log(Function instanceof Function);//true</script>參考:http://blog.csdn.net/cuew1987/article/details/15498121http://www.blogjava.net/heavensay/archive/2013/10/20/405440.html
新聞熱點
疑難解答