דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. JS: איך עובד this binding?

JS: איך עובד this binding?

מתוזמן נעוץ נעול הועבר תכנות
12 פוסטים 3 כותבים 199 צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • yossizY מנותק
    yossizY מנותק
    yossiz
    כתב ב נערך לאחרונה על ידי
    #1

    דבר מעניין שלמדתי אתמול:

    const myLogger = {
      messageNumber: 0,
      log (message) {
        console.log(`${this.messageNumber++}: ${message}`);
      }
    };
    
    function log (message, logger) {
      (logger.log || console.log)(message);
    }
    
    log('Hello, world!', myLogger);
    log('Another message...', myLogger);
    

    מה יהיה בפלט של הקוד, (ובעיקר למה?)

    📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

    תגובה 1 תגובה אחרונה
    2
    • dovidD מנותק
      dovidD מנותק
      dovid ניהול
      כתב ב נערך לאחרונה על ידי
      #2

      אוקי הבנתי, הthis מתייחס למיקום של המצביע ולא למיקום של הפונקציה עצמה שלו אין משמעות.
      זה הגיוני. הנה המחשה יותר בסגנון שלי:

      var test = {
        a: 0,
        log: function log () {
          console.log(this.a++);
        }
      };
      test.log()
      var refFun = test.log;
      refFun();
      

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

      מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

      בכל נושא אפשר ליצור קשר dovid@tchumim.com

      yossizY תגובה 1 תגובה אחרונה
      1
      • dovidD מנותק
        dovidD מנותק
        dovid ניהול
        כתב ב נערך לאחרונה על ידי
        #3

        עוד זוית:

        var objA = {
           a: 0,
           log: function(){
                console.log(this.a++);
           }
        };
        var objB = {
           a: 0,
           log: objA.log
        };
        var objC = {
           a: 0,
           log: objA.log
        };
        
        objA.log();
        objA.log();
        objB.log();
        objB.log();
        objC.log();
        objC.log();
        

        מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

        בכל נושא אפשר ליצור קשר dovid@tchumim.com

        תגובה 1 תגובה אחרונה
        1
        • yossizY מנותק
          yossizY מנותק
          yossiz
          השיב לdovid ב נערך לאחרונה על ידי yossiz
          #4

          @dovid עיקר השאלה שלי הוא מה ההגיון לזה ש "שאופרטור || מחזיר מצביע חדש"?

          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

          תגובה 1 תגובה אחרונה
          0
          • yossizY מנותק
            yossizY מנותק
            yossiz
            כתב ב נערך לאחרונה על ידי yossiz
            #5

            @dovid תמיד הסתכלתי על הלוגיקה של איגוד ה-this גם כן כמוך שזה ענין של "על ידי איזה מצביע הגעת לפונקציה?". אבל מתוך הנ"ל למדתי שהכיוון שגוי. זו הנקודה שאותה רציתי ללבן.

            במנוע JS יש 2 רכיבים: ה"מפרסר" וה"מריץ".
            המפרסר מפרסר את הקוד ומתרגם אותה לפעולות קטנטנות פרימטיביות, שאותם הרכיב המריץ מריץ.
            המשימה של איגוד ה-this לאובייקט הנכון היא משימתה של המפרסר ולא של המריץ. מבחינת המריץ, הפונקציה נראית אותו דבר לגמרי בין אם נגשת לזה כמאפיין של אובייקט אחר או לא. זה תמיד אותו "מצביע".
            כדי לאגד את ה-this, המפרסר בודק את ההקשר הלשוני של אפרטור הקריאה - ().
            הכלל הוא שאם אופרטור הקריאה () מתייחס לביטוי של "גישה למאפיין של אובייקט" (MemberExpression), אז המפרסר מאגד את האובייקט ההוא ל-this של הפונקציה בעת הקריאה (כלומר, במקרה של obj.property(...args) המפרסר מתרגם את הקוד לפעולה שמתנהגת כ-property.call(obj, ...args))
            בדוגמה שלי, הביטוי שאליו מתייחסת אופרטור הקריאה הוא ביטוי לוגי (LogicalExpression), לא ביטוי של גישה למאפיין של אובייקט.

            עיין כאן בניתוח ה-AST של (logger.log || console.log)(message) ותבין.

            📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

            dovidD תגובה 1 תגובה אחרונה
            3
            • dovidD מנותק
              dovidD מנותק
              dovid ניהול
              השיב לyossiz ב נערך לאחרונה על ידי dovid
              #6

              @yossiz ראשית אני מעריך את העומק. הבנתי מה שאתה אומר שהמריץ כבר לא מתעסק עם this כי המפרסר מחליט בשבילו, וזה בהחלט יפה לדעת.
              שנית, בראש שלי אינני מבין למה צריך להגיע לזה, זה ברור שתוצאת ה || מחזירה מצביע חדש. כי ה || מחזירות ערך שהוא הנכון מבין השניים. ודאי שזה לא מחזיר את המצביע המקורי (שאז היית עושה ++ למשל אחרי הסוגריים).

              מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

              בכל נושא אפשר ליצור קשר dovid@tchumim.com

              yossizY תגובה 1 תגובה אחרונה
              2
              • yossizY מנותק
                yossizY מנותק
                yossiz
                השיב לdovid ב נערך לאחרונה על ידי yossiz
                #7

                @dovid אמר בJS: איך עובד this binding?:

                שנית, בראש שלי אינני מבין למה צריך להגיע לזה, זה ברור שתוצאת ה || מחזירה מצביע חדש. כי ה || מחזירות ערך שהוא הנכון מבין השניים. ודאי שזה לא מחזיר את המצביע המקורי (שאז אם היית עושה ++ למשל אחרי הסוגריים).

                לא הבנתי כוונתך. נגיד לשם דוגמה שהביטוי object.property מחזיר מצביע במיקום 0x000a שערכו הוא 0x000b שזה הכתובת בזכרון של הפונקציה property.
                אז בשלמא אם אתה כותב: let a = object.property מובן שזה ייתן לך מצביע חדש במיקום 0x000c שערכו גם כן 0x000b.
                אבל למה נראה לך שהביטוי (null || object.property) לא יחזיר בדיוק אותו מצביע שobject.property יחזיר?

                📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                dovidD תגובה 1 תגובה אחרונה
                0
                • dovidD מנותק
                  dovidD מנותק
                  dovid ניהול
                  השיב לyossiz ב נערך לאחרונה על ידי dovid
                  #8

                  @yossiz שוב פעם אתה תמיד מגיע מהבנת הדברים לעומקם, תסביר לי שאני די רדוד ותמים בעניין למה הקוד הזה לא חוקי:

                  var a = 0, b = 1;
                  var c = (a || b)++;
                  

                  אם ה || היה מחזיר מצביע זה היה אמור להיות קוד חוקי.
                  ההבנה הפשוטה היא מייד שה || מחזיר ערך ולא מצביע. ולערך לא שייך לעשות ++.

                  מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                  בכל נושא אפשר ליצור קשר dovid@tchumim.com

                  yossizY א 2 תגובות תגובה אחרונה
                  3
                  • yossizY מנותק
                    yossizY מנותק
                    yossiz
                    השיב לdovid ב נערך לאחרונה על ידי yossiz
                    #9

                    @dovid רק עכשיו אני מבין מה התכוונת מקודם. אני כבר לא בטוח שאני צודק... תן לי לעשות קצת 🤔 (ואל תגיד שאתה רדוד ותמים... כמעט הצלחת לשכנע אותי 😮 )

                    📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                    תגובה 1 תגובה אחרונה
                    3
                    • א מנותק
                      א מנותק
                      אהרן
                      השיב לdovid ב נערך לאחרונה על ידי
                      #10

                      @dovid אמר בJS: איך עובד this binding?:

                      לערך לא שייך לעשות ++.

                      מה הכוונה?
                      חשבתי ש-++ עובד רק בפרמיטיביים, שבהם מאוחסן הערך עצמו?!

                      dovidD תגובה 1 תגובה אחרונה
                      0
                      • dovidD מנותק
                        dovidD מנותק
                        dovid ניהול
                        השיב לאהרן ב נערך לאחרונה על ידי
                        #11

                        @אהרן נכון, רק כתבתי שלערך עצמו ללא כל משתנה ( = כתובת בזיכרון לערך החדש), לא שייך לעשות ++.

                        מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                        בכל נושא אפשר ליצור קשר dovid@tchumim.com

                        תגובה 1 תגובה אחרונה
                        2
                        • yossizY מנותק
                          yossizY מנותק
                          yossiz
                          כתב ב נערך לאחרונה על ידי yossiz
                          #12

                          @dovid אחרי העיון, (ואם תרשה לי לתרגם את הדברים שלך מהזווית שלי), אני מסכים לגמרי למה שאתה טוען, ועוד יותר, נראה לי שזה פחות או יותר אותו דבר כמו שאני אמרתי

                          ובהקדם,
                          צריך להבחין בין ערך, מצביע, ו-identifier.

                          • ערך הוא הערך הגולמי. לדוגמה המספר 5, או התו 'a'. זה אובייקט שקיים בזכרון בזמן ריצה.
                          • מצביע (pointer) ג"כ הוא אובייקט פיזי שקיים בזמן ריצה. כלומר, מדובר על ערך שקיים בזכרון שערכו הוא כתובת זכרון של אובייקט אחר.
                          • בשונה מזה, identifier הוא מושג שקיים רק ברמת השפה/מפרסר. מדובר על "ידית" לכתובת זכרון, כלומר, דרך להזכיר את הכתובת של ערך בלי לייצר "מצביע" רגיל.
                            (למי שמכיר, ההבדל בין pointer ל-identifier הוא ההבדל ב-++C בין pointer ל-reference variable, נוסח אחר לאותו מושג זה lvalue ו-rvalue)

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

                          אם כן, אפשר לתרגם מה ש@dovid אמר בצורה כזאת:
                          התוצאה של ביטוי לוגי עם אופרטור || היא "ערך" ולא identifier. והמפרסר חייב identifier עבור פעולת ++.

                          אותו דבר, ב-this binding.
                          המפרסר עושה את איגוד ה-this בכפוף לצורה שבה הזכרת את הפונקציה. אם הזכרת אותו על ידי identifier שהוא חלק מביטוי שהוא בתבנית MemberExpression אז יתבצע איגוד לאובייקט הבסיס של ה-MemberExpression. אחרת זה לא יתבצע.
                          הביטוי logger.log || console.log הוא לא MemberExpression
                          ויותר מזה הוא לא identifier בכלל אלא ערך גולמי של פונקציה. וזה מה שדוד מוסיף.

                          הכל ברור? 🙂

                          עריכה: ושכחתי להגיד תודה ל @dovid על העזרה שלו בליבון הנושא. תודה רבה.

                          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                          תגובה 1 תגובה אחרונה
                          4

                          בא תתחבר לדף היומי!
                          • התחברות

                          • אין לך חשבון עדיין? הרשמה

                          • התחברו או הירשמו כדי לחפש.
                          • פוסט ראשון
                            פוסט אחרון
                          0
                          • דף הבית
                          • קטגוריות
                          • פוסטים אחרונים
                          • משתמשים
                          • חיפוש
                          • חוקי הפורום