回到了自己的家鄉,期待中有感覺到了很多的陌生,一個有“故事”的環境中,你我是否“孤獨”!
函數的類型
在我看來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對象自己的屬性