המדריך השלם לכך ב- JavaScript

ב- JavaScript, לכל פונקציה יש thisהפניה שנוצרת אוטומטית כשאתה מצהיר עליה.

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

להלן 5 כללים בסיסיים thisלכריכה ב- JavaScript:

חוק מספר 1

כאשר פונקציה נקראת בהיקף הגלובלי, thisההפניה כברירת מחדל קשורה לאובייקט הגלובלי ( windowבדפדפן, או globalב- Node.js). לדוגמה:

function foo() { this.a = 2; } foo(); console.log(a); // 2

הערה: אם אתה מצהיר על foo()הפונקציה לעיל במצב קפדני, אז אתה קורא לפונקציה זו בהיקף גלובלי, thisיהיה undefinedוההקצאה this.a = 2תזרוק Uncaught TypeErrorחריג.

כלל 2

בואו נבחן דוגמה למטה:

function foo() { this.a = 2; } const obj = { foo: foo }; obj.foo(); console.log(obj.a); // 2

ברור שבקטע הקוד שלמעלה, foo()הפונקציה נקראת עם הקשר היא objאובייקט thisוההתייחסות כעת קשורה ל obj. לכן כאשר נקראת לפונקציה עם אובייקט הקשר, thisההפניה תהיה קשורה לאובייקט זה.

כלל 3

.call, .applyו .bindיכול לשמש כל באתר הקריאה לאגד במפורש this. השימוש .bind(this)הוא משהו שאתה עשוי לראות בהרבה מאוד רכיבי תגובה.

const foo = function() { console.log(this.bar) } foo.call({ bar: 1 }) // 1

הנה דוגמה מהירה לאופן שבו כל אחד משמש לקישור this:

  • .call(): fn.call(thisObj, fnParam1, fnParam2)
  • .apply(): fn.apply(thisObj, [fnParam1, fnParam2])
  • .bind(): const newFn = fn.bind(thisObj, fnParam1, fnParam2)

כלל 4

function Point2D(x, y) { this.x = x; this.y = y; } const p1 = new Point2D(1, 2); console.log(p1.x); // 1 console.log(p1.y); // 2

הדבר שאתה חייב לשים לב אליו הוא Point2Dהפונקציה שנקראת עם newמילת מפתח, thisוההתייחסות חייבת להיות p1אובייקט. לכן כאשר נקראת לפונקציה עם newמילת מפתח, היא תיצור אובייקט חדש thisוההתייחסות תהיה קשורה לאובייקט זה.

הערה: כשאתה קורא לפונקציה עם newמילת מפתח, אנו מכנים אותה גם כפונקציית קונסטרוקטור .

כלל 5

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

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

const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.makeSound(); // Fat Daddy says: Mrrooowww

עכשיו בואו ננסה לתת לחתול דרך annoy()לאנשים על ידי חזרה על הצליל שלו 100 פעמים, אחת לחצי שנייה.

const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const t = setInterval(function() { this.makeSound(); // <-- this line fails with `this.makeSound is not a function` count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();

זה לא עובד מכיוון שבתוך setIntervalהשיחה החוזרת יצרנו הקשר חדש עם היקף גלובלי, ולכן thisכבר לא מצביע על מופע החתול שלנו. בדפדפן אינטרנט, thisבמקום זאת יצביע על אובייקט Window, שאין לו makeSound()שיטה.

כמה דרכים לגרום לזה לעבוד:

  1. לפני שתיצור את ההקשר החדש, הקצה thisלמשתנה מקומי בשם me, או self, או איך שלא תרצה לקרוא לו, והשתמש במשתנה זה בתוך החזרה להתקשרות.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const self = this; const t = setInterval(function() { self.makeSound(); count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();
  1. עם ES6 תוכלו להימנע מהקצאה thisלמשתנה מקומי באמצעות פונקציית חץ, הנקשרת thisלהקשר של הקוד שמסביב במקום בו הוא מוגדר.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const t = setInterval(() => { this.makeSound(); count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();