Разница между this и self в JavaScript

118

Все знают о thisjavascript, но есть также примеры, selfвстречающиеся в дикой природе, например здесь

Итак, в чем разница между thisи selfв JavaScript?

Бен Нельсон
источник
3
И по поводу этого ...
Дени Сегюре 01
8
@dystroy: Есть один: window.self( === window). Хотя OP, вероятно, означает тривиальное имя переменной…
Берги
2
@dystroy: На самом деле я не думал, что он действительно может иметь это в виду, но действительно в глобальном масштабе (и в среде браузера) this === selfэто правда :-)
Берги
2
Субъективно: использование псевдонимов thisв selfнастоящее время не является хорошей практикой, когда часто бывает код со многими (ну, более одного - это плохо) уровнями вложенности обратных вызовов, как следствие асинхронного программирования. Вместо этого используйте более информативное имя. Объективно говоря, само имя thisне несет никакой информации и представляет собой лишь неплохой выбор имени, потому что лексический контекст определения класса квалифицирует его.
millimoose 01
2
это правильный и полезный вопрос, его следует
снова

Ответы:

127

Если не установлен в другом месте, то значение selfявляется windowпотому , что JavaScript позволяет получить доступ к любой собственности xв windowкачестве просто x, вместо window.x. Таким образом, selfдействительно window.self, что отличается от this.

window.self === window; // true

Если вы используете функцию, которая выполняется в глобальной области видимости и не находится в строгом режиме, по thisумолчанию windowиспользуется и, следовательно,

function foo() {
    console.log(
        window.self === window, // is self window?
        window.self === this,   // is self this?
        this === window         // is this window?
    );
}
foo(); // true true true

Если вы используете функцию в другом контексте, thisбудет ссылаться на этот контекст, но selfвсе равно будет window.

// invoke foo with context {}
foo.call({}); // true false false

Вы можете найти window.selfопределение объекта Window в рабочем проекте W3C 2006 здесь .

Пол С.
источник
34
Для полноты, selfполезно в контексте WebWorker, когда окно недоступно ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Использование selfвместо windowпозволяет вам получить доступ к глобальному объекту переносимым способом.
lqc 01
24

Небольшое дополнение к этому, поскольку люди могут столкнуться с этим в контексте сервис-воркеров, и в этом случае это означает что-то немного другое.

Вы можете увидеть это в модуле сервис-воркера:

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
});

Здесь self относится к WorkerGlobalScope, и это стандартный метод установки прослушивателей событий.

Из документов Mozilla :

Используя self, вы можете ссылаться на глобальную область видимости таким образом, чтобы это работало не только в контексте окна (self разрешается в window.self), но также и в контексте worker (self затем разрешается в WorkerGlobalScope.self).

Andyhasit
источник
Спасибо ! Я искал этот ответ :)
agpt
23

Хотя я здесь опоздал, я наткнулся на один пример, который тоже может быть полезен для thisдальнейшего понимания :

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    (function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    }());
  }
};
myObject.func();

O / P

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

До ECMA 5 thisвнутренняя функция ссылалась на глобальный объект окна; тогда как в ECMA 5 thisвнутренняя функция не определена.

Шашанк Вивек
источник
это всегда определяется в его контексте. Что не определено, так это this.foo. Это огромная разница, и для достижения поведения, о котором вы упомянули, существовало до ECMA 5, можно использовать стрелочные функции или, как вы указали, назначить self вне внутренней функции и использовать self внутри вместо this, более чистый способ - это функция стрелки .
Дежазмач
2

Ссылка на ECMA 5 требует пояснения.

Я предполагаю, что это означает ECMA-262 Edition 5. Следует отметить, что ECMA-262 (также известный как ECMAScript или, менее точно, Javascript) - это общий язык сценариев, который был реализован в Интернет-браузерах. Из стандарта Edition 5.1:

