[עמוד ראשי]   [נושא קודם]
פונקציות
1. הגדרה וקריאה לפונקציה
הרעיון
הרעיון ביצירת משתנה הוא הקצאת מילת כינוי אחת עבור הפלט של אירוע או פקודת JS.
יצירת פונקציה היא זהה פרט לכך שהקצאת מילת הכינוי היא עבור סדרת פקודות שלמה, כלומר איחוד הרבה פקודותJS לפקודה אחת.
הגדרת הפונקציה היא בעצם ביטוי שכולל את שם הפונקציה ,ארגומנטים שהיא מקבלת (משתנים מבחוץ) והפעולות שהיא תבצע.
כל קבוצת פקודות JS אשר גורמות להשפעה יכולות להיות חלק מפונקציה. הקריאה לפונקציה היא בעצם בקשה להפעלתה, לכן הקריאה לפונקציה תיכתב במקום בו נרצה שהפונקציה תפעל.
הקריאה לפונקציה נעשית ע"י כתיבת שמה המלא (כולל סוגריים ,ארגומנטים-אם זוהי פונקציה המקבלת ארגומנטים).
ה-SCRIPT
ה-Script למעשה הוא שני חלקים : ה-Script עצמו שמכיל את הפונקציה ואירוע ה-“onLoad” שגורם לפונקציה לפעול.
דוגמא 1 ( פונקציה ללא ארגומנטים):
<SCRIPT LANGAUGE = "JS">

<!-- JS יש להחביא מדפדפנים שאינם מבינים  

function dateinbar()
{
   var d = new Date();
   var y = d.getFullYear();
   var m = d.getMonth() + 1;
   var d = d.getDate();
   var t = d + "/" + m + "/" + y ;
   alert("You arrived at the page on " + t + ".");
}

-->

</SCRIPT>

<input type="button" value="get date" onclick="dateinbar()">
דוגמא 2 ( פונקציה המקבלת ארגומנטים):
function Add(x,y)
{
 x+=y;
 document.write("Now x=x+y");
}
השפעת ה-SCRIPT
השפעת ה-script תראה ב-status bar.
הסבר ה-SCRIPT
שני דברים מתרחשים : הראשון הוא החלק ב-Script שיוצר את הפונקציה ,השני היא הפקודה שנמצאת בדף ה-HTML בחלק של ה-<BODY> שגורמת לפונקציה לפעול.
מבנה הפונקציה די ברור. שם הפונקציה ניתן לה ע"י כתיבת "function" ואז שם הפונקציה שנבחר( דומה מאוד ליצירת שם משתנה).
חשוב לזכור ששם הפונקציה כולל אחריו סוגרים והוא יכול להיות ארוך כרצוננו כל עוד אין שימוש במרווחים (Spaces) ובמילים שכבר מופיעות בשפת JS.
בדר"כ נבחר שם בעל משמעות-תיאור מטרת / פעולת הפונקציה.
לתשומת לבך!
כאשר יוצרים פונקציה הפקודות והקוד שהיא מכילה חייבים להיות בתוך סוגרים מסולסלות. ניתן לראות בדוגמא : סוגר פותח מיד אחרי הצהרת הפונקציה וסוגר שני בסוף.
קוד הפונקציה הראשונה:
· משתנה הוגדר לשנה.
· משתנה נוסף עבור החודש.
· משתנה עבור היום.
· משתנה רביעי עבור הצגת התאריך.

