欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript的函數(shù)

 更新時(shí)間:2007年01月31日 00:00:00   作者:  
作者:F. Permadi
譯者:Sheneyan(子烏)
時(shí)間:2006.01.03
英文原文: INTRODUCTION TO JavaScript Functions
中文譯文(包括示例):javascript的函數(shù)
子烏注:一篇相當(dāng)不錯(cuò)的function入門文章,個(gè)人感覺(jué)相當(dāng)經(jīng)典。

詞語(yǔ)翻譯列表
function:函數(shù)(Function未翻譯)
declare:定義
assign:指派,分配
functionbody:函數(shù)體(就是函數(shù)的內(nèi)容)
object:對(duì)象
property:屬性
unnamed:匿名(在這里沒(méi)翻譯成未命名)
object oriented programming:面相對(duì)相編程
class:類(比如后面的class data type我翻譯成類數(shù)據(jù)類型)
pointer:指針
reassign:重新分配
nest:嵌套
feature:功能,特性
local/global:局部/全局
blueprint:藍(lán)圖(?)
user defined:用戶自定義
instance:實(shí)例
prototype:原型(除了標(biāo)題都不翻譯)
internal:內(nèi)部
constructor:構(gòu)造器
duplication:

函數(shù):定義

  有以下這些方法可以定義一個(gè)函數(shù)。所有這些都是有效的,但是它們?cè)诤笈_(tái)如何實(shí)現(xiàn)的則有一些差別。

  一般大家都用這個(gè)寫(xiě)法來(lái)定義一個(gè)函數(shù):


[Copy to clipboard]CODE:
functionName([parameters]){functionBody};

Example D1:


[Copy to clipboard]CODE:
function add(a, b) 
{                     
  return a+b;
}                     
alert(add(1,2));        // 結(jié)果 3

  當(dāng)我們這么定義函數(shù)的時(shí)候,函數(shù)內(nèi)容會(huì)被編譯(但不會(huì)立即執(zhí)行,除非我們?nèi)フ{(diào)用它)。而且,也許你不知道,當(dāng)這個(gè)函數(shù)創(chuàng)建的時(shí)候有一個(gè)同名的對(duì)象也被創(chuàng)建。就我們的例子來(lái)說(shuō),我們現(xiàn)在有一個(gè)對(duì)象叫做“add”(要更深入了解,看底下函數(shù):對(duì)象節(jié)。)
  我們也可以通過(guò)指派一個(gè)變量名給匿名函數(shù)的方式來(lái)定義它。

Example D2 


[Copy to clipboard]CODE:
var add=function(a, b) 
{                     
  return a+b;
}                     
alert(add(1,2));        // 結(jié)果 3

  這個(gè)代碼和前一個(gè)例子做了同樣的事情。也許語(yǔ)法看起來(lái)比較奇怪,但它應(yīng)該更能讓你感覺(jué)到函數(shù)是一個(gè)對(duì)象,而且我們只是為這個(gè)對(duì)指派了一個(gè)名稱??梢园阉醋龊?nbsp;var myVar=[1,2,3]一樣的語(yǔ)句。以這種方式聲明的函數(shù)內(nèi)容也一樣會(huì)被編譯。
  當(dāng)我們指派一個(gè)這樣的函數(shù)的時(shí)候,我們并不一定要求必須是匿名函數(shù)。在這里,我作了和ExampleD2一樣的事情,但我加了函數(shù)名“theAdd”,而且我可以通過(guò)調(diào)用函數(shù)名或者是那個(gè)變量來(lái)引用函數(shù)。

Example D2A


[Copy to clipboard]CODE:
var add=function theAdd(a, b) 
{                     
  return a+b;
}                     
alert(add(1,2));           // 結(jié)果 3
alert(theAdd(1,2));        // 結(jié)果也是 3

  使用這種方式來(lái)定義函數(shù)在面向?qū)ο缶幊讨惺呛苡杏玫?,因?yàn)槲覀兡芟竦紫逻@樣使一個(gè)函數(shù)成為一個(gè)對(duì)象的屬性。


[Copy to clipboard]CODE:
var myObject=new Object();
myObject.add=function(a,b){return a+b};  
// myObject 現(xiàn)在有一個(gè)叫做“add”的屬性(或方法)
// 而且我能夠象下面這樣使用它
myObject.add(1, 2);

  我們也能夠通過(guò)使用運(yùn)算符new來(lái)定義一個(gè)函數(shù)。這是一個(gè)最少見(jiàn)的定義函數(shù)的方式并且并不推薦使用這種方式除非有特殊的理由(可能的理由見(jiàn)下)。語(yǔ)法如下:


[Copy to clipboard]CODE:
varName=new Function([param1Name, param2Name,...paramNName], functionBody);

Example D3: 


[Copy to clipboard]CODE:
var add=new Function("a", "b", "return a+b;");
alert(add(3,4));        // 結(jié)果 7

  我在這里有兩個(gè)參數(shù)叫做a和b,而函數(shù)體返回a和b的和。請(qǐng)注意new Function(...)使用了大寫(xiě)F,而不是小寫(xiě)f。 這就告訴javascript,我們將要?jiǎng)?chuàng)建一個(gè)類型是Function的對(duì)象。 還要注意到,參數(shù)名和函數(shù)體都是作為字符串而被傳遞。我們可以隨心所欲的增加參數(shù),javascript知道函數(shù)體會(huì)是右括號(hào)前的最后一個(gè)字符串(如果沒(méi)有參數(shù),你能夠只寫(xiě)函數(shù)體)。你沒(méi)必要將所有東西都寫(xiě)在一行里(使用\或者使用字符串連接符+來(lái)分隔長(zhǎng)代碼)。\標(biāo)記告訴JavaScript在下一行查找字符串的其余部分。例子如下:

Example D4 


[Copy to clipboard]CODE:
// 注意 "+"
// 和 "\"的不同用法
var add=new Function("a", "b", 
  "alert" +                      
  "('adding '+a+' and ' +b);\
   return a+b;");
alert(add(3,4));        // 結(jié)果 7

  采用這種方式定義函數(shù)會(huì)導(dǎo)致函數(shù)并沒(méi)被編譯,而且它有可能會(huì)比用其它方式定義的函數(shù)要慢。至于為什么,看一下這個(gè)代碼:

Example D5


[Copy to clipboard]CODE:
function createMyFunction(myOperator)
{
  return new Function("a", "b", "return a" + myOperator + "b;");
}

var add=createMyFunction("+");                // 創(chuàng)建函數(shù) "add" 
var subtract=createMyFunction("-");           // 創(chuàng)建函數(shù) "subtract" 
var multiply=createMyFunction("*");           // 創(chuàng)建函數(shù) "multiply" 
// test the functions
alert("加的結(jié)果="+add(10,2));                  // 結(jié)果是 12
alert("減的結(jié)果="+subtract(10,2));             // 結(jié)果是 8
alert("乘的結(jié)果="+multiply(10,2));             // 結(jié)果是 20
alert(add);

  這個(gè)有趣的例子創(chuàng)建了三個(gè)不同的function,通過(guò)實(shí)時(shí)傳遞不同的參數(shù)來(lái)創(chuàng)建一個(gè)新Function。因?yàn)榫幾g器沒(méi)法知道最終代碼會(huì)是什么樣子的,所以new Function(...)的內(nèi)容不會(huì)被編譯。那這有什么好處呢?嗯,舉個(gè)例子,如果你需要用戶能夠創(chuàng)建他們自己的函數(shù)的時(shí)候這個(gè)功能也許很有用,比如在游戲里。我們也許需要允許用戶添加“行為”給一個(gè)“player”。但是,再說(shuō)一次,一般情況下,我們應(yīng)該避免使用這種形式,除非有一個(gè)特殊的目的。


