יום שבת, 14 ביולי 2012

מבוא מואץ לjQuery עבור מפתחי #C ו Java מנוסים

jQuery היא כל כך נפוצה בקרב מפתחי ווב, שניתן להתייחס אליה כחלק משפת JavaScript לדפדפן. קחו את jQuery מהעולם - ותמצאו מליון נשמות אבודות, שלא יודעות כיצד להמשיך ולכתוב אפליקציות ווב.

הבהרה: jQuery היא ספרייה ל JavaScript - לא הרחבה לשפה. היא פשוט מסייעת במידה כ"כ רבה עד שהפכה אצל מפתחים רבים לחלק בלתי נפרד מכתיבת קוד ב JavaScript. כאשר דפדפן אינו מעורב (לדוגמה node.js) - אין לה שום משמעות.

מה יש בה ב jQuery שהיא כ"כ מצליחה, ורבים כ"כ תלויים בה?
בפוסט זה אנסה לענות על השאלה.


שייך לסדרה מבוא מואץ ל JavaScript ו jQuery


לא מזמן שאלה אותי מישהי כיצד אני בוחר את רמת העומק / הפרטים של הפוסטים? מדוע הם יחסית high level ולא בפרטים? לא ידעתי בעצמי מה לענות.
"כי זו הרמה הקריטית יותר להצלחת הפיתוח" - עניתי, אבל לא שכנעתי את עצמי.
"אולי בגלל שאני ארכיטקט וזו רמת הפרטים שאני רגיל לה?" - ניסיתי שוב. לא ממש ידעתי.
ישנתי על זה לילה. אני חושב ששתי הסיבות הן:

  • להגיע לקהל יעד רחב
  • לכסות נישות שלא מכוסות היטב - כלומר Value Proposition ייחודי.

