سوال در مورد this در function

پرسیده شده
فعالیت 1627 روز پیش
دیده شده 1019 بار
0

تو هر object یه this هست که به خود object اشاره میکنه چرا this در function ها به window اشاره میکنه نه خود function ? 

فایل پیوست

amir yaghoobzadeh
amir yaghoobzadeh

23 آبان 98

0
حذف شده

خب به طور کلی مشکل اصلی با this همیشه اینه که this به چی اشاره داره؟ یا به عبارتی this به چی برمیگرده یا ارجاع پیدا میکنه؟

خب this همیشه به آبجکت ای برمیگرده که در اون آبجکت یا در متد اون آبجکت در حال اجرا شدنه. یا به عبارتی میشه:

The Object That Is Executing The Current Function

برای اینکه بفهمیم کدوم آبجکت هم هست باید بدونیم اون تابعی که this در اون در حال اجرا شدنه از کجا و چگونه فراخوانی شده.

خب اگر بیایم و در یک مرورگر console رو باز کنیم و فورا داخلش تایپ کنیم this و Enter بزنیم متوجه میشیم که به Window Object اشاره میکنه.

حالا اگر کد زیر رو تایپ کنیم چی ؟

123function () {
    console.log(this)
}

در این صورت باز هم به window object اشاره خواهد کرد. چون تمام توابع و متغییر ها زیر مجموعه این آبجکت سراسری هستند.

نکته : اگر Strict Mode فعال باشه مقدار winodw object به undefined بر میگرده و بنابراین در قسمت هایی که this به window object بر میگشت الان دیگه به undefined بر میگرده.

خب حالا اگر کد زیر رو بزنیم نظرتون چیه ؟

12345678910const myObj = {
    init: function () {
        console.log(this);
    },
    print: function(STP) {
        console.log(STP)
    }
}
myObj.init();           //  ----> myObj
myObj.init(this)     // -----> window

همونطور که گفتم چون this در متد init داخل function ای هست که اون function متعلق به myObj هست. پس به myObj بر میگرده ولی در متد print مشاهده میکنیم که مقدار window رو برامون چاپ کرده دلیلش هم اینه که مقدار this داره وارد این متد میشه و خارج از myObj مقدار دهی شده. this در بیرون این object به window اشاره میکرده پس الانم وقتی بیاد داخل این متد باز هم به window اشاره خواهد کرد.

حالا یه مثال دیگه از jQuery

حتما شده که با استفاده از jQuery بخواین یه Click Listener برای یه button بنویسید. به مثال زیر دقت کنید. هر وقت که روی button پرینت کلیک کنید. مقدار this نمایش داده میشود.

123456789var printObj = {
    init: function () {
            const elem = $('button#print');
            elem.on('click', function (){
                     console.log(this); 
            }); 
      }
}
printObj.init();

که در اینجا this مقدار button با آی دی print رو به ما نمایش میده ولی چرا ؟ چرا مقدار printObj رو به ما نشون نمیده چون اگر elem رو کنسول کنید متوجه میشید که elem یه Object هست و تابع کلیک ما برای elem یک متد به حساب میاد و در واقع طبق تعریف اول ما this برای آبجکت elem هست نه برای printObj حالا اگر بخوایم که درون تابع click به printObj دست‌رسی پیدا کنیم میتونیم از تکنیک cache استفاده کنیم. به شکل زیر:

12345678910var printObj = {
    init: function () {
    const self = this;
    const elem = $('button#print');
            elem.on('click', function (){
                      console.log(self);
            })
      }
   }
   printObj.init();

در اینجا self به ما printObj رو نشون میده.

خب تا اینجا متوجه شدیم که اگر this درون متدی از یک آبجت باشه به همون آبجکت برمیگرده و اگر خارج از اون آبجکت باشه به در حقیقت درون یک function باشه که این function هم متد هیچ آبجکتی نباشه پس به window برمیگرده یا اگر NodeJs باشه به global برمیگرده.

12345678910function amir (name) {
    console.log(this) // ---> window obj
    this.name = name
}

const Modal = {
        init: function () {
                console.log(this) // ----> Modal Obj
        },
}

یه پله پیچیده تر:

یه آبجکت تعریف میکنم که پروپرتی store داره و یک لیست از کالا به همراه تابعی که لیست این کالا ها رو چاپ میکنه. اگر متد print رو فراخوانی کنم میشه به شکل زیر:

1234567891011121314151617const Basket = {
        store: "Hasan Agha",
        list: ["Apple", "Pen", "Apple pen"],
        print: function () {
                this.list.forEach(function (item) {
                        console.log(item);
                })
        }
};

Basket.print();

/* ------------------  */
Apple
Pen
Apple pen

تا اینجا که مشکلی نیست ...
خب حالا چی میشه اگر بخوام اسم مغازه هم کنار این کالا ها قرار بدم حتما میگین خب کاری نداره this رو که داریم میریم اونجا که داره لوپ میزنه تا چاپ کنه this.store رو اضافه میکنیم اینجوری ..

1234567this.list.forEach(function (item) {                         
        console.log( this.store --  item);                 
});
/* ------------------  */
undefind -- Apple 
undefind -- Pen 
undefind -- Apple pen

خب this.store که باید "Hasan Agha" رو نشون میداد داره undefind نشون میده اذیت میکنه.

خب پنیک نزنید داستان اینه که اون فانکش که به عنوان ارگومان به forEach پاس دادیم متد حساب نمیشه بلکه یه فانکش معمولی به حساب میاد. که به هیچ جا وصل نیست پس اگر به جای

1 console.log( this.store --  item);

بنویسیم

1console.log( this );

چون فانکش معمولی حساب میشه پس به winodw obj بر خواهد گشت. و چون window.store نداریم به ما undefind برمیگردونه.