函數(shù):對(duì)象
  函數(shù)是javascript中的一種特殊形式的對(duì)象。它是第一個(gè)[b〕類數(shù)據(jù)類型(class data type)。這意味著我們能夠給它增加屬性。這里有一些需要注意的有趣觀點(diǎn): 

  就像剛才提及的,當(dāng)我們定義一個(gè)函數(shù)時(shí),javascript實(shí)際上在后臺(tái)為你創(chuàng)建了一個(gè)對(duì)象。這個(gè)對(duì)象的名稱就是函數(shù)名本身。這個(gè)對(duì)象的類型是function。在下面的例子,我們也許不會(huì)意識(shí)到這一點(diǎn),但我們實(shí)際上已經(jīng)創(chuàng)建了一個(gè)對(duì)象:它叫做Ball。

Example 1 


[Copy to clipboard]CODE:
function Ball()       // 也許看起來(lái)有點(diǎn)奇怪,但是這個(gè)聲明
{                     // 創(chuàng)建了一個(gè)叫做Ball的對(duì)象
  i=1;
}                     
alert(typeof Ball);     // 結(jié)果 "function"

  我們甚至能將這個(gè)對(duì)象的內(nèi)容打印出來(lái)而且它會(huì)輸出這個(gè)函數(shù)的實(shí)際代碼,Example 2: 點(diǎn)擊 alert(Ball);來(lái)看看Ball的內(nèi)容。
  我們能夠添加給Object添加屬性,包括對(duì)象function。因?yàn)槎x一個(gè)函數(shù)的實(shí)質(zhì)是創(chuàng)建一個(gè)對(duì)象。我們能夠“暗地里”給函數(shù)添加屬性。比如,我們這里定義了函數(shù)Ball,并添加屬性callsign。


[Copy to clipboard]CODE:
function Ball()       // 也許看起來(lái)有點(diǎn)奇怪,但是這個(gè)聲明
{                     // 創(chuàng)建了一個(gè)叫做Ball的對(duì)象,而且你能夠
}                     // 引用它或者象下面那樣給它增加屬性
Ball.callsign="The Ball"; // 給Ball增加屬性
alert(Ball.callsign); // 輸出 "The Ball"

  因?yàn)閒unction是一個(gè)對(duì)象,我們能夠?yàn)橐粋€(gè)function分配一個(gè)指針。如下例,變量ptr指向了對(duì)象myFunction。


[Copy to clipboard]CODE:
function myFunction(message) 

  alert(message);
}
var ptr=myFunction;  // ptr指向了myFunction
ptr("hello");         // 這句會(huì)執(zhí)行myFunction:輸出"hello"

  我們能夠運(yùn)行這個(gè)函數(shù),就好像這個(gè)函數(shù)名已經(jīng)被指針名代替了一樣。所以在上面,這行ptr("hello"); 和myFunction("hello");的意義是一樣的。
  指向函數(shù)的指針在面向?qū)ο缶幊讨邢喈?dāng)有用。例如:當(dāng)我們有多個(gè)對(duì)象指向同一個(gè)函數(shù)的時(shí)候(如下):

Example 4A 


[Copy to clipboard]CODE:
function sayName(name) 

  alert(name);
}
var object1=new Object();      // 創(chuàng)建三個(gè)對(duì)象
var object2=new Object();
var object3=new Object();
object1.sayMyName=sayName;       // 將這個(gè)函數(shù)指派給所有對(duì)象
object2.sayMyName=sayName;
object3.sayMyName=sayName;

object1.sayMyName("object1");    // 輸出 "object1"
object2.sayMyName("object2");    // 輸出 "object2"
object3.sayMyName("object3");    // 輸出 "object3"



  因?yàn)橹挥兄羔槺槐4妫ǘ皇呛瘮?shù)本身),當(dāng)我們改變函數(shù)對(duì)象自身的時(shí)候,所有指向那個(gè)函數(shù)的指針都會(huì)發(fā)生變化。我們能夠在底下看到:

Example 5: 


[Copy to clipboard]CODE:
function myFunction() 

  alert(myFunction.message);
}
myFunction.message="old";
var ptr1=myFunction;                 // ptr1 指向 myFunction
var ptr2=myFunction;                 // ptr2 也指向 myFunction

ptr1();                     // 輸出 "old"
ptr2();                              // 輸出 "old"

myFunction.message="new";

ptr1();                     // 輸出 "new"
ptr2();                              // 輸出 "new"

  我們能夠在一個(gè)函數(shù)創(chuàng)建之后重新分配它,但是我們需要指向函數(shù)對(duì)象本身,而不是指向它的指針。在下例中,我將改變myfunction()的內(nèi)容。

Example 6: 


