آموزش خطای (this)$ در جی کوئری

 ما یک شنونده ی رویداد(event handler) داریم که یک کلاس را به یک عنصر DOM اضافه می کند، و با استفاده از setTimeout() یک ثانیه صبر می کند و سپس این کلاس را حذف می کند:

$(document).ready( function() {
    $('.clicky').click( function() {
        $(this).addClass('clicked');
        setTimeout( function() {
            $(this).removeClass('clicked');
        }, 1000 );
    });
});

 مشکل این است که وقتی ما کلیک کنیم، کلاس مورد نظر اضافه می شود اما دیگر هرگز حذف نمی شود. ما تایید می کنیم که کدهای درون setTimeout() فراخوانی شده اند اما به نظر نمی رسد کاری را انجام داده باشند. ما قبلا هم از دستور removeClass() استفاده کرده ایم  و می دانیم که درست کار می کند. ما همین کار را در دو مکان انجام داده ایم، اما به نظر نمی رسد که  در دستور setTimeout() این کدها، کار کند.

 


راه حل

کلمه ی کلیدی this را قبل از فراخوانی setTimeout() در یک متغیر قرار دهید:

$(document).ready( function() {
    $('.clicky').click( function() {
      var element = this;
      $(element).addClass('clicked');
      setTimeout( function() {
          $(element).removeClass('clicked');
      }, 1000 );
   });
});

 بهتر از آن، این است که چون ما در هر دو محل، عبارت $() را فراخوانی می کنیم، توصیه ی بخش 5.3  را دنبال کنیم و عبارت $(this) را به جای this در داخل یک متغیر قرار دهیم:

$(document).ready( function() {
    $('.clicky').click( function() {
      var $element = $(this);
      $element.addClass('clicked');
      setTimeout( function() {
         $element.removeClass('clicked');
      }, 1000 );
   });
});

 


توضیحات

سوال اینجاست که $(this) چیست و چرا همواره کار نمی کند؟ بهتر و ساده تر است که این سوال را به دو بخش تقسیم کنیم، یعنی $() چیست و this چیست؟  عبارت $() کمی مبهم به نظر می رسد اما این طور نیست: این تنها یک فراخوانی تابع است. علامت $ به تابع jQuery رجوع می کند، بنابراین عبارت $() یک راه کوتاه تر برای نوشتن دستور jQuery() است. این فقط فراخوانی یک تابع معمولی جاوا اسکریپت است که از آن برای برگرداندن یک  آبجکت استفاده می شود.

 


نکته:  اگر دارید از یک کتابخانه ی جاوا اسکریپت دیگر استفاده می کنید که علامت $ را بازتعریف می کند، قضیه فرق می کند-و ما دیگر نباید از دستور $() در کدهای جی کوئری خود استفاده کنیم  و باید از نام مستعار شخصی jQuery() استفاده کنیم.


 کلمه ی کلیدی this یکی از گیج کننده ترین ویژگی ها در جاوا اسکرپیت است؛ زیرا از آن برای کارهای مختلفی استفاده می شود.

نکته 1: در برنامه نویسی شیء گرای جاوا اسکریپت، از کلمه ی this در متدهای یک آبجکت برای رجوع به آن آبجکت استفاده می شود؛ درست مانند کلمه ی کلیدی self در پایتون یا روبی.

function Foo( value ) {
  this.value = value;
}
Foo.prototype.alert = function() {
  alert( this.value );
};
var foo = new Foo( 'bar' );
foo.alert(); // 'bar'

 در کد زیر، برای یک خصوصیت onevent (در اینجا onclick) کلمه ی کلیدی this به عنصری رجوع می کند که رویداد را دریافت می کند-اما فقط در داخل خود خصوصیت؛ نه در تابعی که برای این خصوصیت فراخوانی شده است؛ مانند خط 1 در زیر:

<a href="#" id="test" onclick="clicked(this);">Test</a>
function clicked( it ) {
  alert( it.id ); // 'test'
  alert( this.id ); // undefined
  alert( this === window ); // true (what?)
}

 در کدهای بالا همان طور که در خط 5 مشاهده می کنید، کلمه ی کلیدی this در درون تابع، برابر با آبجکت window است.

نکته2: به دلایل تاریخی، وقتی که یک تابع مستقیماً فراخوانی شود(نه اینکه بعنوان یک متد از یک آبجکت فراخوانی شود)، آبجکت window معنی پیش فرض کلمه ی کلیدی this محسوب می شود.

 نکته 3: در یک شنونده ی رویداد(event handler) جی کوئری، کلمه ی this برابر با آن عنصر DOM ای است که رویداد مورد نظر را به کار می برد، بنابراین عبارت $(this) به آن عنصر DOM اشاره می کند.

 

بنابراین، علت اینکه دستور  $(this).addClass()  در کدهای مسئله ی ما به درستی کار می کرد، همین نکته ی شماه 3 است.  اما پس از این کد، دستور setTimeout() اجرا می شود؛ و این دستور مانند فراخوانی مستقیم یک تابع عمل می کند و کلمه ی کلیدی this در اینجا به آبجکت window اشاره می کند؛ نه به عنصر DOM مورد نظر.

بنابراین وقتی که کدهای ما دستور $(this).removeClass() را فراخوانی می کنند، در حقیقت تلاش می شود تا کلاس مورد نظر از آبجکت window حذف شود. اما چرا ما باید کلمه ی this یا $(this) را در داخل یک متغیر محلی قرار دهیم تا مسئله حل شود؟ زیرا جاوا اسکریپت برای پارامترها و متغیرهای محلی یک تابع، یک کلوژر ایجاد می کند. کلوژرها در ابتدا ممکن است مبهم به نظر برسند، اما آنها واقعا از سه قاعده پیروی می کنند:

  1.  ما می توانیم تابع ها یا کلوژرهای جاوا اسکریپت را یکی در داخل دیگری قرار دهیم و تو رفتگی ایجاد کنیم. این تو رفتگی ها می توانند چندین سطح داشته باشند.
  2. یک تابع یا کلوژر نه تنها می تواند پارامترها و متغیرهای محلی خود را بخواند و بنویسد بلکه می تواند پارامترها و متغیرهای هر تابعی که در داخل آن قرار گرفته است را نیز بخواند و بنویسد.
  3. قاعده ی قبلی همواره کار می کند، حتی اگر تابع بیرونی قبلا return شده باشد و تابع درونی بعداً فراخوانی شود(مثلا یک شنونده ی رویداد یا قسمت callback یک setTimeout).

این قواعد به همه ی تابع ها اعمال می شوند؛ هم تابع های نام دار و هم تابع های بی نام.اما کلمه ی کلیدی this نه یک پارامتر تابع است و نه یک متغیر محلی است؛ بلکه یک کلمه ی(keyword) خاص جاوا اسکریپت است. بنابراین قاعده های بالا بر روی آن اعمال نمی شوند. با کپی کردن مقدار کلمه ی کلیدی this در یک متغیر محلی، ما از کلوژرها بهره می بریم و آن مقدار را در هر تابع تو در تویی(nested functions) در دسترس قرار می دهیم.

برای نظردهی، در سایت عضو شوید یا به آن وارد شوید!

ستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعال