天天看點

prototype 和function關系等總結

js提供了一些内置類,如Array String Function等,隻要有類就有原型。

1,function ,屬性包括 arguments, caller,length,name ,prototype,__proto__,

2,prototype,屬性又分為constructor: function () {},__proto__: Object,

3,__proto__從别的原型鍊繼承過來可以直接用的,prototype是要加在自己原型鍊上的,供别人調用,或者直接執行個體化後,别人可以直接調用轉成__proto__的。

__proto__是永遠存在的,都指向下一層,最終是Object。

4,function 和prototype本身都含__proto__,其實本身也都是對象,自己繼承過來的,他們2個也是基本類型的執行個體。

 js的instanceof是根據prototype來判斷兩個對象是否存在繼承關系,A instanceof B, js會沿着A的原型鍊查找 直到找到A.__proto__ === B.prototype 傳回true。

 一句話__proto__一層層都是指向繼承的,最終到基本類型上。

一,function 

function定義的是一個Object(對象),而且還是一個很特殊的對象,這個使用function定義的對象與使用new操作符生成的對象之間有一個重要的差別。

這個差別就是function定義的對象有一個prototype屬性,使用new生成的對象就沒有這個prototype屬性。

prototype是function的一個屬性。所有通過function 來定義的對象,都有prototype這個屬性。

通過{}定義的對象字面量是沒有prototype的,如

var a ={1:"a"}
console.log (a.prototype);      

 結果是undefined,原因是他已經執行個體化,

var a ={1:"a"}
console.log (a.__proto__);      

結果是 Object {} ,相當于new 後的。

函數的 length 屬性隻能得到他的形參個數,而無法得知實參個數。

function 是Object的執行個體,他自己的__proto__是Object.prototype

var A =function (age ){
  this.age = age; 
}
A.prototype.haha = function (){}
console.log( A instanceof Object)// true 
console.log( typeof A) // function
console.log (Object.prototype.toString.call(A)) //[object Function]      

  

 數組類型typeof 是object,數組跟object更加接近

var B =[1,2,3]
console.log(typeof B)//object
console.log(typeof A)//function      

 

var A =function (age ){
  this.age = age; 
}
A.prototype.haha = function (){}
var B =[1,2,3]
console.log(typeof A)//function
console.log(A instanceof Function)//true
console.log(A instanceof Object)//true
console.log(typeof B)//object
console.log(B instanceof Array)//true
console.log (Object.prototype.toString.call(A)) //[object Object]      

   caller:

   傳回一個對函數的引用,該函數調用了目前函數。

   functionName.caller 

   functionName 對象是所執行函數的名稱。

  說明

   對于函數來說,caller 屬性隻有在函數執行時才有定義。如果函數是由頂層調用的,那麼 caller 包含的就是 null 。如果在字元串上下文中使用 caller 屬性,那麼結果和 functionName.toString 一樣,也就是說,顯示的是函數的反編譯文本。

var A =function (age ){
   this.age = age;
   console.log(A.caller)   
}
A.prototype.haha = function (){}
var B = function(type){
   A();  
}
B();      

  傳回,最後是B的函數,誰調用我了,傳回誰

function (type){
   A();    
}      

arguments.callee :傳回正被執行的 Function 對象,也就是所指定的 Function 對象的正文。

     [function.]arguments.callee

          可選項 function 參數是目前正在執行的 Function 對象的名稱。

     說明 : callee 屬性的初始值就是正被執行的 Function 對象。

    callee 屬性是 arguments 對象的一個成員,它表示對函數對象本身的引用,這有利于匿名函數的遞歸或者保證函數的封裝性,例如下邊示例的遞歸計算1到n的自然數之和。而該屬性僅當相關函數正在執行時才可用。還有需要注意的是callee擁有length屬性,這個屬性有時候用于驗證還是比較好的。arguments.length是實參長度,arguments.callee.length是

    形參長度,由此可以判斷調用時形參長度是否和實參長度一緻。

二、prototype

本身含constructor,__proto__      
var A =function (age ){
  this.age = age; 
}
A.prototype.haha = function (){}
console.log (A.prototype) ;      

可以看到的内容

