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

javascript的函數

 更新時間:2006年09月07日 00:00:00   作者:  

javascript的函數

子烏注:一篇相當不錯的function入門文章,個人感覺相當經典。

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

函數:定義

有以下這些方法可以定義一個函數。所有這些都是有效的,但是它們在后臺如何實現的則有一些差別。

常用的寫法

一般大家都用這個寫法來定義一個函數:

functionName([parameters]){functionBody};

Example D1:

Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
  1. function add(a, b)
  2. {                     
  3.   return a+b;
  4. }                     
  5. alert(add(1,2));        // 結果 3
  6.  

運行示例

當我們這么定義函數的時候,函數內容會被編譯(但不會立即執(zhí)行,除非我們去調用它)。而且,也許你不知道,當這個函數創(chuàng)建的時候有一個同名的對象也被創(chuàng)建。就我們的例子來說,我們現在有一個對象叫做“add”(要更深入了解,看底下函數:對象節(jié)。)

匿名函數

我們也可以通過指派一個變量名給匿名函數的方式來定義它。

Example D2

Language:javascript, parsed in: 0.006 seconds, using GeSHi 1.0.7.12
  1. var add=function(a, b)
  2. {                     
  3.   return a+b;
  4. }                     
  5. alert(add(1,2));        // 結果 3
  6.  

運行示例

這個代碼和前一個例子做了同樣的事情。也許語法看起來比較奇怪,但它應該更能讓你感覺到函數是一個對象,而且我們只是為這個對指派了一個名稱??梢园阉醋龊?CODE>var myVar=[1,2,3]一樣的語句。以這種方式聲明的函數內容也一樣會被編譯。

當我們指派一個這樣的函數的時候,我們并不一定要求必須是匿名函數。在這里,我作了和ExampleD2一樣的事情,但我加了函數名“theAdd”,而且我可以通過調用函數名或者是那個變量來引用函數。

Example D2A

Language:javascript, parsed in: 0.008 seconds, using GeSHi 1.0.7.12
  1. var add=function theAdd(a, b)
  2. {                     
  3.   return a+b;
  4. }                     
  5. alert(add(1,2));           // 結果 3
  6. alert(theAdd(1,2));        // 結果也是 3
  7.  

運行示例

使用這種方式來定義函數在面向對象編程中是很有用的,因為我們能像底下這樣使一個函數成為一個對象屬性。

Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
  1. var myObject=new Object();
  2. myObject.add=function(a,b){return a+b}
  3. // myObject 現在有一個叫做“add”的屬性(或方法)
  4. // 而且我能夠象下面這樣使用它
  5. myObject.add(1, 2);
  6.  

new

我們也能夠通過使用運算符new來定義一個函數。

這是一個最少見的定義函數的方式并且并不推薦使用這種方式除非有特殊的理由(可能的理由見下)。語法如下:

varName=new Function([param1Name, param2Name,...paramNName], functionBody);

Example D3:

Language:javascript, parsed in: 0.004 seconds, using GeSHi 1.0.7.12
  1. var add=new Function("a", "b", "return a+b;");
  2. alert(add(3,4));        // 結果 7
  3.  

運行示例

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

Example D4

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. // 注意 "+"
  2. // 和 "\"的不同用法
  3. var add=new Function("a", "b",
  4.   "alert" +                     
  5.   "('adding '+a+' and ' +b);\
  6.    return a+b;");
  7. alert(add(3,4));        // 結果 7
  8.  

javascript:exampleD4();

采用這種方式定義函數會導致函數并沒被編譯,而且它有可能會比用其它方式定義的函數要慢。至于為什么,看一下這個代碼:

Example D5

Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
  1. function createMyFunction(myOperator)
  2. {
  3.   return new Function("a", "b", "return a" + myOperator + "b;");
  4. }
  5.  
  6. var add=createMyFunction("+");                // 創(chuàng)建函數 "add"
  7. var subtract=createMyFunction("-");           // 創(chuàng)建函數 "subtract"
  8. var multiply=createMyFunction("*");           // 創(chuàng)建函數 "multiply"
  9. // test the functions
  10. alert("加的結果="+add(10,2));                  // 結果是 12
  11. alert("減的結果="+subtract(10,2));             // 結果是 8
  12. alert("乘的結果="+multiply(10,2));             // 結果是 20
  13. alert(add);
  14.  

運行示例

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

函數:對象