[Copy to clipboard]CODE:
function myFunction() 

  alert("Old");
}
myFunction(); // 輸出 "Old"
myFunction=function()
{
  alert("New");
};
myFunction(); // 輸出 "New"

  舊函數(shù)哪里去了??被拋棄了。


  如果我們需要保留它,我們可以在改變它之前給它分配一個(gè)指針。

Example 6A: 


[Copy to clipboard]CODE:
function myFunction() 

  alert("Old");
}
var savedFuncion=myFunction;
myFunction=function()
{
  alert("New");
};
myFunction();    // 輸出 "New"
savedFuncion();  // 輸出 "Old"



  不過(guò)要小心,象下面這樣的例子并不會(huì)有作用,因?yàn)槭莿?chuàng)建了另一個(gè)叫做myFunctionPtr的函數(shù)而不是修改它。

Example 6B: 


[Copy to clipboard]CODE:
function myFunction() 

  alert("Old");
}
var savedFunc=myFunction;
savedFunc=function()
{
  alert("New");
};
myFunction();            // 輸出 "Old"
savedFunc();             // 輸出 "New"

  我們還能夠在一個(gè)函數(shù)中嵌套一個(gè)函數(shù)。下例,我有一個(gè)叫做getHalfOf的函數(shù),而在它里面,我有另一個(gè)叫做calculate的函數(shù)。

Example 7 


[Copy to clipboard]CODE:
function getHalfOf(num1, num2, num3)     

  function calculate(number)
  {
    return number/2;
  }

  var result="";
  result+=calculate(num1)+" ";
  result+=calculate(num2)+" ";
  result+=calculate(num3);
  return result;
}         
var resultString=getHalfOf(10,20,30);
alert(resultString);         // 輸出 "5 10 15"

  你只能在內(nèi)部調(diào)用嵌套的函數(shù)。就是說(shuō),你不能這么調(diào)用:getHalfOf.calculate(10),因?yàn)閏alculate只有當(dāng)外部函數(shù)(getHalfOf())在運(yùn)行的時(shí)候才會(huì)存在。這和我們前面的討論一致(函數(shù)會(huì)被編譯,但只有當(dāng)你去調(diào)用它的時(shí)候才會(huì)執(zhí)行)。
  你也許正在想命名沖突的問(wèn)題。比如,下面哪一個(gè)叫做calculate的函數(shù)會(huì)被調(diào)用?

Example 8 


[Copy to clipboard]CODE:
function calculate(number)
{
  return number/3;
}

function getHalfOf(num1, num2, num3)     

  function calculate(number)
  {
    return number/2;
  }

  var result="";
  result+=calculate(num1)+" ";
  result+=calculate(num2)+" ";
  result+=calculate(num3);
  return result;
}         
var resultString=getHalfOf(10,20,30);
alert(resultString);         // 輸出 "5 10 15"

  在這個(gè)例子中,編譯器會(huì)首先搜索局部?jī)?nèi)存地址,所以它會(huì)使用內(nèi)嵌的calculate函數(shù)。如果我們刪除了這個(gè)內(nèi)嵌(局部)的calculate函數(shù),這個(gè)代碼會(huì)使用全局的calculate函數(shù)。

函數(shù):數(shù)據(jù)類型及構(gòu)造函數(shù)

  讓我們來(lái)看看函數(shù)的另一個(gè)特殊功能--這讓它和其它對(duì)象類型截然不同。一個(gè)函數(shù)能夠用來(lái)作為一個(gè)數(shù)據(jù)類型的藍(lán)圖。這個(gè)特性通常被用在面向?qū)ο缶幊讨衼?lái)模擬用戶自定義數(shù)據(jù)類型(user defined data type)。使用用戶自定義數(shù)據(jù)類型創(chuàng)建的對(duì)象通常被成為用戶自定義對(duì)象(user defined object)。

  在定義了一個(gè)函數(shù)之后,我們也同時(shí)創(chuàng)建了一個(gè)新的數(shù)據(jù)類型。這個(gè)數(shù)據(jù)類型能夠用來(lái)創(chuàng)建一個(gè)新對(duì)象。下例,我創(chuàng)建了一個(gè)叫做Ball的新數(shù)據(jù)類型。

Example DT1 