Object {haha: function}
constructor: function (age ){
    arguments: null
    caller: null
    length: 1
    name: ""
    prototype: Object
    __proto__: function Empty() {}
    <function scope>
haha: function (){}
__proto__: Object      
constructor實際指向的是 函數建立時的那個function。      
function Animal(name) {
   this.name = name;
}
Animal.prototype = {
    talk: function() {},
    run: function() {}
}
function Dog(age,name) {
   //Animal.call(this,name)  
   this.age=age;
}
// 要讓 Dog 繼承 Animal, 隻需:__ 2個_
Dog.prototype = new  Animal ; // 執行個體化後
Dog.prototype.constructor = Dog;//手工的把constructor給暴露出來了。可以通過dog.constructor來調用
//Dog.prototype = new  Animal ; //Animal的構造函數和自己的prototype也都放到Dog上
Dog.prototype.haha = function () {};//
Dog.prototype.haha.tata = 4;
var dog = new Dog("sdd","bbb"); 
var animal = new Animal("aaaa");
console.log(dog);      
console.log(Dog.prototype);      

  傳回結果如下:

prototype 和function關系等總結

 dog.__proto__.__proto__ === Animal.prototype 傳回的true。

原型鍊作為實作繼承的主要方法,其基本思想是:讓原型對象等于另一個類型的執行個體,這樣原型對象将包含一個指向另一個原型的指針,相應的,另一個原型中也包含着一個指向另一個構造函數的指針,假如另一個原型又是另一個類型的執行個體,如此層層遞進,就構成了執行個體與原型的鍊條,這個鍊條就稱之為原型鍊.

 另外一個問題,prototype是存儲放到共享區域内的,可以共同修改。

Dog.prototype = Animal.prototype的方法內建,如果子類重寫了父類的方法,父類也會受到影響。      

   推薦的用法是 

Dog.prototype.__proto__ = Animal.prototype      

不用寫Dog.prototype.constructor = Dog了,constructor 沒有被覆寫,Dog本身就有了。

參考可以看下下面的例子

代碼 

function Person(name)   
{   
   this.name=name;   
   this.showMe=function()   
        {   
           alert(this.name);   
        }   
};   

Person.prototype.from=function()   
{   
  alert('I come from prototype.');   
}   
var father=new Person('js');//為了下面示範使用showMe方法,采用了js參數,實際多采用無參數   
alert(father.constructor);//檢視構造函數,結果是:function Person(name) {...};   
function SubPer()   
{   
}   
SubPer.prototype=father;//注意這裡   
SubPer.prototype.constructor=SubPer;   

var son=new SubPer();   
son.showMe();//js   
son.from();//I come from prototype.   
alert(father.constructor);//function SubPer(){...}   
alert(son.constructor);//function SubPer(){...}   
alert(SubPer.prototype.constructor);//function SubPer(){...}      

 關于prototype是共享和prototype的作用域問題

function Tree(x){
  this.value = x; 
}
Tree.prototype.children = [1,2];

var a =new Tree(2);
a.children=3;
var b = new Tree(4);
b.children=5;
var c = new Tree(6); 
console.log (c.children)//[1,2]      

 這個對 a.__proto_ 沒有做修改,最後依然是 a.__proto_ === Tree.prototype

   a.children=3,相當于在a這個對象下面直接加了個children的屬性。

function Tree(x){
  this.value = x; 
}
Tree.prototype.children = [1,2];

var a =new Tree(2);
a.children.push("3");
var b = new Tree(4);
b.children.push("5");
var c = new Tree(6); 
console.log (c.children);//[1,2,"3","5"]      

  a.children相當于開始是undefined,如果直接複制的話,就是在a對象下加屬性了,然後在.操作,相當于從原型鍊上去取了。

var A = function(b){
     this.b =b; 
}
A.prototype.hh="222";

$.extend(A.prototype,{
  b:"333",
  hh:"444"  
});
var a = new A();
console.log(a);      
  1. b: undefined
  2. __proto__: Object
  1. b: "333"
  2. constructor: function (b){
  1. arguments: null
  2. caller: null
  3. length: 1
  4. name: ""
  5. prototype: Object
  6. __proto__: function Empty() {}
  7. <function scope>
  1. hh: "444"

繼續閱讀