函數是javascript中的一種特殊形式的對象。它是第一個類數據類型。這意味著我們能夠給它增加屬性。這里有一些需要注意的有趣觀點:

對象的創(chuàng)建

就像剛才提及的,當我們定義一個函數時,javascript實際上在后臺為你創(chuàng)建了一個對象。這個對象的名稱就是函數名本身。這個對象的類型是function。在下面的例子,我們也許不會意識到這一點,但我們實際上已經創(chuàng)建了一個對象:它叫做Ball。

Example 1

Language:javascript, parsed in: 0.006 seconds, using GeSHi 1.0.7.12
  1. function Ball()       // 也許看起來有點奇怪,但是這個聲明
  2. {                     // 創(chuàng)建了一個叫做Ball的對象
  3.   i=1;
  4. }                     
  5. alert(typeof Ball);     // 結果 "function"
  6.  

運行示例

我們甚至能將這個對象的內容打印出來而且它會輸出這個函數的實際代碼,Example 2: 點擊 alert(Ball);來看看Ball的內容。

屬性的添加

我們能夠添加給Object添加屬性,包括對象function。因為定義一個函數的實質是創(chuàng)建一個對象。我們能夠“暗地里”給函數添加屬性。比如,我們這里定義了函數Ball,并添加屬性callsign

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. function Ball()       // 也許看起來有點奇怪,但是這個聲明
  2. {                     // 創(chuàng)建了一個叫做Ball的對象,而且你能夠
  3. }                     // 引用它或者象下面那樣給它增加屬性
  4. Ball.callsign="The Ball"; // 給Ball增加屬性
  5. alert(Ball.callsign); // 輸出 "The Ball"
  6.  

運行示例

指針

因為function是一個對象,我們能夠為一個function分配一個指針。如下例,變量ptr指向了對象myFunction。

Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
  1. function myFunction(message)
  2. {
  3.   alert(message);
  4. }
  5. var ptr=myFunction;  // ptr指向了myFunction
  6. ptr("hello");        // 這句會執(zhí)行myFunction:輸出"hello"
  7.  

運行示例

我們能夠運行這個函數,就好像這個函數名已經被指針名代替了一樣。所以在上面,這行ptr("hello"); myFunction("hello");的意義是一樣的。

指向函數的指針在面向對象編程中相當有用。例如:當我們有多個對象指向同一個函數的時候(如下):

Example 4A

Language:javascript, parsed in: 0.017 seconds, using GeSHi 1.0.7.12
  1. function sayName(name)
  2. {
  3.   alert(name);
  4. }
  5. var object1=new Object();      // 創(chuàng)建三個對象
  6. var object2=new Object();
  7. var object3=new Object();
  8. object1.sayMyName=sayName;       // 將這個函數指派給所有對象
  9. object2.sayMyName=sayName;
  10. object3.sayMyName=sayName;
  11. object1.sayMyName("object1");    // 輸出 "object1"
  12. object2.sayMyName("object2");    // 輸出 "object2"
  13. object3.sayMyName("object3");    // 輸出 "object3"
  14.  

運行示例

上例圖示

因為只有指針被保存(而不是函數本身),當我們改變函數對象自身的時候,所有指向那個函數的指針都會發(fā)生變化。我們能夠在底下看到:

Example 5:

Language:javascript, parsed in: 0.016 seconds, using GeSHi 1.0.7.12
  1. function myFunction()
  2. {
  3.   alert(myFunction.message);
  4. }
  5. myFunction.message="old";
  6. var ptr1=myFunction;                 // ptr1 指向 myFunction
  7. var ptr2=myFunction;                 // ptr2 也指向 myFunction
  8.  
  9. ptr1();         // 輸出 "old"
  10. ptr2();                              // 輸出 "old"
  11.  
  12. myFunction.message="new";
  13.  
  14. ptr1();         // 輸出 "new"
  15. ptr2();                              // 輸出 "new"
  16.  

運行示例

指針的指向

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

Example 6:

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. function myFunction()
  2. {
  3.   alert("Old");
  4. }
  5. myFunction(); // 輸出 "Old"
  6. myFunction=function()
  7. {
  8.   alert("New");
  9. };
  10. myFunction(); // 輸出 "New"
  11.  

運行示例

舊函數哪里去了??被拋棄了。

上例圖示

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

Example 6A:

Language:javascript, parsed in: 0.008 seconds, using GeSHi 1.0.7.12
  1. function myFunction()
  2. {
  3.   alert("Old");
  4. }
  5. var savedFuncion=myFunction;
  6. myFunction=function()
  7. {
  8.   alert("New");
  9. };
  10. myFunction();    // 輸出 "New"
  11. savedFuncion()// 輸出 "Old"
  12.  