הפקודה האחרונה היא חדשה : defaultStatus היא תכונה של האובייקט Window.
מטרתה היא למקם טקסט בתחתית ה-status bar של חלון הדפדפן.
קוד הפונקציה השניה:
כאן הוגדרה פונקציה המקבלת שני ארגומנטים (משתנים חיצוניים) : x ו- y. ניתן לראות שאת המשתנים כותבים בתוך הסוגרים (שבדוגמא הקודמת היו ריקות) כאשר מפרידים ביניהם ע"י פסיק.
פעולות הפונקציה:
· ביצוע פעולת החיבור בין שני המשתנים ושמירת התוצאה במשתנה x.
· כתיבת הפלט שבמירכאות.
התוצאה נשמרת במשתנה x ובמידה וערכו השתנה, הערך החדש ישמר גם בסיום פעולת הפונקציה.
הפרמטרים לפונקציה יכולים להיות מחרוזות, מספרים וכ"ו.
פקודת ה-onload
פקודה זו מסמנת לדפדפן שבטעינת הדף יפעל כמו שכתוב אחריה. במקרה זה קריאה לפונקציה.
פקודה זו כמעט תמיד נמצאת בחלק ה-<BODY> של דף ה-HTML וכמעט תמיד אחריה קריאה לפונקציה, אבל לא בהכרח. ניתן לשים אובייקט או מתודה במקום.
קריאה לפונקציה המחזירה ערך
לפנינו קוד ה-Script הבא:
function raiseP(x,y)
{
 total = 1;
 for(j=0;j<y;j++)
 { total*=x; }

 return total;
}
total=raiseP(4,3);
document.write("4 raised to the 3rd power is "+total);
פונקציה זו מקבלת ארגומנטים ומחזירה ערך. פונקציה כזו המחזירה ערך נקראת תמיד מתוך ביטוי כלשהו לדוגמא : total=raiseP(4,3)
למרות ש-total הוא משתנה מקומי, משתמשים בו על מנת לכתוב את התוצאה. דבר זה נעשה בעזרת: return total הקובע שניתן יהיה להציג את ערכו גם מחוץ לפונקציה.
בשורה לפני האחרונה ישנה קריאה לפונקציה, כאשר ניתנים לה הערכים ההתחלתיים 3 ו- 4. בשורה האחרונה, ישנו כתיבת פלט התוצאה.
מיקום הפונקציה
את ה- script שמכיל את הפונקציה יש למקם בין פקודות ה- ו בדף ה-HTML.
ניתן למקם אותו בכל מקום בדף אך מיקומו מתחת לפקודת ה-onLoad יגרום להפעלתו לאחר שכל הדף נטען.
מיקום ה-script מעל פקודת ה-onLoad ממקם אותו בזיכרון המחשב תחילה, כך שהוא מוכן להפעלה כאשר פקודת ה-onLoad קוראת לו.
הבנאי Function( )
ב-JS 1.1 ניתן להשתמש בבנאי Function( ) ובאופרטור new על מנת ליצור פונקציה חדשה.
דוגמא ליצירת פונקציה בדרך זו :
var f = new Function("x", "y", "return x*y;");
שורת קוד זו יוצרת פונקציה חדשה אשר פחות או יותר זהה לפונקציה המוגדרת ע"י התחביר המוכר :
function f(x,y){ return x*y; }
בנאי ה-Function( ) מצפה לכל מספר של ארגומנטים של מחרוזות. הארגומנט האחרון הוא גוף הפונקציה – הוא יכול להכיל הצהרות JS שרירותיות ,המופרדות אחת מן השניה ע"י פסיקים.
כל שאר הארגומנטים לבנאי הם מחרוזות אשר מגדירות את שמות הפרמטרים לפונקציה שמוגדרת.
אם מגדירים פונקציה שאינה מקבלת ארגומנטים, יש להעביר מחרוזת יחידה – גוף הפונקציה- לבנאי.

יש לשים לב שהבנאי Function( ) אינו מעביר שום ארגומנט שמגדיר את שם הפונקציה שהוא יוצר.
כאשר ממירים פונקציה ללא שם למחרוזת, משתמשים בשם : "anonymous".
מסיבה זו, פונקציות הנוצרות ע"י הבנאי Function( ) נקראות לפעמים : "anonymous function".

הגדרת פונקציה ע"י הבנאי Function( ), מאפשרת לבנות ולקמפל פונקציות באופן דינמי, כך שלא נהיה מוגבלים ע"י גוף הפונקציה של ההצהרה function( ) המקומפל מראש.
הבנאי Function( ) חייב לקמפל פונקציה בכל פעם שהוא נקרא, לכן, לא נרצה לקרוא לבנאי זה בתוך גוף של לולאה וכדומה.

