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?