運行示例

上例圖示

不過要小心,象下面這樣的例子并不會有作用,因為是創(chuàng)建了另一個叫做myFunctionPtr的函數而不是修改它。

Example 6B:

Language:javascript, parsed in: 0.009 seconds, using GeSHi 1.0.7.12
  1. function myFunction()
  2. {
  3.   alert("Old");
  4. }
  5. var savedFunc=myFunction;
  6. savedFunc=function()
  7. {
  8.   alert("New");
  9. };
  10. myFunction();            // 輸出 "Old"
  11. savedFunc();             // 輸出 "New"
  12.  

運行示例

內嵌函數

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

Example 7

Language:javascript, parsed in: 0.015 seconds, using GeSHi 1.0.7.12
  1. function getHalfOf(num1, num2, num3)     
  2. {
  3.   function calculate(number)
  4.   {
  5.     return number/2;
  6.   }
  7.  
  8.   var result="";
  9.   result+=calculate(num1)+" ";
  10.   result+=calculate(num2)+" ";
  11.   result+=calculate(num3);
  12.   return result;
  13. }         
  14. var resultString=getHalfOf(10,20,30);
  15. alert(resultString);         // 輸出 "5 10 15"
  16.  

運行示例

你只能在內部調用嵌套的函數。就是說,你不能這么調用:getHalfOf.calculate(10),因為calculate只有當外部函數(getHalfOf())在運行的時候才會存在。這和我們前面的討論一致(函數會被編譯,但只有當你去調用它的時候才會執(zhí)行)。

調用哪個函數?

你也許正在想命名沖突的問題。比如,下面哪一個叫做calculate的函數會被調用?

Example 8

Language:javascript, parsed in: 0.017 seconds, using GeSHi 1.0.7.12
  1. function calculate(number)
  2. {
  3.   return number/3;
  4. }
  5.  
  6. function getHalfOf(num1, num2, num3)     
  7. {
  8.   function calculate(number)
  9.   {
  10.     return number/2;
  11.   }
  12.  
  13.   var result="";
  14.   result+=calculate(num1)+" ";
  15.   result+=calculate(num2)+" ";
  16.   result+=calculate(num3);
  17.   return result;
  18. }         
  19. var resultString=getHalfOf(10,20,30);
  20. alert(resultString);         // 輸出 "5 10 15"
  21.  

運行示例

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

函數:數據類型及構造函數

讓我們來看看函數的另一個特殊功能--這讓它和其它對象類型截然不同。一個函數能夠用來作為一個數據類型的藍圖。這個特性通常被用在面向對象編程中來模擬用戶自定義數據類型(user defined data type)。使用用戶自定義數據類型創(chuàng)建的對象通常被成為用戶自定義對象(user defined object)。

數據類型

在定義了一個函數之后,我們也同時創(chuàng)建了一個新的數據類型。這個數據類型能夠用來創(chuàng)建一個新對象。下例,我創(chuàng)建了一個叫做Ball的新數據類型。

Example DT1

Language:javascript, parsed in: 0.004 seconds, using GeSHi 1.0.7.12
  1. function Ball()
  2. {
  3. }
  4. var ball0=new Ball(); // ball0 現在指向一個新對象
  5.  
  6. alert(ball0);         // 輸出 "Object",因為 ball0 現在是一個對象
  7.  

運行示例

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

Example DT2

Language:javascript, parsed in: 0.009 seconds, using GeSHi 1.0.7.12
  1. function Ball(message)
  2. {
  3.   alert(message);
  4. }
  5. var ball0=new Ball("creating new Ball")// 創(chuàng)建對象并輸出消息
  6. ball0.name="ball-0";                      // ball0現在有一個屬性:name
  7. alert(ball0.name);                        // 輸出 "ball-0"
  8.  

運行示例

我們可以把上面這段代碼的高亮的一行看做是底下的代碼高亮處的一個簡寫:

Language:javascript, parsed in: 0.010 seconds, using GeSHi 1.0.7.12
  1. function Ball(message)
  2. {
  3.   alert(message);
  4. }
  5. var ball0=new Object();
  6. ball0.construct=Ball;
  7. ball0.construct("creating new ball")// 執(zhí)行 ball0.Ball("creating..");
  8. ball0.name="ball-0";                     
  9. alert(ball0.name);         
  10.  