סיבה נוספת לשימוש בבנאי Function( ) היא שלפעמים זה נוח , ואפילו אלגנטי, להיות מסוגלים להגדיר פונקציה כחלק מביטוי של JS , יותר מאשר כהצהרה.
Function Literals
Function Literals זוהי הדרך השלישית ליצירת פונקציה. זהו ביטוי אשר יוצר פונקצית lambda ללא שם.
התחביר די דומה ליצירת פונקציה בדרך הראשונה פרט לכך שהוא משמש כביטוי יותר מאשר הצהרה ולא מוגדר שם לפונקציה.
דוגמא:
var f = function(x){ x*x; };
Function Literals שימושיות באותה מידה כמו פונקציות שנוצרו ע"י הבנאי Function( ).
מאחר ופונקציות אלו נוצרות ע"י ביטויי JS יותר מאשר הצהרה, השימוש בהן גמיש יותר ומתאים במיוחד לפונקציות שמשתמשים בהן פעם אחת ואינן זקוקות לשם.
למשל פונקציה המוגדרת ע"י ביטוי Function Literals יכולה להתאכסן בתוך משתנה ולהיות מועברת לפונקציה אחרת או להיקרא באופן ישיר :
הגדרה ואחסון
a[0] = function(x){ return x*x; }; 
הגדרה והעברה לפונקציה אחרת
a.sort(function(a,b){ return a-b; }); 
הגדרה וקריאה
var tensquared =(function(x){ return x*x; }) (10); 
Function Literals בעלות יתרון לעומת הבנאי Function( ): גוף פונקציה שנוצרה ע"י הבנאי Function( ) חייב להיות מוגדר כמחרוזת, דבר שיכול להיות לא נוח, ארוך ומסובך, לעומת זאת גוף הפונקציה של Function Literals נעשה בתחביר סטנדרטי של JS.
לתשומת לבך
יש לזכור שהבנאי Function( ) בר תוקף רק בגרסאות JS 1.1 ומעלה. ו- Function Literals תקפות בגרסאות JS 1.2 ומעלה.
2. פונקציות כנתונים
המאפיינים החשובים ביותר של פונקציות הן היכולת להגדירן ולקרוא להן.
ב-JS פונקציות אינן רק תחביר אלא גם נתון ולכן ניתן להתייחס אליהן כמו לערך של נתון: לאחסן במשתנה, באובייקט, באלמנט של מערך , להעביר לפונקציה וכ"ו.
דוגמא :
Function square(x){ return x*x; } 
הגדרה זו יוצרת אובייקט פונקציה חדש ומאחסנת אותו לתוך המשתנה square. שם הפונקציה הוא שם המשתנה המאחסן אותה.

הפונקציה יכולה להתאכסן במשתנה אחר :
a = square(4); 
b = square; 
c = b(5); 
הפונקציה יכולה להתאחסן במאפיין של אובייקט :
o = new object; 
o.square = new Function(x,return x*x) 
הפונקציה יכולה להתאחסן באלמנטים של מערך :
a = new array(10); 
a[0] = function(x){ return x*x; } 
a[1] = 20; 
a[2] = a[0](a[1]);
תחביר הקריאה לפונקציה בדוגמא האחרונה נראה מוזר, אבל הוא עדיין שימוש חוקי של האופרטור ( ) של JS.