حالا یه مثال جالب انگیزناک :

اگر this درون یک Constructor Function باشه چی ؟

123456789function Amir() {
        this.name = "Amir"
        this.printName = {
                console.log(this.name)
        }
};
Amir.printName();    //   ---> Uncaught TypeError: Hasan.printName is not a function
const A1 = new Amir();
A1.printName();         //   ----> Amir

حتما میپرسید که مگه نگفتی اگر فانکشن من داخل متد نبود به window بر میگرده پس چرا الان باز به Amir برگشت؟
جواب اینه که وقتی که از new استفاده میکنیم. پشت صحنه javascript یک آبجکت خالی درست میکنه. و this رو به اون آبجکت خالی برمیگردونه.
بنابراین printName حکم method و name حکم property رو برای Amir ایفا میکنه. البته فقط وقتی که از کلمه رزرو new استفاده میکنم. در غیر این صورت همونطور که دیدید Uncaught TypeError برخوردیم. که بایدم میخوردیم اون Amir که نوشیتم تا new نکنیم به فانکش معمولیه پس this داره به window obj بر میگرده پس printName برای window obj ست شده نه برای Amir .

بنابراین

12window.printName();    // ---> Amir
Amir.printName()         // --> Uncaught TypeError: Hasan.printName is not a function

ولی درست بعد از استفاده از new و ذخیره در A1 متوجه شدیم که داره به A1 برمیگرده.
برای همینه که میگم باید دید this در کجا و چگونه داره فراخوانی میشه.
(اینجا فعلا همینو نگه دارین و بدونین چون بخوام روی این قسمت ریز بشم باید prototype and inheritance هم بگم که هدفم اینه در مقالات بعدی بگم )

خلاصه اینها میشه این:

  • اگر در function معمولی بود بر میگرده به window
  • اگر درون متد بود بر میگرده به اون آبجکتی که داره متد رو اجرا میکنه
  • اگر درون constructor function بود بعد از new کردن برمیگرده به همون constructor function ولی قبل new همون function معمولی به حساب میاد.


خب حالا یکمی عمیق تر میگم:

زبان جاواسکریپت یه زبان مفسری هست. که یعنی هیچ کامپالیی نداریم و مفسر (مترجم) خط به خط کد رو اجرا میکنه در ضمن محیط یا اسکوپی که خط در حال اجرا در اون قرار داره بهش "Execution Context"' گفته میشه. و در ران تایم javascript یک پشته از این Execution Context ها داریم اون تکه کدی که در بالای این پشته قرار داره در حال اجرا شدنه و this همیشه در حال ارجاع دادن به اون تکه کده و هر بار که این تکه کد تغییر میکنه مقدار آدرس this هم باهاش تغییر میکنه.

خب تا اینجا متوجه شدیم که چرا this همیشه در جای های مختلف مقادیر مختلفی رو به ما نشون میشه.

راههایی هم هست برای اینکه مشخصا ذکر کنیم this در تابع یا متد مورد نظر ما دقیقا چه مقداری به خودش اختصاص بده که اونم با استفاده از متد های call - apply - bind هست که در پست بعدی قصد دارم توضیح بدم.

فایل پیوست

AMIR

توسط

AMIR

24 آبان 98

0
حذف شده

خلاصه اینها میشه این:

  • اگر در function معمولی بود بر میگرده به window
  • اگر درون متد بود بر میگرده به اون آبجکتی که داره متد رو اجرا میکنه
  • اگر درون constructor function بود بعد از new کردن برمیگرده به همون constructor function ولی قبل new همون function معمولی به حساب میاد.
فایل پیوست

AMIR

توسط

AMIR

24 آبان 98

حذف شده
خیلی عالی و کامل بود و نکات جالبی هم بهش اشاره شده بود... خودت همشو نوشتی؟
mostafa hedayat

24 آبان 98

حذف شده
البته در مورد گزینه اول چنانچه کلمه this درون یک function مرتبط به رویداد (event) باشه مثلا onClick باشه به همون عنصر از DOM اشاره داره مثلا اگه توی رویداد کلیک یک button از کلمه this استفاده بشه this به همون button اشاره میکنه نه window
Hedayat Kamalian

24 آبان 98

حذف شده
اگر ما در حالت مدرن باشیم یعنی از use strict استفاده کرده باشم درصورتی که در یک تابع معمولی از this استفاده بکنیم undefined برگشت داده خواهد شد نه window
رضا پروین

25 آبان 98

حذف شده
سوال بود
رضا پروین

25 آبان 98

حذف شده
خیلی عالی و کامل???
AliMweb

25 آبان 98

حذف شده
دوستان خیلی ممنون از فید های مثبتی که به من دادید
AMIR

9 آذر 98

0
حذف شده

کلمه کلیدی this به صاحب خودش اشاره میکنه، وقتی یک شئ از یک کلاس میسازید، این کلمه کلیدی درون کلاس، به صاحبش یعنی اون آبجکتی که ازش ساختی اشاره میکنه. اگه دقت بشه وقتی از this داخل متد استفاده میشه این کلمه به خود متد اشاره نمیکنه بلکه به ابجکت ساخته شده اشاره داره.

اما وقتی خارج از کلاس، یک متد میسازید، بازهم this باید به صاحبش اشاره کنه.که در اینجا به ابجکت window اشاره میکنه. زمانیکه صفحه شما لود میشه این ابجکت ساخته میشه که در خودش یه سری متدها و پراپرتیزها داره.

فایل پیوست

محسن موحد

توسط

محسن موحد

24 آبان 98

0
حذف شده

یک سورس بسیار عالی که مثال های متعدد هم داره 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

 

فایل پیوست

AMIR

توسط

AMIR

9 آذر 98