胡說-JavaScript函式型別

胖先森發表於2019-03-02

回到了自己的家鄉,期待中有感覺到了很多的陌生,一個有“故事”的環境中,你我是否“孤獨”!

函式的型別

在我看來function共有三種型別,作為物件使用,處理業務以及穿件object的例項物件。跟這三種用法相對應的有三種子型別,分別是物件的屬性、變數(包括引數)和建立出來的object型別例項物件的屬性。這三種子類是相互獨立的,而且也很容易區分。但是,我們剛剛接觸的時候很容易混淆。

1.function 作為物件來使用

這種情況下,function物件的子型別就是物件自己的屬性,這時通過操作符“.”(或者方括號操作符)使用,示例如下:

function book(){}
book.price=999;
book["getPrice"]=function(){
    return this.price;
}
console.log(book.getPrice()); //輸出結果:999
複製程式碼

我很少碰到function來作為object型別的物件來使用。

2.funciton 用於處理業務

這種情況下,function的子型別就是自己定義的區域性變數(包括引數),這時的變數實在方法被呼叫時通過變數作用域鏈來管理的。
關於變數我之前的文件中有涉及到,這裡就不過多的說明了。

3.function 用於建立物件

這種情況下,對應的子型別是使用function建立例項物件的屬性(很常用),主要包括在function中通過this新增屬性,以及建立完成之後例項物件自己新增的屬性。另外,還可以呼叫function的prototype屬性物件所包含的屬性,示例如下:

function Car(color,displacement){
    this.color = color;
    this.displacement = displacement;
}
Car.prototype.logMessage = function(){
  console.log(this.color+","+this.displacement);  
};
var car = new Car("yellow","2.4T");//看看是不是類似建構函式?哈哈
複製程式碼

這個例子中建立的car物件就包含有color和displacement兩個屬性,而且還可以呼叫Car.prototype的logMessage方法。當然,建立完之後還可以使用點操作符給建立的car物件新增或者修改屬性,也可以使用delete刪除其中的屬性,示例如下:

function Car(color,displacement){
    this.color = color;
    this.displacement = displacement;
}
//所有建立出來的car都有該方法
Car.prototype.logMessage = function(){
  console.log(this.color+","+this.displacement);  
};
var car = new Car("yellow","2.4T");//看看是不是類似建構函式?哈哈
//給car物件新增屬性
car.logColor = function(){
  console.log(this.color);  
};
//完成呼叫測試
car.logColor();//輸出結果: yellow
car.color = "red";
car.logColor();//輸出結果:red
delete car.color;//刪除屬性
car.logColor();//輸出結果:undefined

複製程式碼

程式碼分析:

在建立完car物件之後,又給它新增了logColor的方法,可以列印car的color屬性。新增完logColor方法後直接呼叫就可以列印出car原來的color屬性值(yellow)。然後,將其修改為red,在列印出了red。最後,使用delete刪除car的color的屬性,這時在呼叫logColor方法會列印出undefined

其實跟我的註釋說明一致!!!

三種子型別的關係

function的三種子型別是相互獨立的,他們只能在自己所對應的環境中使用而不能相互呼叫,示例如下:

function log(msg){//第二種業務處理
    console.log(msg);
}
function Bird(){
    var name = "kitty";
    this.type = "pigeon";
    this.getName = function(){
        return this.name;//建立的物件沒有name屬性
    }
}
Bird.color = "white";//第一種object型別的物件
Bird.getType = function(){//第一種object型別的物件
    return this.type;
};
Bird.prototype.getColor = function(){//第三種建立物件
    return this.color;
}
var bird = new Bird();
log(bird.getColor());// undefined
log(bird.getName()); // undefined
log(bird.getType()); // undefined
複製程式碼

Bird 作為物件時包含 color 和 getType 兩個屬性,作為處理業務的函式是包含一個名為name的區域性變數,建立的例項物件bird具有type和getName兩個屬性,而且還可以呼叫Bird.prototype的getColor屬性,getColor也可以看作bird的屬性。

用 法 子 類 型
物件(Bird) color 、getType
處理業務(Bird方法) name
建立例項物件(bird) type、getName、(getColor)