הדוגמא הבאה היא דוגמא מפורטת של דברים שיכולים להיעשות כאשר משתמשים בפונקציות כנתונים. היא מדגימה איך פונקציות יכולות להיות מועברות כארגומנטים לפונקציות אחרות, כמו כן, איך הן יכולות להיות מאוחסנות במערכים אסוציאטיביים.
הגדרת מספר פונקציות פשוטות :
function add(x,y){ return x + y; }
function subtract(x,y){ return x - y; }
function multiply(x,y){ return x * y; }
function divide(x,y){ return x / y; }
הפונקציה לוקחת אחת מהפונקציות הנ"ל כארגומנט וקוראת לה עם שני אופרנדים :
function operate(operator,operand1,operand2)
{
  return operator(operand1,operand2);
}
ניתן לקרוא לפונקציה כך על מנת לחשב את הערך (2+3)+(4*5) :
var i = operate(add, operate(add,2,3), operate(multiply, 4,5));
ניתן לקרוא לפונקציה כך על מנת לחשב את הערך (2+3)+(4*5).
כעת הפונקציות הנ"ל מיושמות שוב, הפעם ע"י function literal. מאחסנים את הפונקציות במערך אסוציאטיבי.
var operators = new Object();
operators["add"] = function(x,y){ return x + y; }
operators["subtract"] = function(x,y){ return x - y; }
operators["multiply"] = function(x,y){ return x * y; }
operators["divide"] = function(x,y){ return x / y; }
operators["pow"] = Math.pow;
הפונקציה לוקחת את שם האופרטור , מחפשת אותו במערך, ואז קוראת לו עם האופרנדים המסופקים.
יש לשים לב לתחביר הקריאה לפונקצית האופרטור.
function operate2(op_name, operand1, operand2)
{
 if(operators[op_name] == null)
    return "unknown operator";
 else
    return operators[op_name](operand1,operand2);
}
ניתן לקרוא לפונקציה זו על מנת לחשב את הערך ("hello" + " " + "world") כך :
var j = operate2("add", "hello", operate2("add"," ", "world"))
ע"י שימוש בפונקציה המוגדרת מראש: ( )math.pow :
var k = operate2("pow",10,2)
הפונקציה ( )Array.sort ממינת את האלמנטים במערך. מכיוון שיש הרבה דרכים למיון, פונקציה זו באופן אופציונאלי מקבלת פונקציה אחרת כארגומנט על מנת שתאמר לה על סמך אילו פרמטרים לבצע את המיון.
לפונקציה זו יש תפקיד פשוט מאוד: היא לוקחת שני אלמנטים של המערך, משווה ביניהם, ואז מחזירה ערך שמגדיר איזה מהאלמנטים שהושוו יהיה ראשון. פונקציה זו עושה את המתודה ( )Array.sort כללית וגמישה לחלוטין, היא יכולה לערוך מיון של כל סוגי הנתונים, בכל סדר שהוא, המתקבל על הדעת.
3. טווח הכרה- אובייקט ה-Call
גוף פונקציה פועל בטווח מקומי ששונה מהטווח הגלובלי. טווח חדש זה נוצר ע"י הוספת האובייקט call לחזית של שרשרת הטווח.
מאחר שאובייקט ה-call הוא חלק משרשרת הטווח כל מאפיין שלו נגיש כמשתנה של גוף פונקציה. משתנים מקומיים מוגדרים ע"י var ונוצרים כמאפיינים של האובייקט.
הפרמטרים של הפונקציה נגישים גם כמאפייני האובייקט.