[Copy to clipboard]CODE:
function Ball()
{
}
var ball0=new Ball(); // ball0 現(xiàn)在指向一個(gè)新對(duì)象

alert(ball0);         // 輸出 "Object",因?yàn)?nbsp;ball0 現(xiàn)在是一個(gè)對(duì)象

  這樣看來(lái),ball0=new Ball()作了什么?new關(guān)鍵字創(chuàng)建了一個(gè)類型是Object的新對(duì)象(叫做ball0)。然后它會(huì)執(zhí)行Ball(),并將這個(gè)引用傳給ball0(用于調(diào)用對(duì)象)。下面,你會(huì)看到這條消息:“creating new Ball”,如果Ball()實(shí)際上被運(yùn)行的話。

Example DT2 


[Copy to clipboard]CODE:
function Ball(message)
{
  alert(message);
}
var ball0=new Ball("creating new Ball");  // 創(chuàng)建對(duì)象并輸出消息
ball0.name="ball-0";                      // ball0現(xiàn)在有一個(gè)屬性:name
alert(ball0.name);                        // 輸出 "ball-0"

  我們可以把上面這段代碼的第6行看做是底下的代碼6-8行的一個(gè)簡(jiǎn)寫(xiě):


[Copy to clipboard]CODE:
function Ball(message)
{
  alert(message);
}
var ball0=new Object();
ball0.construct=Ball;
ball0.construct("creating new ball");  // 執(zhí)行 ball0.Ball("creating..");
ball0.name="ball-0";                      
alert(ball0.name);         

  這行代碼ball0.construct=Ball和Example 4中的ptr=myFunction語(yǔ)法一致。
  如果你還是不明白這行的含義那就回過(guò)頭再?gòu)?fù)習(xí)一下Example 4。注意:你也許考慮直接運(yùn)行ball0.Ball("..."),但是它不會(huì)起作用的,因?yàn)閎all0并沒(méi)有一個(gè)叫做Ball("...")的屬性,并且它也不知道你究竟想作些什么。
  當(dāng)我們象上面那樣使用關(guān)鍵字new創(chuàng)建一個(gè)對(duì)象的時(shí)候,一個(gè)新的Object被創(chuàng)建了。我們可以在創(chuàng)建之后給這個(gè)對(duì)象添加屬性(就好像我在上面那樣添加屬性name。而接下來(lái)的問(wèn)題就是如果我們創(chuàng)建了這個(gè)對(duì)象的另外一個(gè)實(shí)例,我們得象下面那樣再次給這個(gè)新對(duì)象添加這個(gè)屬性。)

Example DT3 (creates 3 ball objects) 


[Copy to clipboard]CODE:
function Ball()
{
}
var ball0=new Ball(); // ball0 現(xiàn)在指向了類型Ball的一個(gè)新實(shí)例
ball0.name="ball-0";  // ball0 現(xiàn)在有一個(gè)屬性"name"

var ball1=new Ball();
ball1.name="ball-1";

var ball2=new Ball();

alert(ball0.name);    // 輸出 "ball-0"
alert(ball1.name);    // 輸出 "ball-1"
alert(ball2.name);    // 哦,我忘記給ball2添加“name”了!

  我忘記給ball2添加屬性name了,如果在正式的程序中這也許會(huì)引發(fā)問(wèn)題。有什么好辦法可以自動(dòng)增加屬性呢?嗯,有一個(gè):使用this關(guān)鍵字。this這個(gè)詞在function中有特別的意義。它指向了調(diào)用函數(shù)的那個(gè)對(duì)象。讓我們看看下面的另一個(gè)示例,這時(shí)候我們?cè)跇?gòu)造函數(shù)中添加上這些屬性:

Example DT4 