הקדמה
על jQuery יש טונות של חומרים. רוצים לדעת מה ההבדל בין live ל bind? עשרות מקורות טובים ישמחו להסביר. עם מעט חיפוש, גוגל יפנה אתכם לתשובה בודדת ב StackOverflow שעונה בדיוק, אבל בדיוק, על המקרה שאתם מתמודדים איתו. אבל יש משהו שנראה לי ייחודי ושקשה למצוא - מבט גבוה קצת מהפרטים, מפוכח ובעברית - על מה שקורה שם.
לפני כתיבת פוסט זה חיפשתי בגוגל "jQuery Crash Course" או "jQuery introduction". יש הרבה - אבל הם מספקים hands-on בכדי להתחיל להשתמש ב jQuery. הם לא מספקים הקדמה נאותה שתכין אתכם ללמידת jQuery או בכלל תעזור לכם להבין אם זה מה שאתם מחפשים. כשאני התחלתי ללמוד jQuery (לא כ"כ מזמן) - רציתי למצוא מישהו שיספר לי "מה העוקץ ב jQuery" - אך לא מצאתי. הנה זה לפניכם.
עלייתה של jQuery
תחילתה של jQuery היא בימי הביניים (של הדפדפנים - כמובן), ימים אפלים שהאנושות מנסה לשכוח.
בעוד JavaScript הייתה סטנדרטית (נניח...), ה APIs של הדפדפן לייצוג דף הHTML, מה שנקרא (Document Object Model (DOM, היה שונה למדי בין דפדפן לדפדפן. אמנם היו פונקציות עם שמות זהים (כמו getElementsByTagName) - אבל ההתנהגויות היו שונות. לעתים הן החזירו מבנים שונים, לפעמים הם קראו לאירועים (events) בסדר שונה. ובד"כ הן עשו את זה לאט ובצורה לא יעילה, תחת ההנחה ששינויים דינמיים ב DOM הם מעטים למדי. בקיצור: כל מה שלא הייתם רוצים מ API.
הכתיבה של קוד ווב Cross-Browser הייתה סיוט, ואכן רק אנשים מעטים הסכימו לעסוק במלאכה הבזויה[א]. ספריה שתספק API אחיד, אמין ומהיר עתידה להפוך לדבר שהמפתחים יהיו תלויים בו ולא יוכלו עוד בלעדיו.
כעשור מאוחר יותר, הדפדפנים מהירים יותר ואחידים יותר במבנה ה DOM APIs שלהם.
"מדוע מפתחים עדיין 'תלויים' ב jQuery?" - אפשר לשאול. ובכן, לשימוש ב jQuery יש הרבה תיעוד ודוגמאות - הרבה יותר מאשר שימוש ישיר ב DOM. בנוסף, בעוד ה API של ה DOM התפתח בקצב איטי ונשאר דומה למדי לתכנון בן 13+ שנים, jQuery יכלה להרשות לעצמה שינויים יותר דרמטיים שמשקפים יותר טוב את צורכי התקופה.

אז מה jQuery מספקת?
אמירה מקובלת היא ש "jQuery היא רק ספריה ל Selection" - אבל זה לא מדויק. jQuery מכסה מספר נושאים:

  • ביצוע שינויים ב DOM - קריאה וכתיבה.
  • מודל פשוט ואחיד יותר של אירועים (DOM events).
  • שיפורי ביצועים עבור טיפול בהרבה אירועים.
  • אנימציות - שיכולות להיות מופעלות על כל אלמנט ב DOM כמו Image, או Div שמאגד אלמנטים רבים.
  • הפשטה של XMLHttpRequest - מה שקרוי Ajax.
  • Utilities שונים לשימוש בג'אווהסקריפט, כגון each.$ או proxy.$
כפי שניתן לראות jQuery הוא דיי רוחבית. חוץ מהאנימציות שהן קצת "אקסטרה" - ספריה זו מספקת עטיפה ל DOM שמאפשרת לנו לעבוד איתו ברמת הפשטה קצת יותר גבוהה.

אלטרנטיבות
Prototype ו MooTools הן ספריות בעלות יכולות מקבילות, פחות או יותר. jQuery נצחה אותן בזכות קהילה, תיעוד טוב יותר או אולי אמינות גבוהה יותר.
Dojo, YUI או ExtJS/Sencha הן ספריות שמספקות רמת הפשטה גבוהה בהרבה ובעצם מנתקות אתכם מה DOM. הן נותנות למפתח לעבוד ברמה קרובה הרבה יותר ל Windows Forms או AWT ובעצם מייצרות מודל חדש אלטרנטיבי ל DOM שהמפתח עובד מולו.

יש המון כוח ויופי בכך ש jQuery לא מתארת מודל חדש, אלא רק מודל משופר של ה DOM. המפתח נותר עם קשר והבנה טובה בהרבה למה שקורה בפועל בתוך הדפדפן, ו jQuery יכולה להתחבר בקלות להמון ספריות שנכתבו בחשיבה על ה DOM. מי שרוצה ליצור ספרייה מעל YUI צריך לעבוד ע"פ המודל של YUI שעשוי בהחלט לא להתאים ל Dojo או ל ExtJS.



טעימה מיכולותיה של jQuery
לא אנסה להרשים אתכם בתצוגות-תכלית מגניבות. ה Adoption של jQuery הוא כבר מעבר לזה. אנסה לתת, בקצרה, טעימה מהיכולות העיקריות והסגנון של jQuery.

DOM Manipulation
בדומה לSQL בה יש משפטי SELECT...FROM...WHERE עם פורמט ידוע, גם ב jQuery יש דרך פעולה שחוזרת על עצמה. משפטי jQuery הם בעלי המבנה הבא:

$('selection').<execute>();


בחר שורה של אלמנטים - ובצע עליהם משהו: שינוי של HTML, CSS, רישום לאירועים ועוד.
חלק גדול מהיופי של jQuery היא הדרך בה היא משתלבת בטבעיות בנוף של HTML, JavaScript ו CSS. שפת CSS עושה פעולה דומה: בוחרת אלמנטים ב DOM (כלומר ב HTML) ומחילה (כלומר apply) עליהם עיצוב.
jQuery משתמשת בתחביר של javaScript לתאר את אותה התבנית. הנה דוגמה:

$('.banner').css('background-color', 'red');

שהיא המקבילה לכתיבת ה CSS הבא:

.banner {
  background-color : red;
}

מפתח שחדש ל jQuery אך בקיא ב CSS יוכל ללא קושי להגדיר שאילתות דיי מורכבות.
jQuery לא אמורה להיות תחליף ל CSS - לצורך זה היא תהיה משמעותית פחות יעילה, אבל היא מאפשרת באותה דרך חשיבה לבצע שינויים מרחיקי לכת בעזרת שורות בודדות של קוד.
התחביר של jQuery, בדומה ל javaScript, תומך בשרשור (chaining). פעולת ה Select מחזירה רשימה (באורך 0, 1 או יותר) של אלמנטים ב DOM. כל אחת מפעולות ה execute מחזירה את אותה הרשימה של אובייקטים עליה נקראה, כך שיהיה ניתן לשרשר עליה עוד ועוד פעולות:

$('div > p').show().css('color', 'blue').removeClass('selection');


קריאה זו תבחר את אלמנטי ה p (פסקה ב HTML) שנמצאים ישירות בתוך div, תציג אותם, תחיל על הטקסט צבע כחול ותסיר class בשם selection - אם קיים.
אם ננסה לתאר בצורה יותר כללית את תבנית כתיבת הביטויים ב jQuery - אפשר לתאר אותם כך:

$('selection').<execute>().<execute>().<filter>().execute();


פעולת הפילטר היא פעולה שמצמצמת את רשימת האובייקטים. "צמצום" יכול להיות גם פעולת בחירה במקרה זה, כאשר find בוחרת את אלמנטי ה strong הבנים לאלמנטי ה div שבחרנו:

$('div').css('border', '1px solid blue').fadeTo('slow', 0.5).find('strong').css('color', 'red');
הנה דוגמת ההרצה של קוד זה. אין מניעה שיהיו יותר אלמנטים של strong מאלמנטים div-אבות כמובן, כך שהשם "צמצום" (filter) הוא שם בהחלט לא מדויק. וריאציה אחרת של צמצום נקראת "טיול" או traversal. בעזרת פקודות כגון ()parent או ()siblings אפשר "לטייל" על ה DOM מהנקודה בה אתם נמצאים.
יש מספר רב של פעולות execute, traversal ו filter אפשריות - אני בטוח שגוגל יוכל לעזור לכם למצוא מידע רב על כולן.

טיפול באירועים (events)
jQuery מספקת רמת הפשטה נוחה יותר לאירועים ב DOM. לדוגמה, עבור hover סביר שמפתח יבחר להירשם לאירועים של ה DOM בשם mouseOver ו mouseOut, אבל היכרות אינטימית תלמד שברוב הדפדפנים שימוש ב mouseEnter ו mouseLeave הוא עדיף. jQuery חוסכת לכם ללמוד פרטים כאלו ומספקת אירוע hover (שדורש 2 פונקציות: כניסה ויציאה) שידע לעשות את הדבר הנכון עבור כל דפדפן.
עוד צרה קשה היא רישום מופעים רבים של אירוע.
נאמר שיש לכם גלריה עם 100 תמונות על המסך, שבפעולת Hover אתם רוצים להדגיש את התמונה (אחת מ 100) שכרגע העכבר מצביע עליה. הדרך הנאיבית היא לרשום את אירוע ה hover והטיפול בו 100 פעם, פעם עבור כל תמונה בגלריה. מחיר הביצועים עלול להיות הרסני.
עדיף בהרבה לרשום את אירוע ה hover פעם אחת על כל הגלריה, לאתר את התמונה הרלוונטית לאירוע ואז להפעיל את קוד הטיפול באירוע בעזרת ההקשר הנכון.
שיפור הביצועים הוא משמעותי מאוד, אבל לדפדפנים שונים יש חוקים שונים כיצד לעשות זאת. jQuery מספקת הפשטה טובה לסיבוכיות זו ונותנת לכם לרשום אירועים על "קבוצה של אלמנטים" בקלות רבה.



כיצד jQuery עובדת? (בקצרה)
jQuery היא ספריית JavaScript לכל דבר. מוסיפים אותה ל HTML Header ואז ניתן להשתמש בה.
jQuery רושמת אובייקט גלובלי בשם $ (שם חוקי ב javaScript) שהוא משמש כמפתח לפעולות שונות של הספריה.
כאשר מבצעים Selection (כלומר "בחירה") - לא מקבלים רשימה של האובייקטים האמיתיים ב DOM, כי אם wrappers של jQuery שמספקים API בטוח, cross-browser, ופשוט יותר.
ל jQuery יש אלגוריתם יעיל לביצוע selection ב DOM. הוא נקרא Sizzle וניתן למצוא אותו כספריית javaScript עצמאית. ספרייה זו באמת "רק עושה selection". הנה כמה כללים איך להשתמש ב jQuery בצורה יעילה.
יש שמועות על כך ש jQuery מבצעת caching לאלמנטים ב DOM. שמעתי אותן לא פעם. לא נתקלתי מעולם בזכר להתנהגות שנראתה כמו caching עבור פעולות DOM. בעיקרון, גישה ישירה ל DOM אמורה להיות תמיד מהירה יותר משימוש ב jQuery.

Plug-ins
ניתן לכתוב plugins ל jQuery. בפועל plugin הוא פונקציה שנרשמת על ה namespace של jQuery (כלומר, סימן ה $) ויכולה להשתלב בתבנית ה Select-execute.
לדוגמה, אני יכול לכתוב פונקציה שהופכת אלמנטים להציג מימין לשמאל, ע"י שינוי כל פרטמר אפשרי לתמוך בהתנהגות זו. במקום לקבל רשימה של wrappers ולעבור עליהם בלולאה, יהיה הרבה יותר אלגנטי להשתמש בפונקציה שלי בצורה הבאה:
$('.text .localizable').toRTL();

יש כמה כללים (המנעות מהתנגשויות על הסימן $, אתחול, ...) שכדאי להקפיד עליהם בעת כתיבת jQuery Plugin - יש מדריכים רבים באינטרנט שישמחו לספר ולהדגים זאת.
סה"כ ראיתי כמה jQuery Plugins שלא הייתה להם הצדקה אמיתית להיכתב כ Plugin. אני מנחש שאם jQuery הייתה קוראת ל Plugins בשם פחות מרשים (כמו jQuery Chained Function) - היו נכתבים הרבה פחות Plugins של jQuery.

---
[א] הפוסט מופנה למפתחי Server בשפות מודרניות, שם ה APIs המקובלים טובים בהרבה.

12 תגובות:

  1. שבוע טוב

    1.
    הזהר בדבריך, אל תאמר ש"ניתן להתייחס אליה כחלק משפת JavaScript".
    הרבה מאד מהעוסקים בתחום בניית אתרים הם כאלו שלא מבינים את ההבדל בין שפת PHP ל-SQL, הם לא מבינים מה מוזר בזה שהם מגדירים את עצמם כ"מתכנתי HTML", ולכן לא פלא שהם חושבים ש-jQuery גם היא שפת תכנות.
    אבל אתה, לפחות לפי ההיבטים המשקתפים במאמריך, נראה שאתה מבין איזה חלק מהפעולה תלוי בתקשורת הנתונים, מה קשור לשרת האינטרנט, והיכן מתחיל ניתוח הקוד שתלוי במפרשן שבצד השרת. לכן, תמשיך לדייק בדבריך, ולעשות הבחנה ברורה מאד בין ספריה מומלצץ לשימוש, לבין שפת התכנות עצמה, שצריך לדעת אותה מספיק טוב, גם אם נראה שהשימוש בספריה המומלצת יכול לחסוך את לימוד השפה :)

    2.
    getElementsByTagName - getElementbyTagName, element-s ברבים. וכמובן גם האות b נכתבת באות גדולה, להבדיל מ-getElementById הנכתבת בלשון יחיד.
    בנוסף, ראוי לדייק שמדובר בשיטה (method) של אובייקט המסמך (האובייקט document, בשאופן רשמי הינו תכונה של האובייקט window, אך יכול להכתב גם בלעדיו, ואכן כך רגילים לכתוב). הגם ששיטה הינה אכן פונקציה.

    3.
    אמנם עברית קשה שפה, אך בכל זאת ניתן לבטא את המילה והמונח selection, בעברית.
    אם המילה "בחירה" נשמעת לכם מוכר, זה כנראה בגלל זה...

    השבמחק
    תשובות
    1. תודה ישראל על ההערות!

      1. הוספתי הערה בנושא. לא צפיתי את הבלבול האפשרי, אבל לאחר שהערת - אני בהחלט יכול לדמיין אותו קורה. תודה.

      2. טעות עריכה - סליחה. לגבי שיטות ופונקציות: בתור עוסק ב Java ו #C במשך שנים אני רגיל קרוא לכל קטע קוד עם לוגיקה ("פונקציה") - שיטה (method). כעת כשאני עוסק גם בג'אווהסקריפט - אני מכריח את עצמי להשתמש במונח "פונקציה" על מנת לדייק, אם כי אני מבין שפספסתי פה הבדל בעל משמעות. למדתי משהו.

      3. בחירת המונחים היא דילמה אינסופית. Selection עדיין מתקשר לי מהר יותר וברור יותר להקשר המבוקש מהמילה העברית "בחירה". אני מניח שמה שנכון לי לא תמיד נכון לאחרים וזה חלק מהמחיר של לכתוב על טכנולוגיה בעברית.

      מחק
  2. מעניין מאוד. תודה רבה. כיף שיש הסבר כה מפורט בעברית.

    השבמחק
    תשובות
    1. אני שמח לשמוע שמצאת את המידע שימושי.

      מחק
  3. אני חושב שהתובנה האחרונה לגבי ה branding של הפלאגינים מאוד נכונה :)
    תודה על עוד מאמר מעניין!

    השבמחק
  4. אחלה פוסט, מקיף ומעניין

    השבמחק
  5. כתבת כ"כ יפה, אז אני ארשה לעצמי
    "בוחרת אלמנטים ב DOM (כלומר ב HTML) ומכילה עליהם עיצוב."
    צריך להיות מחילה מלשון להתחיל (INIT.
    אמנם אולי מבלבל שב"ד מחילה זה סליחה כי באמת המילה התקנית מהמקרא לINIT היא חינוך, כך שהיינו צריכים לאמר "חונכת עליהם עיצוב" אך "כבוד" האקדמיה ללשון החליטה שחינוך זה EDUCATION כלומר לימוד הכולל תפיסה והשקפה והביאה את המילה חל מלשון מחולל שמשמעותו המקראית היא כמו DISPOSE, כמו התרוקן, כמו "חטאתך תחולל", וקישרה אותו ללהתחיל ויצא מחיל.
    להכיל הוא מלשון (CONTAINS).
    מקווה שנהנתם בשיעור לשון - ממריץ אותי לעשות COMPILER בעברית לילדים, רק חבל לי שתתקבע להם המחשבה בעברית

    השבמחק
    תשובות
    1. תודה על ההערה המוקפדת!

      בחיי שזו רק הייתה שגיעט קטיב.

      מחק
  6. כל הכבוד. יכולת הפשטה מצויינת.

    מדהים איך לפעמים משפטים ממש פשוטים, מסתירים מאחוריהם ידע עצום ונרחב.
    וזו בדיוק התועלת המצופה בקריאת בלוג כזה.

    תמשיך כך.

    השבמחק
  7. תודה על הבלוג. בלוג מדהים.
    באמצע הפוסט יש קטע שההזחה היא משמאל לימין.
    אשמח אם תסדר את זה.

    השבמחק