運行示例

這行代碼ball0.construct=BallExample 4中的ptr=myFunction語法一致。

如果你還是不明白這行的含義那就回過頭再復習一下Example 4。注意:你也許考慮直接運行ball0.Ball("..."),但是它不會起作用的,因為ball0并沒有一個叫做Ball("...")的屬性,并且它也不知道你究竟想作些什么。

添加屬性

當我們象上面那樣使用關鍵字new創(chuàng)建一個對象的時候,一個新的Object被創(chuàng)建了。我們可以在創(chuàng)建之后給這個對象添加屬性(就好像我在上面那樣添加屬性name。而接下來的問題就是如果我們創(chuàng)建了這個對象的另外一個實例,我們得象下面那樣再次給這個新對象添加這個屬性。)

Example DT3 (creates 3 ball objects)

Language:javascript, parsed in: 0.013 seconds, using GeSHi 1.0.7.12
  1. function Ball()
  2. {
  3. }
  4. var ball0=new Ball(); // ball0 現在指向了類型Ball的一個新實例
  5. ball0.name="ball-0"// ball0 現在有一個屬性"name"
  6.  
  7. var ball1=new Ball();
  8. ball1.name="ball-1";
  9.  
  10. var ball2=new Ball();
  11.  
  12. alert(ball0.name);    // 輸出 "ball-0"
  13. alert(ball1.name);    // 輸出 "ball-1"
  14. alert(ball2.name);    // 哦,我忘記給ball2添加“name”了!
  15.  

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

Example DT4

Language:javascript, parsed in: 0.010 seconds, using GeSHi 1.0.7.12
  1. function Ball(message, specifiedName)
  2. {
  3.   alert(message);
  4.   this.name=specifiedName;               
  5. }
  6. var ball0=new Ball("creating new Ball", "Soccer Ball")
  7. alert(ball0.name);                   // prints "Soccer Ball"
  8.  

運行示例

請記?。菏?STRONG>new關鍵字最終使得構造函數被執(zhí)行。在這個例子中,它將會運行Ball("creating new Ball", "Soccer Ball");而關鍵字this將指向ball0。

因此,這行:this.name=specifiedName變成了ball0.name="Soccer Ball"

它主要是說:給ball0添加屬性name,屬性值是Soccer Ball。

我們現在只是添加了一個name屬性給ball0,看起來和上一個例子中所做的很象,但卻是一個更好更具擴展性的方法。現在,我們可以隨心所欲的創(chuàng)建許多帶有屬性的ball而無需我們手動添加它們。而且,人們也希望創(chuàng)建的Ball對象能夠清晰的看懂它的構造函數并且能夠輕松找出Ball的所有屬性。讓我們添加更多屬性到Ball里。

Example DT5

Language:javascript, parsed in: 0.026 seconds, using GeSHi 1.0.7.12
  1. function Ball(color, specifiedName, owner, weight)
  2. {
  3.   this.name=specifiedName;               
  4.   this.color=color;
  5.   this.owner=owner;
  6.   this.weight=weight;
  7. }
  8. var ball0=new Ball("black/white", "Soccer Ball", "John", 20)
  9. var ball1=new Ball("gray", "Bowling Ball", "John", 30)
  10. var ball2=new Ball("yellow", "Golf Ball", "John", 55)
  11. var balloon=new Ball("red", "Balloon", "Pete", 10)
  12.  
  13. alert(ball0.name);                        // 輸出 "Soccer Ball"
  14. alert(balloon.name);                      // 輸出 "Balloon"
  15. alert(ball2.weight);                      // 輸出 "55"
  16.  

運行示例

嘿!使用面向對象術語,你能夠說Ball是一個擁有如下屬性的對象類型:name, color, owner, weight。

將對象賦給屬性

我們并沒被限制只能添加形如字符串或者數字之類的簡單數據類型作為屬性。我們也能夠將對象賦給屬性。下面,supervisorEmployee的一個屬性.

Example DT6

Language:javascript, parsed in: 0.021 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary, mySupervisor)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5.   this.supervisor=mySupervisor;
  6. }
  7. var boss=new Employee("John", 200);
  8.  
  9. var manager=new Employee("Joan", 50, boss)
  10. var teamLeader=new Employee("Rose", 50, boss)
  11.  
  12. alert(manager.supervisor.name+" is the supervisor of "+manager.name);
  13. alert(manager.name+"\'s supervisor is "+manager.supervisor.name)
  14.  