[Copy to clipboard]CODE:
function Ball(message, specifiedName)
{
  alert(message);
  this.name=specifiedName;                
}
var ball0=new Ball("creating new Ball", "Soccer Ball");  
alert(ball0.name);                   // prints "Soccer Ball"

  請(qǐng)記?。菏莕ew關(guān)鍵字最終使得構(gòu)造函數(shù)被執(zhí)行。在這個(gè)例子中,它將會(huì)運(yùn)行Ball("creating new Ball", "Soccer Ball");而關(guān)鍵字this將指向ball0。
  因此,這行:this.name=specifiedName變成了ball0.name="Soccer Ball"。
  它主要是說(shuō):給ball0添加屬性name,屬性值是Soccer Ball。 
  我們現(xiàn)在只是添加了一個(gè)name屬性給ball0,看起來(lái)和上一個(gè)例子中所做的很象,但卻是一個(gè)更好更具擴(kuò)展性的方法。現(xiàn)在,我們可以隨心所欲的創(chuàng)建許多帶有屬性的ball而無(wú)需我們手動(dòng)添加它們。而且,人們也希望創(chuàng)建的Ball對(duì)象能夠清晰的看懂它的構(gòu)造函數(shù)并且能夠輕松找出Ball的所有屬性。讓我們添加更多屬性到Ball里。

Example DT5


[Copy to clipboard]CODE:
function Ball(color, specifiedName, owner, weight)
{
  this.name=specifiedName;                
  this.color=color;
  this.owner=owner;
  this.weight=weight;
}
var ball0=new Ball("black/white", "Soccer Ball", "John", 20);  
var ball1=new Ball("gray", "Bowling Ball", "John", 30);  
var ball2=new Ball("yellow", "Golf Ball", "John", 55);  
var balloon=new Ball("red", "Balloon", "Pete", 10);  

alert(ball0.name);                        // 輸出 "Soccer Ball"
alert(balloon.name);                      // 輸出 "Balloon"
alert(ball2.weight);                      // 輸出 "55"

  嘿!使用面向?qū)ο笮g(shù)語(yǔ),你能夠說(shuō)Ball是一個(gè)擁有如下屬性的對(duì)象類型:name, color, owner, weight。 
  我們并沒(méi)被限制只能添加形如字符串或者數(shù)字之類的簡(jiǎn)單數(shù)據(jù)類型作為屬性。我們也能夠?qū)?duì)象賦給屬性。下面,supervisor是Employee的一個(gè)屬性.

Example DT6 


[Copy to clipboard]CODE:
function Employee(name, salary, mySupervisor)
{
  this.name=name;                
  this.salary=salary;
  this.supervisor=mySupervisor;
}
var boss=new Employee("John", 200);

var manager=new Employee("Joan", 50, boss);  
var teamLeader=new Employee("Rose", 50, boss);  

alert(manager.supervisor.name+" is the supervisor of "+manager.name);
alert(manager.name+"\'s supervisor is "+manager.supervisor.name);  

  會(huì)輸出什么呢?
  就像你在上面這個(gè)例子中看到的那樣,manager和teamLeader都有一個(gè)supervisor屬性,而這個(gè)屬性是類型Employee的一個(gè)對(duì)象。
  任何類型的對(duì)象都可以作為一個(gè)屬性,回憶一下前面的Example 4(不是Example DT4),函數(shù)也是一個(gè)對(duì)象。所以你可以讓一個(gè)函數(shù)作為一個(gè)對(duì)象的一個(gè)屬性。下面,我將添加兩個(gè)函數(shù)getSalary和addSalary。

Example DT7 


[Copy to clipboard]CODE:
function Employee(name, salary)
{
  this.name=name;                
  this.salary=salary;

  this.addSalary=addSalaryFunction;

  this.getSalary=function()
                 {
                   return this.salary;
                 };
}
function addSalaryFunction(addition)
{
  this.salary=this.salary+addition;
}

var boss=new Employee("John", 200000);
boss.addSalary(10000);                    // boss 長(zhǎng)了 10K 工資……為什么老板工資可以長(zhǎng)這么多:'(
alert(boss.getSalary());                  // 輸出 210K……為什么默認(rèn)工資也那么高……:'(

  addSalary和getSalary演示了幾種將函數(shù)賦給屬性的不同方法。如果你記得我們最開(kāi)始的討論;我討論了三種聲明函數(shù)的不同方式。所有那些在這里都是適用的,但是上面展示的兩個(gè)最常用。
  讓我們看看有什么不同。下面,注意一下9-12行的代碼。當(dāng)這部分代碼執(zhí)行的時(shí)候,函數(shù)getSalary被聲明。如前面數(shù)次提到的,一個(gè)函數(shù)聲明的結(jié)果是一個(gè)對(duì)象被創(chuàng)建。所以這時(shí)候boss被創(chuàng)建(接下來(lái)的第19行),而boss里有一個(gè)getSalary屬性。


