לדלג לתוכן

4.2 מילת המפתח this תרגול

תרגול - מילת המפתח this


תרגיל 1 - חידות this

מה ידפיס כל אחד מקטעי הקוד? ענו בלי להריץ.

חידה א:

const obj = {
    name: "Object",
    getName: function() {
        return this.name;
    },
    getNameArrow: () => {
        return this.name;
    }
};

console.log(obj.getName());
console.log(obj.getNameArrow());

חידה ב:

const person = {
    name: "Alice",
    friends: ["Bob", "Charlie"],
    listFriends() {
        this.friends.forEach(function(friend) {
            console.log(`${this.name} is friends with ${friend}`);
        });
    }
};

person.listFriends();

חידה ג:

function Dog(name) {
    this.name = name;
    this.bark = function() {
        console.log(`${this.name} says woof!`);
    };
}

const dog = new Dog("Rex");
const bark = dog.bark;

dog.bark();
bark();

תרגיל 2 - תיקון הקשר שאבד

התקנו את הקוד הבא כך שכל המתודות יעבדו נכון, גם כש-this הולך לאיבוד. תנו שני פתרונות - אחד עם bind ואחד עם arrow function.

class Playlist {
    constructor(name) {
        this.name = name;
        this.songs = [];
    }

    addSong(song) {
        this.songs.push(song);
        console.log(`Added "${song}" to ${this.name}`);
    }

    play() {
        console.log(`Playing ${this.name}:`);
        this.songs.forEach(function(song, i) {
            console.log(`  ${i + 1}. ${song} (from ${this.name})`);
        });
    }
}

const playlist = new Playlist("My Favorites");
playlist.addSong("Song A");
playlist.addSong("Song B");

// these should work:
playlist.play();

const addSong = playlist.addSong;
addSong("Song C"); // should work without errors

setTimeout(playlist.play, 100); // should work without errors

תרגיל 3 - call, apply, bind

חלק א

כתבו פונקציה introduce שמדפיסה הצגה עצמית. הפעילו אותה עם call ו-apply על אובייקטים שונים:

function introduce(greeting, hobby) {
    console.log(`${greeting}! I'm ${this.name}, age ${this.age}. I love ${hobby}.`);
}

const alice = { name: "Alice", age: 25 };
const bob = { name: "Bob", age: 30 };

// call introduce with alice and bob using call and apply

חלק ב

כתבו פונקציה borrowMethod שמקבלת אובייקט מקור, שם מתודה, ואובייקט יעד - ומחזירה את המתודה כשהיא bound לאובייקט היעד:

const calculator = {
    value: 0,
    add(n) {
        this.value += n;
        return this;
    },
    getValue() {
        return this.value;
    }
};

const myObj = { value: 100 };

const boundAdd = borrowMethod(calculator, "add", myObj);
boundAdd(5);
boundAdd(10);
console.log(myObj.value); // 115

תרגיל 4 - אובייקט עם שרשור מתודות

צרו אובייקט QueryBuilder שבונה שאילתה עם שרשור מתודות (method chaining). כל מתודה צריכה להחזיר this:

const query = new QueryBuilder("users")
    .select("name", "email")
    .where("age", ">", 18)
    .where("active", "=", true)
    .orderBy("name")
    .limit(10)
    .build();

console.log(query);
// "SELECT name, email FROM users WHERE age > 18 AND active = true ORDER BY name LIMIT 10"

תרגיל 5 - this ב-event handlers

כתבו מחלקה ClickTracker שעוקבת אחרי לחיצות על כפתור:

  • ה-constructor מקבל element selector (מחרוזת CSS)
  • start() - מתחיל לעקוב אחרי לחיצות
  • stop() - מפסיק לעקוב
  • getCount() - מחזיר כמה לחיצות היו
  • reset() - מאפס את המונה

שימו לב שצריך לשמור הפניה ל-handler כדי שאפשר יהיה להסיר אותו עם removeEventListener.

const tracker = new ClickTracker("#myButton");
tracker.start();
// ... user clicks the button 3 times ...
console.log(tracker.getCount()); // 3
tracker.stop();
// ... more clicks don't count ...
tracker.reset();
console.log(tracker.getCount()); // 0

תרגיל 6 - this במקרים מורכבים

חלק א

צרו אובייקט eventEmitter עם המתודות:

  • on(event, handler) - רושם handler לאירוע מסוים
  • emit(event, ...args) - מפעיל את כל ה-handlers של אירוע מסוים
  • off(event, handler) - מסיר handler מסוים

כש-handler רץ, this שלו צריך להצביע על ה-eventEmitter.

const emitter = createEventEmitter();

function onData(data) {
    console.log(`${this.name} received: ${data}`);
}

emitter.name = "MyEmitter";
emitter.on("data", onData);
emitter.emit("data", "hello"); // "MyEmitter received: hello"

חלק ב

הוסיפו מתודה once(event, handler) שרושמת handler שרץ פעם אחת בלבד ואז מסיר את עצמו.


תרגיל 7 - השוואה מסכמת

ללא הרצה, קבעו מה הערך של this בכל שורה מסומנת:

const obj = {
    value: 42,

    regular() {
        console.log(this.value);         // (A)

        const inner = function() {
            console.log(this.value);     // (B)
        };
        inner();

        const arrow = () => {
            console.log(this.value);     // (C)
        };
        arrow();
    },

    arrow: () => {
        console.log(this.value);         // (D)
    }
};

obj.regular();
obj.arrow();

const fn = obj.regular;
fn();                                     // (E) - what happens at lines A, B, C?

const bound = obj.regular.bind(obj);
bound();                                  // (F) - what happens at lines A, B, C?