Різниця між цим та "Я" у JavaScript


118

Усі знають про thisjavascript, але також існують випадки, коли вони selfзустрічаються в дикій природі, наприклад, тут

Отже, в чому різниця між JavaScript thisта selfJavaScript?



8
@dystroy: Є одне: window.self( === window). Хоча ОП, мабуть, означає тривіальну назву змінної…
Бергі

2
@dystroy: Насправді я не думав, що він насправді може це мати на увазі, але справді в глобальному масштабі (і середовищі браузера) this === selfправда :-)
Бергі

2
Суб'єктивні в стороні: згладжування , thisщоб selfне велика практика в наш час , коли це поширене мати код з багатьма (ну, більш ніж один досить погано) рівнями зворотного виклику вкладеності, як наслідок асинхронного програмування. Натомість використовуйте більш описову назву. Об'єктивно кажучи, саме ім'я thisне містить інформації і є лише неперевершеним вибором імені, оскільки лексичний контекст визначення класу його кваліфікує.
мільйозу

2
це дійсне і корисне питання, його слід знову відкрити
danza

Відповіді:


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з робочим проектом W3C 2006 для об'єкта Window тут .


34
Для повноти selfкорисний у контексті WebWorker, коли вікно недоступне ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Використання selfзамість цього windowдозволяє переносити глобальний об'єкт на портативний спосіб.
lqc

24

Невелике доповнення до цього, оскільки люди можуть зіткнутися з цим у контексті службовців, і в цьому випадку це означає дещо інше.

Ви можете побачити це в модулі сервісного працівника:

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

Тут само посилання на WorkerGlobalScope, і це стандартний метод налаштування слухачів подій.

З Документів Mozilla :

Використовуючи self, ви можете звертатися до глобальної сфери таким чином, щоб вона працювала не лише у віконному контексті (self вирішиться до window.self), але і в робочому контексті (self тоді вирішить для WorkerGlobalScope.self).


Дякую ! Я шукав цей відповідь :)
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();

О / П

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 всередині, чистішим способом є функція стрілки. .
Dejazmach

2

Посилання на ECMA 5 потребує уточнення.

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

Наступні кроки виконуються, коли керування входить у контекст виконання для коду функції, що міститься в об'єкті функцій F, абонент, наданий thisArg, і абонент, що надає аргументиList:

  1. Якщо код функції є суворим кодом, встановіть ThisBinding на цейArg.
  2. В іншому випадку, якщо thisArg є нульовим або невизначеним, встановіть ThisBinding на глобальний об'єкт.
  3. В іншому випадку, якщо Type (thisArg) не є Object, встановіть ThisBinding на ToObject (thisArg).
  4. В іншому встановіть ThisBinding для цьогоArg
  5. ... (не про "це")

Термін "глобальний об'єкт" відноситься до того, що об'єкт знаходиться у верхній частині ланцюга сфери застосування. Для браузерів це буде "віконний" об'єкт, але це вибір реалізації (у хості Windows Script є невидимий глобальний об'єкт, але немає строгого режиму, тому некваліфіковані посилання отримують доступ до його властивостей, і немає глобального "Я"). Також "суворий режим" повинен бути чітко включений, інакше він не активний (розділ 14.1 стандарту). Як таке, невизначене "це" все-таки вирішиться до глобального об'єкта (вікна) в "ECMA 5", якщо суворий режим не активний.

Тож відповідь на питання:

"це" завжди посилається на об'єкт, що викликає функцію. Якщо функція не викликалася об'єктом (тобто не викликом методу), то "це" (як передано функції) є "невизначеним". Однак якщо НЕ використовує суворий режим, то невизначене "це" встановлюється глобальним об'єктом (правило 2 вище).

"Я" не має особливого синтаксичного значення, це лише ідентифікатор. Браузери, як правило, визначають window.self (лише властивість об'єкта глобального вікна) = window. Це призводить до того, що некваліфіковані посилання на "я" є такими ж, як "вікно" БЕЗ ВАС "самовизначення" було переосмислено в рамках, що додається (наприклад, "var self = 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

Зверніть увагу, як внутрішня функція не викликається, поки не викликається вашимObject. Таким чином, this.foo тепер є yourObject.foo, але self все ще вирішує змінну в тій області, що обгороджує, яка на момент повернення внутрішнього об'єкта функції була (і в результаті закриття все ще є myObject). Отже, у внутрішній функції "це" посилається на об'єкт, що викликає внутрішню функцію, тоді як "Я" посилається на об'єкт, який викликав зовнішню функцію для створення посилання на внутрішню функцію.

Для узагальнення резюме підсумків, "це" визначається мовним стандартом, "self" визначається тим, хто його визначає (виконавцем виконання або кінцевим програмістом).


0

Знайдіть нижче деякі комбінації «вікно», «я» та «ця» консоль, що виводиться в глобальному масштабі (середовище браузера), щоб побачити, куди йдеться.

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