[Copy to clipboard]CODE:
function Employee(name, salary)
{
  this.name=name;                
  this.salary=salary;

  this.addSalary=addSalaryFunction;

  this.getSalary=function()
                 {
                   return this.salary;
                 };
}
function addSalaryFunction(addition)
{
  this.salary=this.salary+addition;
}

var boss=new Employee("John", 200000);
var boss2=new Employee("Joan", 200000);
var boss3=new Employee("Kim", 200000);


  當(dāng)你創(chuàng)建這個(gè)對(duì)象的更多實(shí)例時(shí)(boss2和boss3),每一個(gè)實(shí)例都有一份getSalary代碼的單獨(dú)拷貝;而與此相反,addSalary則指向了同一個(gè)地方(即addSalaryFunction)。  

  看看下面的代碼來(lái)理解一下上面所描述的內(nèi)容。

Example DT8


[Copy to clipboard]CODE:
function Employee(name, salary)
{
  this.name=name;                
  this.salary=salary;

  this.addSalary=addSalaryFunction;
  this.getSalary=function()
                 {
                   return this.salary;
                 };
}
function addSalaryFunction(addition)
{
  this.salary=this.salary+addition;
}

var boss1=new Employee("John", 200000);
var boss2=new Employee("Joan", 200000);


// 給getSalary函數(shù)對(duì)象添加屬性
boss1.getSalary.owner="boss1";
boss2.getSalary.owner="boss2";
alert(boss1.getSalary.owner);   // 輸出 "boss1"
alert(boss2.getSalary.owner);   // 輸出 "boss2"
// 如果兩個(gè)對(duì)象指向同一個(gè)函數(shù)對(duì)象,那么
// 上面兩個(gè)輸出都應(yīng)該是“boss2”。

// 給addSalary函數(shù)對(duì)象添加屬性
boss1.addSalary.owner="boss1";
boss1.addSalary.owner="boss2";
alert(boss1.addSalary.owner);   // 輸出 "boss2"
alert(boss2.addSalary.owner);   // 輸出 "boss2"
// 因?yàn)閮蓚€(gè)對(duì)象都指向同一個(gè)函數(shù),(子烏注:原文寫(xiě)are not pointing to the same function,疑為筆誤)
// 當(dāng)修改其中一個(gè)的時(shí)候,會(huì)影響所有的實(shí)例(所以兩個(gè)都輸出“boss2”).


  也許不是重要的事情,但這里有一些關(guān)于運(yùn)行類似上面的getSalary的內(nèi)嵌函數(shù)的結(jié)論: 1) 需要更多的存儲(chǔ)空間來(lái)存儲(chǔ)對(duì)象(因?yàn)槊恳粋€(gè)對(duì)象實(shí)例都會(huì)有它自己的getSalary代碼拷貝);2) javascript需要更多時(shí)間來(lái)構(gòu)造這個(gè)對(duì)象。
  讓我們重新寫(xiě)這個(gè)示例來(lái)讓它更有效率些。

Example DT9


[Copy to clipboard]CODE:
function Employee(name, salary)
{
  this.name=name;                
  this.salary=salary;

  this.addSalary=addSalaryFunction;
  this.getSalary=getSalaryFunction;
}
function getSalaryFunction()
{
  return this.salary;
}

function addSalaryFunction(addition)
{
  this.salary=this.salary+addition;
}

  看這兒,兩個(gè)函數(shù)都指向同一個(gè)地方,這將會(huì)節(jié)約空間和縮短構(gòu)造時(shí)間(特別是當(dāng)你有一大堆內(nèi)嵌函數(shù)在一個(gè)構(gòu)造函數(shù)的時(shí)候)。這里有另外一個(gè)函數(shù)的功能能夠來(lái)提升這個(gè)設(shè)計(jì),它叫做prototype,而我們將在下一節(jié)討論它。

