var self = це?


182

Використання методів екземплярів як зворотних викликів для обробників подій змінює область дії thisз "Мій екземпляр" на "Що б тільки не викликали зворотний виклик" . Тож мій код виглядає приблизно так

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

Це працює, але це найкращий спосіб зробити це? Мені це дивно виглядає.


15
Вам слід уникати, selfоскільки є window.selfоб'єкт, і ви можете випадково його використовувати, якщо ви забудете оголосити свій власний selfvar (наприклад, пересуваючи якийсь код навколо). Це може дратувати пляму / налагодження. Краще використовувати щось подібне _this.
Alastair Maw


3
З JavaScript Підручник : «Значення thisдинамічна в JavaScript Це визначається , коли функція. Називається , не тоді , коли вона оголошена.»
DavidRR


Річ у тому, що в глобальному масштабі self === this. Тому selfв місцевих контекстах є сенс і слідкуйте за зразком.
програміст5000

Відповіді:


210

Це питання не стосується jQuery, але загалом стосується JavaScript. Основна проблема полягає в тому, як "каналізувати" змінну у вбудованих функціях. Це приклад:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

Ця методика спирається на використання замикання. Але це не працює, thisтому що thisце псевдо-змінна, яка може динамічно змінюватися від області до області:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

Що ми можемо зробити? Призначте її до якоїсь змінної та використовуйте її через псевдонім:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

thisне є унікальним у цьому відношенні: чи argumentsє інша псевдозмінна, до якої слід ставитися так само - шляхом зведення.


7
Ви дійсно повинні прив’язати "це" до виклику функції, а не передавати його навколо або проміняти з ним змінні області
michael

10
@michael Чому це?
Кріс Андерсон

@michael, можливо, ви працюєте всередині pipe, map, передплачуєте ... в одній функції, а не викликаєте функції, у цьому випадку "це" змінюється, тому змінна область є рішенням
Скандер Дженхані

@SkanderJenhani цьому коментарю 8 років. Моя відповідь була б сьогодні дуже різною
michael

18

Так, це здається загальним стандартом. Деякі кодери використовують самості, інші використовують мене. Він використовується як посилання на "реальний" об'єкт на відміну від події.

Це щось, що мені зайняло трохи часу, щоб реально дістатись, спочатку це виглядає дивно.

Зазвичай я роблю це прямо у верхній частині свого об'єкта (вибачте, мій демо-код - це більш концептуально, ніж усе інше і не є уроком з відмінної техніки кодування):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}

12
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

редагувати: незважаючи на вкладені функції всередині об'єкта, переймає глобальний об'єкт вікна, а не навколишній об'єкт.


Ви, здається, описуєте, що var self = thisробить, але це не те, що задається питанням (питання полягає в тому, чи це найкраще рішення проблеми).
Квентін

3
"Основна проблема полягає в тому, як" каналізувати "змінну у вбудованих функціях." Я погоджуюся з цим твердженням у прийнятій відповіді. Крім того, що немає нічого поганого в практиці "тієї". Це досить поширене явище. Отже, як частина відповіді на "код мені дивно виглядає" я вибрав пояснення, як це працює. Я вважаю, що причина, що "код мені здається дивним", походить від плутанини того, як він працює.
серкан

12

Якщо ви робите ES2015 або робите скрипт типу та ES5, то ви можете використовувати функції стрілок у своєму коді, і ви не стикаєтесь з цією помилкою, і це стосується бажаного обсягу у вашому випадку.

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
Як пояснення: у ES2015 функції стрілок захоплюють thisіз визначеної області їх застосування. Нормальні визначення функцій цього не роблять.
денонсування

@defnull Я не думаю, що це щось особливе. Функції створюють область блоку. тому використання позначення стрілки замість функції не дозволяє створювати область, тому це все ще буде посилатися на зовнішню цю змінну.
Німешка Срімаль

4

Одне рішення для цього - прив’язати весь зворотний виклик до вашого об'єкта bindметодом javascript .

Це можна зробити за допомогою названого методу,

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

Або з анонімним зворотним дзвоном

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

Виконуючи це, замість того, щоб вдаватися до var self = thisпоказів, ви розумієте, як прив'язка thisповодиться в JavaScript і не покладається на посилання на закриття.

Крім того, оператор зі стрілкою жиру в ES6 в основному є тим самим викликом .bind(this)анонімної функції:

doCallback( () => {
  // You can reference "this" here now
});

Особисто я думаю, що .bind (це) просто більше набирає текст, змінюючи це посилання на мене (або що завгодно), а потім просто використовувати його, замість цього робить чистішим кодом. Жирова стрілка - це майбутнє тхо.
davidbuttar

3

Я не використовував jQuery, але в такій бібліотеці, як прототип, ви можете прив'язувати функції до певної області. Отже, маючи на увазі, ваш код виглядатиме так:

 $('#foobar').ready('click', this.doSomething.bind(this));

Метод прив'язки повертає нову функцію, яка викликає вихідний метод із заданим вами областю.


Аналог: $('#foobar').ready('click', this.doSomething.call(this));правильно?
Muers

bindМетод не працює в старих браузерах, тому використовуйте $.proxyметод.
Гуффа


1

Я думаю, що насправді залежить від того, що ти збираєшся робити у межах своєї doSomethingфункції. Якщо ви збираєтеся отримати доступ до MyObjectресурсів за допомогою цього ключового слова, вам доведеться ним скористатися. Але я думаю, що наступний фрагмент коду також буде працювати, якщо ви не робите особливих речей, використовуючи object(MyObject)властивості.

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.