會輸出什么呢?運行示例

就像你在上面這個例子中看到的那樣,managerteamLeader都有一個supervisor屬性,而這個屬性是類型Employee的一個對象。

將函數作為屬性

任何類型的對象都可以作為一個屬性,回憶一下前面的Example 4(不是Example DT4),函數也是一個對象。所以你可以讓一個函數作為一個對象的一個屬性。下面,我將添加兩個函數getSalaryaddSalary。

Example DT7

Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5.  
  6.   this.addSalary=addSalaryFunction;
  7.  
  8.   this.getSalary=function()
  9.                  {
  10.                    return this.salary;
  11.                  };
  12. }
  13. function addSalaryFunction(addition)
  14. {
  15.   this.salary=this.salary+addition;
  16. }
  17.  
  18. var boss=new Employee("John", 200000);
  19. boss.addSalary(10000);                    // boss 長了 10K 工資……為什么老板工資可以長這么多:'(
  20. alert(boss.getSalary());                  // 輸出 210K……為什么默認工資也那么高……:'(
  21.  

運行示例

addSalarygetSalary演示了幾種將函數賦給屬性的不同方法。如果你記得我們最開始的討論;我討論了三種聲明函數的不同方式。所有那些在這里都是適用的,但是上面展示的兩個最常用。

讓我們看看有什么不同。下面,注意一下9-12行的代碼。當這部分代碼執(zhí)行的時候,函數getSalary被聲明。如前面數次提到的,一個函數聲明的結果是一個對象被創(chuàng)建。所以這時候boss被創(chuàng)建(接下來的高亮行),而boss里有一個getSalary屬性。

Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5.  
  6.   this.addSalary=addSalaryFunction;
  7.  
  8.   this.getSalary=function()
  9.                  {
  10.                    return this.salary;
  11.                  };
  12. }
  13. function addSalaryFunction(addition)
  14. {
  15.   this.salary=this.salary+addition;
  16. }
  17.  
  18. var boss=new Employee("John", 200000);
  19. var boss2=new Employee("Joan", 200000);
  20. var boss3=new Employee("Kim", 200000);
  21.  
  22.  

當你創(chuàng)建這個對象的更多實例時(boss2boss3),每一個實例都有一份getSalary代碼的單獨拷貝;而與此相反,addSalary則指向了同一個地方(即addSalaryFunction)。

看看下面的代碼來理解一下上面所描述的內容。

Example DT8

Language:javascript, parsed in: 0.036 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5.  
  6.   this.addSalary=addSalaryFunction;
  7.   this.getSalary=function()
  8.                  {
  9.                    return this.salary;
  10.                  };
  11. }
  12. function addSalaryFunction(addition)
  13. {
  14.   this.salary=this.salary+addition;
  15. }
  16.  
  17. var boss1=new Employee("John", 200000);
  18. var boss2=new Employee("Joan", 200000);
  19.  
  20.  
  21. // 給getSalary函數對象添加屬性
  22. boss1.getSalary.owner="boss1";
  23. boss2.getSalary.owner="boss2";
  24. alert(boss1.getSalary.owner);   // 輸出 "boss1"
  25. alert(boss2.getSalary.owner);   // 輸出 "boss2"
  26. // 如果兩個對象指向同一個函數對象,那么
  27. // 上面兩個輸出都應該是“boss2”。
  28.  
  29. // 給addSalary函數對象添加屬性
  30. boss1.addSalary.owner="boss1";
  31. boss1.addSalary.owner="boss2";
  32. alert(boss1.addSalary.owner);   // 輸出 "boss2"
  33. alert(boss2.addSalary.owner);   // 輸出 "boss2"
  34. // 因為兩個對象都指向同一個函數,(子烏注:原文寫are not pointing to the same function,疑為筆誤)
  35. // 當修改其中一個的時候,會影響所有的實例(所以兩個都輸出“boss2”).
  36.  
  37.  

運行示例

也許不是重要的事情,但這里有一些關于運行類似上面的getSalary的內嵌函數的結論: 1) 需要更多的存儲空間來存儲對象(因為每一個對象實例都會有它自己的getSalary代碼拷貝);2) javascript需要更多時間來構造這個對象。

讓我們重新寫這個示例來讓它更有效率些。

Example DT9