函數(shù):原型
  每一個(gè)構(gòu)造函數(shù)都有一個(gè)屬性叫做原型(prototype,下面都不再翻譯,使用其原文)。這個(gè)屬性非常有用:為一個(gè)特定類聲明通用的變量或者函數(shù)。

  你不需要顯式地聲明一個(gè)prototype屬性,因?yàn)樵诿恳粋€(gè)構(gòu)造函數(shù)中都有它的存在。你可以看看下面的例子:

Example PT1 


[Copy to clipboard]CODE:
function Test()
{
}
alert(Test.prototype);  // 輸出 "Object"

  就如你在上面所看到的,prototype是一個(gè)對(duì)象,因此,你能夠給它添加屬性。你添加給prototype的屬性將會(huì)成為使用這個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象的通用屬性。
  例如,我下面有一個(gè)數(shù)據(jù)類型Fish,我想讓所有的魚(yú)都有這些屬性:livesIn="water"和price=20;為了實(shí)現(xiàn)這個(gè),我可以給構(gòu)造函數(shù)Fish的prototype添加那些屬性。

Example PT2 


[Copy to clipboard]CODE:
function Fish(name, color)
{
  this.name=name;
  this.color=color;
}
Fish.prototype.livesIn="water";
Fish.prototype.price=20;

  接下來(lái)讓我們作幾條魚(yú):


[Copy to clipboard]CODE:
var fish1=new Fish("mackarel", "gray");
var fish2=new Fish("goldfish", "orange");
var fish3=new Fish("salmon", "white");

  再來(lái)看看魚(yú)都有哪些屬性:


[Copy to clipboard]CODE:
for (var i=1; i<=3; i++)
{
  var fish=eval("fish"+i);   // 我只是取得指向這條魚(yú)的指針
  alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price);
}

  輸出應(yīng)該是:


[Copy to clipboard]CODE:
"mackarel, gray, water, 20"
"goldfish, orange, water, 20"
"salmon, white  water, 20" 

  你看到所有的魚(yú)都有屬性livesIn和price,我們甚至都沒(méi)有為每一條不同的魚(yú)特別聲明這些屬性。這時(shí)因?yàn)楫?dāng)一個(gè)對(duì)象被創(chuàng)建時(shí),這個(gè)構(gòu)造函數(shù)將會(huì)把它的屬性prototype賦給新對(duì)象的內(nèi)部屬性__proto__。這個(gè)__proto__被這個(gè)對(duì)象用來(lái)查找它的屬性。
  你也可以通過(guò)prototype來(lái)給所有對(duì)象添加共用的函數(shù)。這有一個(gè)好處:你不需要每次在構(gòu)造一個(gè)對(duì)象的時(shí)候創(chuàng)建并初始化這個(gè)函數(shù)。為了解釋這一點(diǎn),讓我們重新來(lái)看Example DT9并使用prototype來(lái)重寫(xiě)它:

Example PT3 


[Copy to clipboard]CODE:
function Employee(name, salary)
{
  this.name=name;                
  this.salary=salary;
}
Employee.prototype.getSalary=function getSalaryFunction()
{
  return this.salary;
}

Employee.prototype.addSalary=function addSalaryFunction(addition)
{
  this.salary=this.salary+addition;
}

  我們可以象通常那樣創(chuàng)建對(duì)象:


[Copy to clipboard]CODE:
var boss1=new Employee("Joan", 200000);
var boss2=new Employee("Kim", 100000);
var boss3=new Employee("Sam", 150000);

  并驗(yàn)證它:


[Copy to clipboard]CODE:
alert(boss1.getSalary());   // 輸出 200000
alert(boss2.getSalary());   // 輸出 100000
alert(boss3.getSalary());   // 輸出 150000

  這里有一個(gè)圖示來(lái)說(shuō)明prototype是如何工作的。這個(gè)對(duì)象的每一個(gè)實(shí)例(boss1, boss2, boss3)都有一個(gè)內(nèi)部屬性叫做__proto__,這個(gè)屬性指向了它的構(gòu)造器(Employee)的屬性prototype。當(dāng)你執(zhí)行g(shù)etSalary或者addSalary的時(shí)候,這個(gè)對(duì)象會(huì)在它的__proto__找到并執(zhí)行這個(gè)代碼。注意這點(diǎn):這里并沒(méi)有代碼的復(fù)制(和Example DT8的圖表作一下對(duì)比)。

相關(guān)文章

最新評(píng)論