Douglas Crockford
ביסודו, Javascript הוא כולו בנוגע לאובייקטים. מערכים הינם אובייקטים, פונקציות הינם אובייקטים, אובייקטים הינם אובייקטים וכן הלאה. אם כן, מהם למעשה אובייקטים? אובייקטים הינם אוסף זוגות זוגות של שם וערך. השמות הינם מחרוזות והערכים הינם מחרוזות, מספרים, בוליאנים ואובייקטים (כולל מערכים ופונקציות). אובייקטים מיושמים ברוב המקרים כ-Hashtables, כך שניתן לשלוף ערכים במהירות.
אם הערך הינו פונקציה, אנו יכולים להתייחס אליו כאל שיטה. (Method). כאשר שיטה של אובייקט מופעלת, המשתנה this מוקצה לאובייקט. ואז השיטה (method) יכולה לגשת למשתנים דרך המשתנה this.
אובייקטים יכולים להווצר ע"י "בנאים" (constractors), שהם פונקציות אשר מאתחלות אובייקטים. בנאים מספקים תכונות ש-classes מספקים בשפות אחרות, כולל משתנים סטטיים ושיטות.
האיברים של אובייקט, כולם איברים "ציבוריים" (Public). כל פונקציה יכולה לגשת, לשנות, למחוק את האיברים האלו או להוסיף איברים נוספים. ישנן שני דרכים ראשיות להצבת איברים באובייקט חדש.
משתמשים בטכניקה זו בד"כ כדי לאתחל משתנים ציבוריים. המשתנה this של הבנאי משמש להוספת איברים לאובייקט
function Container(param){ this.member = param; }
כך, שאם אנו בונים אובייקט חדש
var myContainer = new Container('abc');
אז myContainer.member
יכיל 'abc'
.
משתמשים בטכניקה זו בד"כ כדי להוסיף שיטות ציבוריות. כאשר מחפשים איבר והוא לא נמצא בתוך האובייקט עצמו, אז הוא נלקח מתוך איבר ה-prototype של הבנאי של האובייקט. מנגנון האב-טיפוס משמש עבור הורשה. הוא גם חוסך בזיכרון. כדי להוסיף שיטה לכל האובייקטים הנוצרים ע"י הבנאי, נוסיף פונקציה ל-prototype של הבנאי
Container.prototype.stamp = function (string) { return this.member + string;
}
כך, אנו יכולים להפעיל את השיטה
myContainer.stamp('def')
אשר מפיקה 'abcdef'
.
איברים פרטיים מיוצרים ע"י הבנאי. באופן כללי var
-ים ופרמטרים של הבנאי הופכים לאיברים פרטיים.
function Container(param) {
this.member = param;
var secret = 3;
var self = this;
}
הבנאי הזה יוצר שלושה משתנים פרטיים: param, secret
ו-self
. הם מוצמדים לאובייקט, אך הם אינם נגישים מחוץ לאובייקט, הם גם לא נגישים לשיטה הציבורית של האובייקט. הם כן נגישים לשיטות פרטיות. שיטות פרטיות הינן פונקציות פנימיות של הבנאי.
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
}else {
return false;
}
}
this.member = param;
var secret = 3; var self = this;
}
השיטה הפרטית dec
בודקת את המשתנה secret
. אם הוא גדול מ-0, הוא מפחית את ערכו ומחזיר true
. אחרת הוא מחזיר false
. אפשר להשתמש בו כדי להפוך את אובייקט זה מוגבל לשלושה שימושים.
כנוהג, אנו יוצרים פרמטר self
פרטי בו משתמשים כדי להפוך את האובייקט זמין לשיטה הפרטית. זהו מעקף (Workaround) של שגיאה בהגדרות שפת ECMAScript אשר גורמת ל-this
להיות מוגדר לא נכון עבור פונקציות פנימיות.
לא ניתן לקרוא לשיטות פרטיות ע"י שיטות ציבוריות. כדי לעשות שיטות פרטיות שימושיות, אנו צריכים להציג שיטה מיוחסת.
שיטה מיוחסת מסוגלת לגשת למשתנים פרטיים ושיטות, והיא כשלעצמה נגישה לשיטות ציבוריות והחוצה. ישנה אפשרות למחוק או להחליף שיטה מיוחסת, אך בלתי אפשרי לשנות אותה, או להכריח אותה לוותר על הסודות שלה.
שיטות מיוחסות מוקצות בעזרת this
בתוך הבנאי.
function Container(param) { function dec() { if (secret > 0) { secret -= 1; return true; } else { return false; } } this.member = param; var secret = 3; var that = this; this.service = function () { if (dec()) { return that.member; } else { return null; } }; }
service
הינה שיטה מיוחסת. קריאה ל-myContainer.service()
תחזיר 'abc'
בשלושת הפעמים הראשונות שהיא תקרא. לאחר מכן, היא תחזיר null
. service
זמין לאובייקטים ושיטות אחרות, אך אינה מאפשרת גישה ישירה לאיברים הפרטיים.
צורה זו של איברים ציבוריים, פרטיים ומיוחסים אפשרית של Javascript יש סגירות. מה שזה אומר זה שלפונקציה פנימית תמיד יש גישה לפרמטרים ולמשתנים של הפונקציה החיצונית שלו, אפילו אחרי שהפונקציה החיצונית חזרה. זהו מאפיין רב-עוצמה של השפה. אין ספר לתכנות ב-Javascript נכון לרגע זה אשר מראה כיצד לנצל אפשרות זו. רובם אפילו לא מזכירים את הנושא.
איברים פרטיים ומיוחסים יכולים להווצר רק כאשר אובייקט נמנה. איברים ציבוריים יכולים להתווסף בכל זמן נתון.
function Constructor(...) {
this.membername = value; } Constructor.prototype.membername = value;
function Constructor(...){
var self = this;
var membername = value;
function membername(...) {
...
}
} // Note: The function statement function membername(...) { ... }
// is shorthand for var membername = function membername(...) { ... };
function Constructor(...) {
this.membername = function (...) {
...
};
}
Copyright 2001 Douglas Crockford. All Rights Reserved Worldwide.