Language:javascript, parsed in: 0.014 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5.  
  6.   this.addSalary=addSalaryFunction;
  7.   this.getSalary=getSalaryFunction;
  8. }
  9. function getSalaryFunction()
  10. {
  11.   return this.salary;
  12. }
  13.  
  14. function addSalaryFunction(addition)
  15. {
  16.   this.salary=this.salary+addition;
  17. }
  18.  

看這兒,兩個函數都指向同一個地方,這將會節(jié)約空間和縮短構造時間(特別是當你有一大堆內嵌函數在一個構造函數的時候)。這里有另外一個函數的功能能夠來提升這個設計,它叫做prototype,而我們將在下一節(jié)討論它。

函數:原型

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

prototype的定義

你不需要顯式地聲明一個prototype屬性,因為在每一個構造函數中都有它的存在。你可以看看下面的例子:

Example PT1

Language:javascript, parsed in: 0.003 seconds, using GeSHi 1.0.7.12
  1. function Test()
  2. {
  3. }
  4. alert(Test.prototype)// 輸出 "Object"
  5.  

運行示例

給prototype添加屬性

就如你在上面所看到的,prototype是一個對象,因此,你能夠給它添加屬性。你添加給prototype的屬性將會成為使用這個構造函數創(chuàng)建的對象的通用屬性。

例如,我下面有一個數據類型Fish,我想讓所有的魚都有這些屬性:livesIn="water"price=20;為了實現這個,我可以給構造函數Fishprototype添加那些屬性。

Example PT2

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. function Fish(name, color)
  2. {
  3.   this.name=name;
  4.   this.color=color;
  5. }
  6. Fish.prototype.livesIn="water";
  7. Fish.prototype.price=20;
  8.  

接下來讓我們作幾條魚:

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. var fish1=new Fish("mackarel", "gray");
  2. var fish2=new Fish("goldfish", "orange");
  3. var fish3=new Fish("salmon", "white");
  4.  

再來看看魚都有哪些屬性:

Language:javascript, parsed in: 0.008 seconds, using GeSHi 1.0.7.12
  1. for (var i=1; i<=3; i++)
  2. {
  3.   var fish=eval("fish"+i);   // 我只是取得指向這條魚的指針
  4.   alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price);
  5. }
  6.  

運行示例

輸出應該是:

Language:text, parsed in: 0.001 seconds, using GeSHi 1.0.7.12
  1. "mackarel, gray, water, 20"
  2. "goldfish, orange, water, 20"
  3. "salmon, white  water, 20"
  4.  

你看到所有的魚都有屬性livesInprice,我們甚至都沒有為每一條不同的魚特別聲明這些屬性。這時因為當一個對象被創(chuàng)建時,這個構造函數將會把它的屬性prototype賦給新對象的內部屬性__proto__。這個__proto__被這個對象用來查找它的屬性。

用prototype給對象添加函數

你也可以通過prototype來給所有對象添加共用的函數。這有一個好處:你不需要每次在構造一個對象的時候創(chuàng)建并初始化這個函數。為了解釋這一點,讓我們重新來看Example DT9并使用prototype來重寫它:

Example PT3

Language:javascript, parsed in: 0.013 seconds, using GeSHi 1.0.7.12
  1. function Employee(name, salary)
  2. {
  3.   this.name=name;               
  4.   this.salary=salary;
  5. }
  6. Employee.prototype.getSalary=function getSalaryFunction()
  7. {
  8.   return this.salary;
  9. }
  10.  
  11. Employee.prototype.addSalary=function addSalaryFunction(addition)
  12. {
  13.   this.salary=this.salary+addition;
  14. }
  15.  

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

Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
  1. var boss1=new Employee("Joan", 200000);
  2. var boss2=new Employee("Kim", 100000);
  3. var boss3=new Employee("Sam", 150000);
  4.  

并驗證它:

Language:javascript, parsed in: 0.006 seconds, using GeSHi 1.0.7.12
  1. alert(boss1.getSalary());   // 輸出 200000
  2. alert(boss2.getSalary());   // 輸出 100000
  3. alert(boss3.getSalary());   // 輸出 150000
  4.  

運行示例

這里有一個圖示來說明prototype是如何工作的。這個對象的每一個實例(boss1, boss2, boss3)都有一個內部屬性叫做__proto__,這個屬性指向了它的構造器(Employee)的屬性prototype。當你執(zhí)行getSalary或者addSalary的時候,這個對象會在它的__proto__找到并執(zhí)行這個代碼。注意這點:這里并沒有代碼的復制(和Example DT8的圖表作一下對比)。

相關文章

最新評論