Следующие шаги выполняются, когда элемент управления входит в контекст выполнения для кода функции, содержащегося в объекте функции F, вызывающий объект предоставил thisArg, а вызывающий объект предоставил argumentsList:

  1. Если код функции является строгим кодом, установите ThisBinding на thisArg.
  2. В противном случае, если thisArg имеет значение null или undefined, установите ThisBinding для глобального объекта.
  3. В противном случае, если Type (thisArg) не является Object, установите ThisBinding на ToObject (thisArg).
  4. В противном случае установите ThisBinding на thisArg
  5. ... (не об "этом")

Термин «глобальный объект» относится к любому объекту, находящемуся в верхней части цепочки областей видимости. Для браузеров это будет объект «окно», но это выбор реализации (Windows Script Host имеет невидимый глобальный объект, но не имеет строгого режима, поэтому неквалифицированные ссылки обращаются к его свойствам, а глобального «я» нет). Кроме того, "строгий режим" должен быть явно включен, иначе он не будет активен (раздел 14.1 стандарта). Таким образом, неопределенное «this» все равно будет преобразовано в глобальный объект (окно) в «ECMA 5» с неактивным строгим режимом.

Итак, ответ на вопрос:

«this» всегда относится к объекту, вызывающему функцию. Если функция не была вызвана объектом (т. Е. Не вызовом метода), то «this» (как передано в функцию) равно «undefined». Однако, если НЕ используется строгий режим, тогда неопределенное «this» устанавливается для глобального объекта (правило 2 выше).

«Я» не имеет особого синтаксического значения, это просто идентификатор. Браузеры обычно определяют window.self (просто свойство глобального объекта окна) = window. Это приводит к тому, что неквалифицированные ссылки на «self» являются такими же, как «window», ЕСЛИ «self» не было переопределено во включающей области (например, с помощью «var self = this;» выше. Удачи в переопределении «this»).

Итак, полное объяснение приведенного выше примера:

outer func:  this.foo = bar
// "this" refers to the invoking object "myObject"
outer func:  self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func:  this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func:  self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"

Интересный вариант примера создает замыкание, возвращая ссылку на внутреннюю функцию.

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    return function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    };
  }
};
var yourObject = {
 foo: "blat",
 func: myObject.func() // function call not function object
};
console.log("----");
yourObject.func();

Производство

outer func:  this.foo = bar
outer func:  self.foo = bar
----
inner func:  this.foo = blat
inner func:  self.foo = bar

Обратите внимание, что внутренняя функция не вызывается, пока не будет вызвана yourObject. Итак, this.foo теперь является yourObject.foo, но self по-прежнему преобразуется в переменную в охватывающей области видимости, которая на момент возврата внутреннего объекта функции была (и в результирующем закрытии все еще остается) myObject. Итак, внутри внутренней функции «this» относится к объекту, вызывающему внутреннюю функцию, а «self» относится к объекту, который вызвал внешнюю функцию, чтобы создать ссылку на внутреннюю функцию.

Подводя итог резюме резюме, "this" определяется стандартом языка, "self" определяется тем, кто его определяет (разработчик среды выполнения или конечный программист).

Убер Клугер
источник
0

Найдите ниже несколько комбинаций консольных выходов «window», «self» и «this» в глобальной области (среде браузера), чтобы узнать, на что они ссылаются.

console.log( window ); // Window {…}
console.log( self );   // Window {…}
console.log( this );   // Window {…}

console.log( window.window ); // Window {…}
console.log( window.self );   // Window {…}
console.log( window.this );   // undefined  

console.log( self.self );     // Window {…}
console.log( self.window );   // Window {…}
console.log( self.this );     // undefined

console.log( this.this );     // undefined
console.log( this.window );   // Window {…}
console.log( this.self );     // Window {…}

console.log( window.window.window );    // Window {…}
console.log( self.self.self );          // Window {…}
console.log( window.self.window.self ); // Window {…}
console.log( self.window.self.window ); // Window {…}
console.log( this.this );               // undefined
ШридхарКрита
источник