בנוסף למשתנים ופרמטרים מקומיים , אובייקט ה-call מגדיר גם תכונה מיוחדת בשם: arguments.
תכונה זו מתייחסת לאובייקט מיוחד אחר שידוע כאובייקט argument.
מכיוון שתכונה זו היא של אובייקט ה-call יש לה את אותו הסטטוס של משתנה מקומי ופרמטרים של פונקציה.
מסיבה זו המזהה :argument צריך להחשב כמילה שמורה ואינו יכול לשמש כמשתנה או שם של פרמטר.
4. ארגומנטים של פונקציה- אובייקט ה-Arguments
arguments הוא תכונה מיוחדת של אובייקט ה-call אשר מתייחס לאובייקט הידוע כאובייקט ה-arguments. אובייקט זה בעל מספר מאפיינים שימושיים ובנוסף בעל מערך. האלמנטים שמערך זה מחזיק הינם ערכי הארגומנטים שהועברו לפונקציה.
ישנה גישה מליאה לאותם ארגומנטים של המערך, אפילו אם חלקם חסרי שם. נניח למשל שמוגדרת פונקציה f שמקבלת ארגומנט אחד x.
אם תתבצע קריאה לפונקציה עם שני ארגומנטים, הארגומנט הראשון יהיה נגיש לפונקציה ע"י הפרמטר x או כ-[arguments[0. הארגומנט השני יהיה נגיש לפונקציה רק ע"י [arguments[1.
בנוסף לכך,ל-arguments יש תכונה של אורך –length מתארת את מספר האלמנטים שהמערך מכיל. בדוגמא הנ"ל ערך מאפיין זה יהיה 2.
בנוסף לכך,לאלמנטים שהמערך מכיל. בדוגמא הנ"ל ערך מאפיין זה יהיה מערך ה-arguments שימושי בכמה דרכים :
ניתן להשתמש בו על מנת לבדוק אם הקריאה לפונקציה נעשתה עם המספר הנכון של ארגומנטים. כמו כן, ישנה אפשרות לכתיבת פונקציות שעובדות עם כל מספר של ארגומנטים.
מאפיין ה-callee
מאפיין זה מתייחס לפונקציה שכרגע מתבצעת. זה שימושי למשל כאשר רוצים לאפשר לפונקציה חסרת שם (literal) לקרוא לעצמה באופן רקורסיבי
לדוגמא:
function(x) 
{ 
 if(x>1) return x* arguments.callee(x-1); 
 return x; 
} 
מאפיין זה תקף בגרסאות 1.2 JS ומעלה.
מאפיין ה-caller
מאפיין זה מתייחס להקשר הקריאה ,משמע, המקום ממנו נקראה הפונקציה. השימוש ב-arguments.caller אינו מתייחס לפונקציה שקראה לפונקציה הנוכחית המתבצעת, אלא מתייחסת לאובייקט ה-arguments של פונקציה זו.
על מנת להתייחס לפונקציה הקוראת, יש להשתמש ב-arguments.caller.callee.

ניתן להשתמש במאפיין זה לכתיבת פונקציה ל- debugging אשר מדפיסה מחסנית "עקבות". על מנת לבצע זאת , יש להיות מודעים לבאג ב- 4 N. ניתן לצפות שפונקציה הנקראת מהשכבה העליונה תהיה בעלת תכונת arguments.caller המאותחלת ל-null או לערך undefined.
ב- 4 N , בכל אופן, פונקציה כזו היא בעלת תכונת arguments.caller המאותחלת לאובייקט arguments.
לכן, כאשר כותבים פונקציה שתעקוב אחר התכונה caller , יש צורך בטכניקה על מנת להבחין האם הגענו לשכבה העליונה או שנכנס ללולאה אין סופית.
הדוגמא הבאה מדגימה את פונקצית מחסנית העקבות : פונקציה זו מחזירה את השם של פונקציה נתונה. היא עושה זאת ע"י הפיכת הפונקציה למחרוזת , ואז משתמשת בביטוי רגיל, על מנת לחלץ את שם הפונקציה מהקוד שהתקבל כתוצאה.
function funcname(f)
{
  var s = f.toString().match(/function (\w*)/)[1];
  if ((s == null) || (s.length == 0)) 
         return anonymous;
  return s;
}
פונקציה זו מחזירה מחרוזת שמכילה "מחסנית עקבות"
function stacktrace()
{
  var s = "";
  for(var a = arguments.caller; a != null; a = a.caller)
  {
    s += funcname(a.callee) + "\n";
    if(a.caller == a) break;
  }
  return s;
}
ניתן להשתמש בתכונה arguments.caller ב-3 N , אך ביישום זה של JS , ישנה התיחסות לפונקציה calling ישירות יותר מאשר לאובייקט arguments של הפונקציה calling.
מסיבה זו, לא ניתן לכתוב פונקצית מחסנית עקבות ב-3 N.
5. תכונות של פונקציות ומתודות
מסיבה זו, לא ניתן לכתוב פונקצית מחסנית מאחר ופונקציות הן אובייקטים יש להן תכונות (מאפיינים) ומתודות.
מאפיין ה- length של מערך ה-arguments מתאר את מספר הארגומנטים שהועברו לפונקציה.
מאפיין ה-length של הפונקציה עצמה מתאר את מספר הארגומנטים שהפונקציה מצפה לקבל כלומר מספר הפרמטרים שהוגדרו ברשימת הפרמטרים של הפונקציה.
מאפיין זה תקף בגרסאות 1.1 JS ומעלה. ב-4 N ישנו באג המונע מתכונה זו לעבוד נכון אלא אם כן ב-LANGUAGE מוצב : "JavaScript1.2”.
המתודות apply( ),call( )
N 4 מוסיף מתודה חדשה ( )apply לאובייקט הפונקציה.
מתודה זו מאפשרת לקרוא לפונקציה, כאילו מהווה מתודה של אובייקט אחר.
הארגומנט הראשון למתודה ( )apply הוא האובייקט עבורו הפונקציה צריכה להיקרא.
ארגומנט זה מתפקד בתור הערך של מילת המפתח this בתוך גוף הפונקציה.
הארגומנט השני הוא מערך אופציונלי, המכיל ארגומנטים המועברים לפונקציה. כך, על מנת לקרוא לפונקציה ( )f עם שני ארגומנטים , כאילו הייתה מתודה של האובייקט o, ניתן להשתמש בקוד כך :
f.apply(0,[1,2]);
שורת קוד זו זהה לשורות הבאות :
o.m = f;
o.m(1,2);
delete o.m; 
שימוש נוסף ב-( )apply הוא כאשר נריץ מתודה אשר "תדרוס" את המתודה ( )toString , המהווה כמתודת ברירת המחדל של אובייקט, והיא בעלת מתודות/פונקציונליות מיוחדת שלעצמה.