每種用法中所定義的方法只能呼叫相對應所對應的屬性,而不能交叉呼叫,從對應關係中可以看出,getName、getColor和getType三個方法中無法獲取到值,大家再仔細分析一下!

另外,getName和getColor是bird的屬性方法,getType是Bird的屬性方法,如果用Bird物件呼叫getName或getColor方法或者使用bird物件呼叫getType方法都會丟擲找不到的錯誤。

三種子型別不可以相互進行呼叫之外,還有一種情況也非常重要:那就是物件的屬性並沒有繼承的關係。

function obj(){}
obj.v=1;
obj.func = {
    logV : function(){
        console.log(this.v);
    }
}
obj.func.logV();
複製程式碼

程式碼分析:

這個例子中的obj是作為物件使用的,obj是有一個屬性v和一個物件屬性func,func物件中又有一個logV方法,logV方法用於列印物件的v屬性。這裡需要特別注意:

logV方法列印的是func物件的v屬性,但是func物件中並沒有v屬性,所以最後結果是undefined。

這個例子中,雖然obj物件中包含v屬性,但是由於屬性不可以繼承,所以obj的func屬性物件中的方法不可以使用obj中的屬性v.

請大家一定要記住,並且不要和prototype的繼承以及變數作用域鏈相混淆

關聯三種子型別

三種子型別本來是相互獨立、各有各的使用環境的,但是,有一些情況下需要操作不屬於自己所對應環境的子型別,這時就需要使用一些技巧來實現了。

約定如下

  • function 作為物件使用時記作 O(Object)
  • 作為函式使用時記作 F(Function)
  • 建立出來的物件例項記作 I(Instance)
  • op(object property)
  • v(variable)
  • ip(instance property)
op v ip
O 直接呼叫 在函式中關聯到O的屬性 不可呼叫
F 使用O呼叫 直接呼叫 不可呼叫
I 使用O呼叫 在函式中關聯到I的屬性 直接呼叫
  • 縱向表頭表示function的不同用法

  • 橫向表頭表示三種型別,表格的主體表示在function相應用法中呼叫各種子類的方法。

    因為function建立的例項物件在建立之前還不存在,所以function作為方法(F)和作為物件(O)使用時無法呼叫function建立的例項物件的屬性(ip)。呼叫引數可以在函式中將變數關聯到相應的屬性,呼叫function作為物件(O)時的屬性可以直接使用 function 物件來呼叫

function log(msg){
    console.log(msg);
}
function Bird(){
    //私有屬性
    var name = "kitty";
    var type = "pigeon";
    //將區域性變數name關聯到新建立的物件的getName,setName屬性方法
    //閉包可以使用區域性變數
    //公有屬性
    this.getName = function(){
        return name;
    }
    this.setName = function(n){
        name = n;
    }
    //將區域性變數type關聯到Bird物件getType屬性方法
    //靜態屬性
    Bird.type = function(){
        return type;
    }
    //在業務處理中呼叫Bird物件的color屬性
    log(Bird.color);//輸出結果: white,F呼叫op
    
}
Bird.color = "white";// 代表 O
//在建立出的例項物件中呼叫Bird物件的color屬性
Bird.prototype.getColor = function(){//I
    return Bird.color;//OP
}
var bird = new Bird(); // 建立例項 I
log(bird.getColor()); // 輸出結果:white , I 呼叫 op
log(bird.getName());// 輸出結果:kitty , I 呼叫 v 區域性變數
log(Bird.getType());// 輸出結果:pigeon , O 呼叫 v 區域性變數
bird.setName("petter");  // I 呼叫 v
log(bird.getName());// 輸出結果:petter , I 呼叫 v 區域性變數
複製程式碼

好好分析上述的程式碼,非常經典的,瞭解三種子型別的不同環境用法中交叉呼叫的方法

附錄:“公有屬性” “私有屬性” 和 “靜態屬性”

上面的示例中我們涉及到了公有屬性、私有屬性和靜態屬性的說明,由於JS並不是基本類而是基於物件的語言,因此JS本身並沒有這些概念。

  • 公有屬性:一般指使用function物件建立出object例項物件所擁有的屬性。
  • 私有屬性:一般指function的內部變數
  • 靜態屬性:一般指function物件自己的屬性

相關文章