Як працює ключове слово "це"?


1309

Я помітив, що не видається чіткого пояснення, що таке thisключове слово та як воно правильно (і неправильно) використовується в JavaScript на сайті переповнення стека.

Я був свідком дуже дивної поведінки з цим і не зрозумів, чому це сталося.

Як thisпрацює і коли його слід використовувати?


6
Я виявив це, коли переглянув
Вай Вонг,


2
Пітер Мішо виступає проти використання this peter.michaux.ca/articles/javascript-widgets-without-this
Марсель Корпель

1
Огляд MDN не є напівпоганим ... developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
дат

2
Цікаве пояснення thisключового слова: rainsoft.io/gentle-explanation-of-this-in-javascript
Дмитро Павлутін

Відповіді:


1350

Рекомендую спочатку ознайомитись зі статтею Майка Веста Область застосування в JavaScript ( дзеркалі ). Це прекрасне, дружнє знайомство з концепціями thisта сферами застосування в JavaScript.

Як тільки ви почнете звикати this, правила насправді досить прості. Стандарт ECMAScript 5.1 визначає this:

§11.1.1this ключове слово

У thisключове слово має значення вартості ThisBinding поточного контексту виконання

ThisBinding - це те, що підтримує інтерпретатор JavaScript під час оцінки коду JavaScript, як спеціальний реєстр процесора, який містить посилання на об'єкт. Інтерпретатор оновлює ThisBinding кожного разу, коли встановлює контекст виконання в одному з лише трьох різних випадків:

1. Початковий глобальний контекст виконання

Це стосується коду JavaScript, який оцінюється на найвищому рівні, наприклад, безпосередньо тут <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

При оцінці коду в початковому контексті глобального виконання ThisBinding встановлюється в глобальний об'єкт window( §10.4.1.1 ).

Введення коду eval

  • … При прямому виклику в eval() ThisBinding залишається незмінним; це те саме значення, що і ThisBinding контексту виконання виклику ( §10.4.2 (2) (a)).

  • … Якщо не шляхом прямого виклику eval()
    ThisBinding встановлюється на глобальний об’єкт так, ніби виконується в початковому контексті глобального виконання ( §10.4.2 (1)).

§15.1.2.1.1 визначає, що таке прямий дзвінок eval(). В основному, eval(...)це прямий дзвінок, тоді як щось подібне (0, eval)(...)або var indirectEval = eval; indirectEval(...);є непрямим дзвінком eval(). Дивіться відповідь chuckj на (1, eval) ("це") проти eval ("це") у JavaScript? та детально ECMA-262-5 Дмитра Сошнікова. Глава 2. Суворий режим. бо коли ви можете використовувати непрямий eval()дзвінок.

Введення коду функції

Це відбувається під час виклику функції. Якщо функція викликається на об'єкті, такому як в obj.myMethod()або еквіваленті obj["myMethod"](), тоді це Прив'язка встановлюється до об'єкта ( objу прикладі; §13.2.1 ). У більшості інших випадків це Прив’язка встановлюється до глобального об'єкта ( §10.4.3 ).

Причина написання "у більшості інших випадків" полягає в тому, що існує вісім вбудованих функцій ECMAScript 5, які дозволяють вказати ThisBinding в списку аргументів. Ці спеціальні функції приймають так зване, thisArgяке стає ThisBinding при виклику функції ( §10.4.3 ).

Ці спеціальні вбудовані функції:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Що стосується Function.prototypeфункцій, вони викликаються на об’єкті функції, але замість встановлення ThisBinding для об'єкта функції, ThisBinding встановлюється в thisArg.

Що стосується Array.prototypeфункцій, даний callbackfnвиклик викликається в контексті виконання, де ThisBinding встановлюється, thisArgякщо він надається; інакше до глобального об’єкта.

Це правила для звичайного JavaScript. Коли ви починаєте використовувати бібліотеки JavaScript (наприклад, jQuery), ви можете виявити, що певні функції бібліотеки маніпулюють значенням this. Розробники цих бібліотек JavaScript роблять це, оскільки воно, як правило, підтримує найбільш поширені випадки використання, і користувачі бібліотеки зазвичай вважають цю поведінку більш зручною. Під час передачі функцій зворотного дзвінка, що посилаються thisна функції бібліотеки, вам слід звернутися до документації, щоб отримати гарантії щодо значення, яке thisвикликається функцією.

Якщо вам цікаво, як бібліотека JavaScript маніпулює значенням this, бібліотека просто використовує одну з вбудованих функцій JavaScript, яка приймає a thisArg. Ви також можете написати власну функцію, використовуючи функцію зворотного дзвінка, і thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Є особливий випадок, якого я ще не згадував. Конструюючи новий об'єкт через newоператора, інтерпретатор JavaScript створює новий, порожній об'єкт, встановлює деякі внутрішні властивості, а потім викликає функцію конструктора на новому об'єкті. Таким чином, коли функція викликається в контексті конструктора, значення this- це новий об'єкт, який інтерпретатор створив:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Функції стрілки

Функції стрілок (введені в ECMA6) змінюють сферу застосування this. Дивіться існуючий канонічний питання: Функція стрілки та декларація / вирази функції: чи вони еквівалентні / обмінні? для отримання додаткової інформації. Але коротше:

Функції стрілки не мають власного this.... прив'язки. Натомість ці ідентифікатори розв’язуються в лексичній області, як і будь-яка інша змінна. Це означає, що всередині функції стрілки, this... посилайтесь (-і) на значення thisу середовищі, в якій визначена функція стрілки.

Просто для розваги, перевіряйте своє розуміння на деяких прикладах

Щоб розкрити відповіді, наведіть курсор на світло-сірі поля.

  1. Яке значення thisпозначеного рядка? Чому?

    window - Позначена лінія оцінюється в початковому контексті глобального виконання.

    if (true) {
        // What is `this` here?
    }
  2. Яке значення thisпозначеного рядка при obj.staticFunction()виконанні? Чому?

    obj - При виклику функції на об'єкті ThisBinding встановлюється на об'єкт.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. Яке значення thisпозначеного рядка? Чому?

    window

    У цьому прикладі інтерпретатор JavaScript вводить код функції, але оскільки myFun/ obj.myMethodне викликається об'єктом, це встановлено window.

    Це відрізняється від Python, в якому звернення до методу ( obj.myMethod) створює пов'язаний об'єкт методу .

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. Яке значення thisпозначеного рядка? Чому?

    window

    Цей був хитрий. При оцінці коду eval, thisє obj. Однак у коді eval myFunне викликається об'єкт, тому для виклику встановлено ThisBinding window.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
  5. Яке значення thisпозначеного рядка? Чому?

    obj

    Рядок myFun.call(obj);викликає спеціальну вбудовану функцію Function.prototype.call(), яка приймає thisArgяк перший аргумент.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


6
@Ali: Вони посилаються на розділи в редакції 5.1 стандарту ECMAScript, ECMA-262 . Я надаю їх, щоб ви могли прочитати Стандарт за технічними деталями, якщо хочете.
Даніель Треббієн

1
Я думаю, що @supertonsky має рацію щодо №2 - якщо myFun () викликається з глобальної сфери, а не як метод на об'єкті, "це" буде глобальним об'єктом, тому фразування питання має значення. btw - Мені дуже подобається ідея використання миші для отримання відповіді на щось подібне.
користувач655489

2
Але, jsfiddle.net/H4LYm/2 показує , що setTimeoutприклад є thisз window(global).
Кевін Мередіт

2
походить від Python, можна було б уявити рівень фрустрації, який у мене був, коли я наткнувся на 3-й приклад .. smh
Marius Mucenicu

1
Цю відповідь, ймовірно, слід оновити, щоб відобразити реальність ES2020, навіть якщо зміни є лише термінологічними.
Бен Астон

156

The this ключових словах веде себе по- різному в JavaScript по порівнянні з іншими мовами. В об'єктно-орієнтованих мовах thisключове слово посилається на поточний екземпляр класу. У JavaScript значення thisвизначається контекстом виклику функції ( context.function()) і тим, де воно викликається.

1. При використанні в глобальному контексті

Коли ви використовуєте this в глобальному контексті, він пов'язаний з глобальним об'єктом ( windowу браузері)

document.write(this);  //[object Window]

Коли ви використовуєте this всередині функції, визначеної в глобальному контексті, thisвона все ще пов'язана з глобальним об'єктом, оскільки ця функція фактично зроблена методом глобального контексту.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Вище f1 робиться метод глобального об’єкта. Таким чином, ми можемо також назвати його на windowоб'єкті наступним чином:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. При використанні всередині об'єктного методу

Коли ви використовуєте thisключове слово всередині методу об'єкта,this прив'язується до "негайного" об'єкта, що обгороджує.

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Вище я поставив слово негайно у подвійних лапках. Слід зазначити, що якщо ви вкладете об'єкт всередину іншого об'єкта, то thisприв’язаний до безпосереднього батьків.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

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

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. При виклику функції без контексту

Коли ви використовуєте thisвнутрішню функцію, яка викликається без будь-якого контексту (тобто не на будь-якому об'єкті), вона пов'язана з глобальним об'єктом ( windowу браузері) (навіть якщо функція визначена всередині об'єкта).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Спробуйте все це з функціями

Ми також можемо спробувати вище точки з функціями. Однак є деякі відмінності.

  • Вище ми додавали членів до об'єктів, використовуючи буквене позначення об'єкта. Ми можемо додавати членів до функцій, використовуючи this. щоб їх вказати.
  • Буквене позначення об'єкта створює екземпляр об'єкта, який ми можемо використати негайно. За допомогою функції нам може знадобитися спочатку створити її екземпляр за допомогою newоператора.
  • Також в буквеному підході об'єкта ми можемо явно додати членів до вже визначеного об'єкта за допомогою оператора крапок. Це додається лише до конкретного примірника. Однак я додав змінну до прототипу функції, щоб вона відображалася у всіх екземплярах функції.

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

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. При використанні всередині функції конструктора .

Коли функція використовується як конструктор (тобто, коли вона викликається newключовим словом), thisвсередині функції функції вказується на новий об'єкт, який будується.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. При використанні всередині функції, визначеної в прототипі ланцюга

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

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Внутрішній виклик (), застосувати () та прив’язати () функції

  • Всі ці методи визначені на Function.prototype.
  • Ці методи дозволяють написати функцію один раз і викликати її в іншому контексті. Іншими словами, вони дозволяють вказати значення, thisяке буде використовуватися під час виконання функції. Вони також приймають будь-які параметри, які передаються в початкову функцію при її виклику.
  • fun.apply(obj1 [, argsArray])Встановлюється obj1як значення thisвсередині fun()і називає fun()передаючі елементи argsArrayяк його аргументи.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Встановлює obj1як значення thisвнутрішньої fun()та виклику fun()передачі arg1, arg2, arg3, ...як його аргументи.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Повертає посилання на функцію funз thisприв’язаною внутрішньою забавою obj1та параметрами, funприв'язаними до вказаних параметрів arg1, arg2, arg3,....
  • В даний час різниця між apply, callі bindмає бути , стало очевидним. applyдозволяє вказати аргументи, які функціонують як масив-подібний об'єкт, тобто об'єкт із числовим lengthвластивістю та відповідними невід'ємними цілими властивостями. Тоді як callдозволяє безпосередньо вказати аргументи функції. І те, applyі callвідразу викликає функцію у вказаному контексті та із вказаними аргументами. З іншого боку, bindпросто повертає функцію, пов'язану із заданим thisзначенням та аргументами. Ми можемо зафіксувати посилання на цю повернуту функцію, призначивши її змінній, а пізніше можемо викликати її будь-коли.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. thisвсередині обробників подій

  • Коли ви призначаєте функцію безпосередньо обробникам подій елемента, використання thisбезпосередньо функції обробки подій посилається на відповідний елемент. Таке пряме призначення функції може бути здійснено за допомогою addeventListenerметоду або за допомогою традиційних методів реєстрації подій, таких якonclick .
  • Аналогічно, коли ви використовуєте thisбезпосередньо всередині властивості події (наприклад,<button onclick="...this..." > ) елемента, воно посилається на елемент.
  • Однак використання thisопосередковано через іншу функцію, яку називають всередині функції поводження з подіями або властивістю події, вирішується на глобальний об'єктwindow .
  • Таке ж вище поведінка досягається, коли ми додаємо функцію до обробника подій, використовуючи метод моделі реєстрації подій Microsoft attachEvent. Замість того, щоб призначити функцію обробнику подій (і таким чином зробити метод функції елемента), він викликає функцію події (ефективно називаючи її в глобальному контексті).

Я рекомендую краще спробувати це в JSFiddle .

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. thisу функції стрілки ES6

У функції стрілки thisбуде поводитись як загальні змінні: вона успадковується зі своєї лексичної області. Функція this, де визначена функція стрілки, буде функцією стрілкиthis .

Отже, така ж поведінка, як:

(function(){}).bind(this)

Дивіться наступний код:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 

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

@RobG Хм може бути, але я виявив це на MDN : У цьому випадку значення thisвиклику не встановлюється. Оскільки код не знаходиться в суворому режимі, значення thismust завжди має бути об'єктом, тому воно за замовчуванням відповідає глобальному об'єкту. Насправді саме тому я думав, що ми можемо безпосередньо телефонувати window.f1(), так що кошти f1()вже приєднані до windowоб’єкта, я маю на увазі перед викликом. Я помиляюсь?
Mahesha999

Я коментував (можливо , не ясно) на вашому зв'язує установку цього з «функція насправді зробив метод глобального контексту», як ніби це свого роду називається window.fn, що це не так . це за замовчуванням для глобального об'єкта, оскільки в виклику не використовувалося базове посилання, а не через те, де визначена функція (тому це все ще встановлюється тим, як функція викликалася). Якщо ви явно викликати його з допомогою window.fn, то ви налаштовуєте це в вікно . Той самий результат, різний спосіб робити це. :-)
RobG

"вище я поставив слово негайно ..." ні, ви цього не зробили. Чи можете ви, будь ласка, переглянути це, щоб помилка була виправлена? Відповіді це здається семантичним, і тому я не можу продовжувати читати, поки помилка не буде виправлена ​​із-за страху дізнатися щось неправильне.
TylerH

@TylerH do Ctrl + F на цій сторінці у вашому браузері, щоб знайти рядок "негайний" (включаючи подвійні лапки) Я думаю, що це там, якщо я розумію, що ви неправильні
Mahesha999

64

JavaScript this

Просте виклик функції

Розглянемо наступну функцію:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

Зауважте, що ми виконуємо це у звичайному режимі, тобто суворий режим не використовується.

Під час запуску в браузері значення " thisзаписується як" window. Це тому, що windowє глобальною змінною в області веб-браузера.

Якщо ви запускаєте цей самий фрагмент коду в середовищі, як node.js, thisбуде посилатися на глобальну змінну у вашому додатку.

Тепер, якщо ми запустимо це в суворому режимі, додавши оператор "use strict";на початок декларації функції, thisбільше не буде посилатися на глобальну змінну в жодному з середовищ. Це робиться для уникнення плутанини в суворому режимі. thisв цьому випадку просто журнал undefined, тому що це є, він не визначений.

У наступних випадках ми побачимо, як маніпулювати значенням this.

Виклик функції на об'єкті

Існують різні способи зробити це. Якщо ви назвали нативні методи в JavaScript як, forEachі sliceви вже повинні знати, що thisзмінна в цьому випадку відноситься до того, Objectна яке ви викликали цю функцію (зауважте, що в javascript майже все є Object, включаючи Arrays і Functions). Візьмемо для прикладу наступний код.

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Якщо вміст Objectмістить властивість, яка містить а Function, властивість називається методом. Цей метод, коли його викликають, завжди матиме thisзмінну, встановлену наObject він пов'язаний. Це справедливо як для суворих, так і не суворих режимів.

Зауважте, що якщо метод зберігається (вірніше, скопіюється) в іншій змінній, посилання на thisбільше не зберігається в новій змінній. Наприклад:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation

Розглядаючи більш практичний сценарій:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

newключове слово

Розглянемо функцію конструктора в Javascript:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

Як це працює? Що ж, давайте подивимося, що станеться, коли ми використовуємо newключове слово.

  1. Виклик функції за допомогою newключового слова негайно ініціалізує ObjectтипPerson .
  2. Конструктор цього Objectмає свій конструктор Person. Також зверніть увагу, що typeof awalповернетьсяObject лише.
  3. Цьому новому Objectбуде призначений прототип Person.prototype. Це означає, що будь-який метод чи властивість у Personпрототипі будуть доступні для всіх примірників Person, у тому числіawal .
  4. Тепер функція Personвикликається; thisбудучи посиланням на щойно побудований об’єкт awal.

Досить прямо, так?

Зауважте, що в офіційній специфікації ECMAScript ніде не зазначено, що такі типи функцій є фактичними constructorфункціями. Вони просто нормальні функції, і newїх можна використовувати на будь-якій функції. Просто ми використовуємо їх як таких, і тому називаємо їх лише такими.

Виклик функцій у функціях: callіapply

Так, так як functions також є Objects(і фактично змінні першого класу в Javascript), навіть функції мають методи, які ... ну, самі функції.

Всі функції успадковуються від глобального Function, і два з його багатьох методів є callі apply, і обидва можуть бути використані для маніпулювання значенням thisфункції, за якою вони викликаються.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

Це типовий приклад використання call. В основному він приймає перший параметр і задає thisфункцію fooяк посилання на thisArg. Усі інші параметри, передані до call, передаються функції fooяк аргументи.
Тож вищевказаний код увійде {myObj: "is cool"}, [1, 2, 3]в консоль. Досить приємний спосіб змінити значенняthis будь-якої функції.

applyмайже такий же, як callприйняти, що він приймає лише два параметри: thisArgі масив, який містить аргументи, які потрібно передавати функції. Отже, вищезгаданий callвиклик можна перекласти applyтак:

foo.apply(thisArg, [1,2,3])

Зауважте, що callі applyможе перекрити значенняthis заданого викликом методу крапок, про який ми говорили у другій кулі. Досить просто :)

Представляючи…. bind !

bindє братом callі apply. Це також метод, успадкований усіма функціями від глобального Functionконструктора в Javascript. Різниця між bindі call/ applyполягає в тому, що і те, callі applyфактично буде викликати функцію. bind, З іншого боку, повертає нову функцію з thisArgі argumentsзаздалегідь заданими параметрами. Візьмемо приклад, щоб краще зрозуміти це:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

Бачите різницю між трьома? Це тонко, але вони використовуються по-різному. Як callі apply, bindтакож буде перевищувати вартістьthis задане викликом методу крапок.

Також зауважте, що жодна з цих трьох функцій не змінює вихідну функцію. callі applyповертав би значення зі свіжозбудованих функційbind поверне саму щойно побудовану функцію, готову до виклику.

Зайві речі, скопіюйте це

Іноді вам не подобається той факт, що thisзмінюється в області застосування, особливо вкладеної області. Погляньте на наступний приклад.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

У наведеному вище коді ми бачимо, що значення thisзмінилося з вкладеною областю, але ми хотіли, щоб значення було thisвід вихідної області. Таким чином , ми «скопійовано» thisв thatі використовується замість копіюванняthis . Розумний, так?

Індекс:

  1. Що тримається в this за замовчуванням?
  2. Що робити, якщо ми називаємо функцію методом із нотацією Object-dot?
  3. Що робити, якщо ми використовуємо new ключове слово?
  4. Як ми маніпулюємо thisз callі apply?
  5. Використання bind.
  6. Копіювання thisдля вирішення вкладених проблем.

47

"це" все стосується сфери застосування. Кожна функція має власну сферу, і оскільки все в JS є об'єктом, навіть функція може зберігати деякі значення в собі, використовуючи "це". OOP 101 вчить, що "це" застосовується лише до екземплярів об'єкта. Тому щоразу, коли функція виконує, новий "екземпляр" цієї функції має нове значення "цього".

Більшість людей плутаються, коли намагаються використовувати "це" всередині анонімних функцій закриття, таких як:

(функція (значення) {
    this.value = значення;
    $ ('. деякі елементи'). кожен (функція (elt) {
        elt.innerHTML = this.value; // Ой-ой!! можливо, невизначений
    });
}) (2);

Отже, тут, усередині кожного (), "це" не містить "значення", на яке ви очікуєте його (від

this.value = значення;
над ним). Отже, щоб подолати цю (не призначену для каламбуру) проблему, розробник міг:

(функція (значення) {
    var self = це; // невелика зміна
    self.value = значення;
    $ ('. деякі елементи'). кожен (функція (elt) {
        elt.innerHTML = self.value; // феу !! == 2
    });
}) (2);

Спробуй; вам почне подобатися ця схема програмування


6
"все в JS - це об'єкт" - це неправда, JavaScript також має примітивні значення, див. bclary.com/2004/11/07/#a-4.3.2
Marcel Korpel

6
Примітивні значення, схоже, мають деякі методи на собі, наприклад, String # substring (), Number # toString () тощо. Отже, можливо, не з тією ж номенклатурою, що ця стаття, вони дійсно поводяться так, ніби вони були об'єктами (вони весь прототип, тобто. String # substring () є насправді: String.prototype.substring = function () {...}). Будь ласка, виправте мене, якщо я помиляюся.
arunjitsingh

12
thisКлючове слово не має нічого спільного з розмахом. Також воно має значення також у функціях, які не є властивостями об’єктів.
Бергі

1
@ arunjitsingh - про це є дві школи думки. Мені подобається той, який говорить, що « все є об’єктом, але деякі можуть бути представлені примітивами для зручності ». ;-)
РобГ

9
thisНЕ ВСЕ щодо сфери застосування. Це ВСЕ про контекст виконання, який не є тим самим, що і сфера застосування. JavaScript має лексичний обсяг (тобто сфера дії визначається місцем розташування коду), але thisвизначається тим, як викликається функція, що містить його - не там, де ця функція.
Скотт Маркус

16

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

Як визначається значення this?

Ми використовуємо це аналогічно тому, як ми використовуємо займенники природними мовами, як англійська: "Джон біжить швидко, тому що намагається спіймати поїзд". Натомість ми могли б написати "... Джон намагається спіймати поїзд".

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this не присвоюється значення, поки об'єкт не викликає функцію, де він визначений. У глобальному масштабі всі глобальні змінні та функції визначаються на windowоб’єкті. Тому thisв глобальній функції посилається на (і має значення) глобальний windowоб'єкт.

Коли use strict, thisв глобальному , так і в анонімних функціях, які не пов'язані з яким - небудь об'єктом має значення undefined.

thisКлючове слово найбільш неправильно , коли: 1) запозичувати метод , який використовує this, 2) призначити метод , який використовує thisна змінний, 3) функції , яка використовує thisпередаються в якості функції зворотного виклику, і 4) thisвикористовуються всередині кришки - внутрішня функція. (2)

стіл

Що тримає майбутнє

Визначений у сценарії 6 ECMA , стрілочні функції приймають thisприв’язку із додаючої (функціональної чи глобальної) області.

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Хоча функції зі стрілками надають альтернативу використанню bind(), важливо відзначити, що вони по суті відключають традиційний thisмеханізм на користь більш широкого розуміння лексичного визначення. (1)


Список літератури:

  1. це та прототипи об'єктів , Кайл Сімпсон. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2RacU

16

thisу JavaScript завжди посилається на "власника" функції, яка виконується .

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

Так якби я зробив

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

thisпосилався б на об'єкт елемента. Але будьте обережні, багато людей роблять цю помилку.

<element onclick="someKindOfFunction()">

В останньому випадку ви просто посилаєтесь на функцію, а не передаєте її елементу. Тому thisбуде посилатися на об’єкт вікна.


15

Кожен контекст виконання в JavaScript має цей параметр, який встановлюється:

  1. Як викликається функція (в тому числі як об'єктний метод, використання виклику та застосування , використання нових )
  2. Використання зв'язування
  3. Лексично для функцій стрілок (вони приймають це у контексті їх зовнішнього виконання)
  4. Незалежно від того, чи знаходиться код у суворому чи не строгому режимі
  5. Чи був виклик коду за допомогою eval

Ви можете встановити значення цього за допомогою func.call, func.applyабо func.bind.

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

jQuery змушує це тривіальне змінити за допомогою jQuery.proxy.


9
Трохи правильніше сказати, що кожен виклик функції має область застосування. Іншими словами, thisу Javascript викликає заплутаність те , що це не властива сама функція, а артефакт способу виклику функції.
Pointy

@pointy спасибі що викликає найбільше плутанину щодо цього у js, це те, що у всіх використовуваних раніше мовах (c #, c ++), - цим не можна маніпулювати n завжди вказує на екземпляр об'єкта, тоді як у js це залежить і може бути змінено при виклику функції , використовуючи func.call, і func.bindт.д. - Sushil
Sushil

2
thisніяк НЕ посилатися на область дії функції. thisбуде посилатися на певний об'єкт (або можливо undefined), який, як ви вже сказали, можна змінити за допомогою .call()або .apply(). Функція , в сфері є ( по суті, при спрощеному) , яким змінним він має доступ, і це повністю залежить від того, де оголошується функція і не може бути змінено.
nnnnnn

@Pointy: "Трохи правильніше сказати, що кожен виклик функції має область". Ще правильніше сказати, що функції (і тепер блоки) мають область , а виклики функцій мають контекст . Область застосування визначає, що таке ідентифікатори, які можуть використовуватися кодом у цій області. Контекст визначає, до чого пов'язані ці ідентифікатори.
TJ Crowder

1
"Що б там не було, на це посилається" це "." Ні, thisі сфера застосування не мають нічого спільного між собою в ES5 та раніше (наприклад, коли ця відповідь була написана). У ES2015 (він же ES6) thisі сфера застосування пов'язані одним досить мінімальним способом функції стрілки wrt ( thisфункція стрілки успадковується від її вкладеної області), але thisніколи не посилається на область застосування.
TJ Crowder

10

Ось одне хороше джерело thisв JavaScript.

Ось підсумок:

  • глобальне це

    У браузері, в глобальному масштабі, this- це windowоб'єкт

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"

    У nodeвикористанні repl this- це головна область імен. Ви можете посилатися на це як global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true

    При nodeвиконанні зі сценарію, thisв глобальному масштабі починається як порожній об'єкт. Це не те саме, щоglobal

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
  • функціонувати це

За винятком випадків обробників подій DOM або коли thisArgнадається a (див. Далі), як у вузлі, так і в браузері, використовуючи thisфункцію, яка не викликається newпосиланнями на глобальну область застосування ...

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Якщо ви використовуєте use strict;, в такому випадку thisбудеundefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

При виконанні функції з newв thisбуде новим контекстом, він не буде посилатися на глобальному this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • прототип цього

Функції, які ви створюєте, стають об'єктами функцій. Вони автоматично отримують спеціальну prototypeвластивість, якій ви можете призначити значення. Коли ви створюєте екземпляр, зателефонувавши до своєї функції, newви отримаєте доступ до значень, призначених для prototypeвластивості. Ви отримуєте доступ до цих значень за допомогою this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Зазвичай помилково призначати масиви або об’єкти на prototype. Якщо ви хочете, щоб екземпляри мали кожен власний масив, створіть їх у функції, а не в прототипі.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • заперечують проти цього

Ви можете використовувати thisбудь-яку функцію об'єкта для позначення інших властивостей цього об'єкта. Це не те саме, що створений примірник new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • DOM подія це

У обробці подій HTML DOM - thisце завжди посилання на елемент DOM, до якого подія була приєднана

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

Якщо вам не bindконтекст

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML це

Всередині атрибутів HTML, в які можна помістити JavaScript, thisє посилання на елемент.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • eval це

Ви можете використовувати evalдля доступу this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • з цим

Ви можете використовувати withдля додавання thisдо поточної області для читання та запису до значень, thisне посилаючись на них thisпрямо.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery це

jQuery у багатьох місцях має thisпосилання на елемент DOM.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

9

Даніель, дивовижне пояснення! Кілька слів про це та хороший список thisпокажчика контексту виконання у випадку обробників подій.

Двома словами, thisу JavaScript вказується на об'єкт, від якого (або з контексту виконання якого) виконувалася поточна функція, і вона завжди доступна лише для читання, ви все одно не можете її встановити (така спроба закінчиться "Недійсна ліва рука" сторона в повідомленні '.

Для обробників подій: обробники вбудованих подій, такі як <element onclick="foo">, заміняють будь-які інші обробники, приєднані раніше та раніше, тому будьте обережні, і краще взагалі залишатися осторонь делегування подій в режимі inline. І дякую Зарі Алавердян, яка надихнула мене на цей список прикладів через суперечливу дискусію :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

9

Існує велика плутанина щодо того, як "це" ключове слово трактується в JavaScript. Сподіваємось, ця стаття закладе всіх тих, хто відпочиває раз і назавжди. І набагато більше. Будь ласка, уважно прочитайте всю статтю. Попереджуйте, що ця стаття довга.

Незалежно від контексту, в якому він використовується, "цей" завжди посилається на "поточний об'єкт" в JavaScript. Однак те, що "поточний об'єкт" відрізняється залежно від контексту . Контекст може бути точно 1 з 6 наступних:

  1. Глобальний (тобто за межами всіх функцій)
  2. Всередині прямого "Безмежної функції" виклику (тобто функції, яка не була пов'язана викликом functionName.bind )
  3. Всередині непрямої "Безмежної функції" Виклик через functionName.call та functionName.apply
  4. Всередині виклику "Обмежена функція" (тобто функція, яка була пов'язана викликом functionName.bind )
  5. Під час створення об’єктів через "нове"
  6. Всередині вбудованого обробника подій DOM

Далі описано кожен з цих контекстів по одному:

  1. Глобальний контекст (тобто поза всіма функціями):

    Поза всіма функціями (тобто в глобальному контексті) "поточний об'єкт" (а отже, значення "цього" ) завжди є "віконним" об'єктом для браузерів.

  2. Всередині прямого дзвінка "Без обмеженої функції" :

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

    function UserDefinedFunction(){
        alert(this)
        }

    він стає властивістю об’єкта вікна, як ніби ви його визначили як

    window.UserDefinedFunction=function(){
      alert(this)
    }  

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

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()

    У "жорсткому режимі" виклик / виклик функції безпосередньо через "UserDefinedFunction ()" буде «НЕ» автоматично викликати / посилатися на нього , як «window.UserDefinedFunction ()» .Hence «поточний об'єкт» (і значення «це» ) в «UserDefinedFunction» має бути визначено . Викликання цієї функції в "Суворому режимі" призведе до наступного

    UserDefinedFunction() // displays undefined

    Однак виклик його явно за допомогою об’єкта вікна призводить до наступного

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."

    Давайте подивимось на інший приклад. Будь ласка, подивіться на наступний код

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4

    У наведеному вище прикладі ми бачимо, що коли "UserDefinedFunction" викликався через o1 , "це" приймає значення o1 і значення його властивостей "a" і "b" . Значення "c" і "d" були показані не визначеними, як o1 не визначає цих властивостей

    Аналогічно, коли "UserDefinedFunction" викликали через o2 , "це" приймає значення o2, а значення його властивостей "c" і "d" відображаються. Значення «а» і «б» було показано , як визначено , як О2 робить не визначати ці властивості.

  3. Всередині непрямої "Безмежної функції" Виклик через functionName.call та functionName.apply :

    Коли "Незв'язана функція" викликається через functionName.call або functionName.apply , "поточний об'єкт" (і, отже, значення "цього" ) встановлюється значенням параметра "цей" (перший параметр), переданого для виклику / застосувати . Наступний код демонструє те саме.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined

    Наведений вище код чітко показує, що значення "це" для будь-якої "NON Bound Function" може бути змінено через виклик / застосувати . Крім того, якщо параметр "цей" явно не переданий для виклику / застосування , "поточний об'єкт" (і, отже, значення "цього") встановлюється на "вікно" в не суворому режимі і "невизначений" в суворому режимі.

  4. Всередині виклику "Обмежена функція" (тобто функція, яка була пов'язана викликом functionName.bind ):

    Зв'язана функція - це функція, чия "це" було зафіксовано. Наступний код продемонстрував, як "це" працює у разі зв'язаної функції

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function

    Як зазначено у наведеному вище коді, значення "це" для будь-якої "Обмеженої функції" НЕ МОЖЕ бути змінено через виклик / застосувати . Крім того, якщо параметр "цей" явно не переданий для прив'язки, "поточний об'єкт" (а отже, значення "цього" ) встановлюється на "вікно" в не суворому режимі і "невизначений" в суворому режимі. І ще одна річ. Прив’язка вже пов'язаної функції не змінює значення "цього" . Він залишається встановленим як значення, встановлене функцією першого прив'язки.

  5. Під час створення об’єктів через "нове" :

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

  6. Всередині вбудованого обробника подій DOM :

    Перегляньте наступний фрагмент HTML

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>

    The «Це» в наведеному вище приклади відносяться до елементу «Кнопки» та елементу «Сон» відповідно.

    У першому прикладі колір шрифту кнопки повинен бути встановлений на білий при натисканні на неї.

    У другому прикладі при натисканні на елемент "div" він повинен викликати функцію OnDivClick з його другим параметром, що посилається на натиснутий елемент div. Однак значення "цього" в OnDivClick НЕ БУДЕ посилатися на натиснутий елемент div . Він повинен бути встановлений як "об'єкт вікна" або "невизначений" у Не суворих та Строгих режимах відповідно (якщо OnDivClick - незв'язана функція ) або встановлюється заздалегідь заданим значенням " Прив'язка" (якщо OnDivClick є пов'язаною функцією )

Далі узагальнено всю статтю

  1. У глобальному контексті "цей" завжди посилається на об'єкт "вікно"

  2. Щоразу, коли функція викликається, вона викликається в контексті об'єкта ( "поточний об'єкт" ). Якщо поточний об’єкт не надано явно, то поточним об'єктом є "об'єкт вікна" в NON Strict Mode і "undefined" в Strict Mode за замовчуванням.

  3. Значення "цього" в немежовій функції - це посилання на об'єкт, у контексті якого викликається функція ( "поточний об'єкт" )

  4. Значення "цього" в немежовій функції може бути замінено за допомогою виклику та застосувати методи функції.

  5. Значення "це" фіксується для функції Bound і не може бути перекрито викликом та застосувати методи функції.

  6. Прив'язувальна і вже пов'язана функція не змінює значення "цього". Він залишається встановленим як значення, встановлене функцією першого прив'язки.

  7. Значення "цього" в конструкторі - це об'єкт, який створюється та ініціалізується

  8. Значення "цього" у вбудованому обробнику події DOM посилається на елемент, для якого задано обробник подій.


9

Напевно, найбільш детальною та всебічною статтею thisє наступна:

Ніжне пояснення ключового слова "це" в JavaScript

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


Якщо у вас виникли проблеми з ідентифікацією this, не запитуйте себе:

Звідки thisбереться ?

але дійсно запитати себе:

Як функція викликається ?

Для функції стрілки (особливий випадок прозорості контексту) запитайте себе:

Яке значення має , thisде функцію стрілки визначаються ?

Такий спосіб мислення правильний при роботі thisі позбавить вас від головного болю.


На додаток до посилань на ваш блог, можливо, ви могли б заглибитись трохи глибше у те, як задавання цих питань допомагає комусь зрозуміти thisключове слово?
Магнус Лінд Окслунд

7

Це найкраще пояснення, яке я бачив: Розумійте це JavaScripts із чіткістю

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

Існує чотири сценарії, де це може заплутати:

  1. Коли ми передаємо метод (який використовує це ) як аргумент, який буде використовуватися як функція зворотного виклику.
  2. Коли ми використовуємо внутрішню функцію (закриття). Важливо врахувати, що закриття не можуть отримати доступ до цієї змінної зовнішньої функції за допомогою цього ключового слова, оскільки ця змінна доступна лише самою функцією, а не внутрішніми функціями.
  3. Коли метод, який спирається на це , присвоюється змінній у різних контекстах, то в цьому випадку це посилання на інший об'єкт, ніж спочатку було призначено.
  4. Використовуючи це разом із прив’язкою, застосовують та методи виклику.

Він наводить приклади коду, пояснення та рішення, які, на мою думку, були дуже корисними.


6

У псевдокласичному плані, як багато лекцій викладають ключове слово "це", це об'єкт, створений класом або конструктором об'єктів. Кожен раз, коли новий клас будується з класу, уявіть, що під кришкою створюється та повертається локальний екземпляр об'єкта "цей". Я пам’ятаю, це вчили так:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;

5

thisє однією з неправильно зрозумілих концепцій JavaScript, оскільки вона поводиться мало інакше від місця до місця. Просто, thisвідноситься до "власника" функції, яку ми виконуємо в даний час .

thisдопомагає отримати поточний об'єкт (він же контекст виконання), з яким ми працюємо. Якщо ви розумієте , в який об'єкт поточна функція стає виконана, ви можете легко зрозуміти , які поточні thisIS

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Вище ми створюємо 3 змінних з такою ж назвою 'val'. Один у глобальному контексті, один всередині obj, а другий всередині внутрішньогометоду obj. JavaScript вирішує ідентифікатори в конкретному контексті, піднімаючись по ланцюжку області з локальної глобальної.


Мало місця, де thisїх можна розрізнити

Виклик методу об’єкта

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Коли line1 виконується, JavaScript встановлює контекст виконання (EC) для виклику функції, установка thisна об'єкт , на який посилається то , що було до останнього «» . тому в останньому рядку ви можете зрозуміти, що a()було виконано в глобальному контексті, який єwindow .

З Конструктором

this може використовуватися для позначення створеного об'єкта

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Коли Person()виконується нове , створюється абсолютно новий об’єкт. Personназивається і йогоthis встановлюється для посилання на цей новий об'єкт.

Виклик функції

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Якщо ми пропустимо newключове слово, whatIsThisстосується найбільш глобального контексту, який він може знайти (window )

З обробниками подій

Якщо обробник події вбудований, thisпосилається на глобальний об'єкт

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

При додаванні обробника подій через JavaScript thisпосилається на елемент DOM, який генерував подію.



5

Значення "цього" залежить від "контексту", в якому виконується функція. Контекстом може бути будь-який об'єкт або глобальний об'єкт, тобто вікно.

Таким чином, семантика "цього" відрізняється від традиційних мов ООП. І це викликає проблеми: 1. коли функція передається іншій змінній (швидше за все, зворотній дзвінок); і 2. коли закриття викликається методом-членом класу.

В обох випадках це встановлено у вікно.


3

Чи це могло б допомогти? (Більшість плутанини "це" у javascript відбувається через те, що воно, як правило, не пов'язане з вашим об'єктом, а з поточною областю виконання - це може бути не так, як воно працює, але мені завжди так здається - дивіться статтю для повного пояснення)


1
Було б краще сказати, що це пов'язано " з поточним контекстом виконання ". За винятком ES6 (чернетка) зміни, що за допомогою функцій стрілки, де це вирішено у зовнішньому контексті виконання.
RobG

3

Трохи інформації про це ключове слово

Давайте введемо thisключове слово на консоль у глобальному масштабі, без коду більше

console.log(this)

У Клієнт / Браузер this ключове слово - це глобальний об'єкт, який єwindow

console.log(this === window) // true

і

У сервери / вузла / Javascript this ключове слово також є глобальним об'єктом, який єmodule.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Майте на увазі, exportsце лише посилання наmodule.exports


1

це використання для Scope саме так

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

значення txt1 і txt є однаковим у наведеному вище прикладі $ (this) = $ ('# tbleName tbody tr') - те саме


1

Я по-іншому сприймаю this інші відповіді, які, сподіваюся, є корисними.

Один із способів дивитися на JavaScript - це бачити, що існує лише 1 спосіб викликати функцію 1 . це є

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

Завжди надається якась ціна objectForThis.

Все інше - синтаксичний цукор для functionObject.call

Отже, все інше можна описати, як це перекладається functionObject.call.

Якщо ви просто викликаєте функцію, то thisце "глобальний об'єкт", який у браузері є вікном

function foo() {
  console.log(this);
}

foo();  // this is the window object

Іншими словами,

foo();

було ефективно переведено на

foo.call(window);

Зауважте, що якщо ви будете використовувати суворий режим, то thisбудеundefined

'use strict';

function foo() {
  console.log(this);
}

foo();  // this is the window object

що означає

Іншими словами,

foo();

було ефективно переведено на

foo.call(undefined);

У JavaScript є такі оператори, як +і -та *. Є також оператор крапки, який є.

.Оператора при використанні функції праворуч і об'єкта зліва фактично означає «об'єкт в якості проходуthis до функції.

Приклад

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

Іншими словами bar.foo()перекладається наconst temp = bar.foo; temp.call(bar);

Зауважте, що не має значення, як створена функція (в основному ...). Все це дасть однакові результати

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

function otherFunction() { console.log(this) };

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

Знову ж таки, це лише синтаксичний цукор для

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

Ще одна зморшка - це прототип ланцюга. При використанні a.bJavaScript спочатку дивиться на об'єкт, на який посилається безпосередньо aвластивість b. Якщо bйого немає на об'єкті, JavaScript буде шукати прототип об'єкта для пошукуb .

Існують різні способи визначення прототипу об'єкта, найпоширенішим у 2019 році є classключове слово. Для цілей, thisхоча це не має значення. Важливо те, що це виглядає в об'єкті aдля власностіb якщо він знаходить властивість bна об'єкті або в його прототипі ланцюга, якщо в bкінцевому підсумку є функцією, то застосовуються ті самі правила, що і вище. Посилання на функції bбудуть викликатися за допомогою callметоду та передачіa як objectForЦе як показано у верхній частині цієї відповіді.

Тепер. Давайте уявимо, що ми робимо функцію, яка явно задається thisперед викликом іншої функції, а потім викликаємо її з .оператором (крапка)

function foo() {
  console.log(this);
}

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

Після перекладу на використання call, obj.bar()стаєconst temp = obj.bar; temp.call(obj); . Коли ми входимо в barфункцію, яку ми викликаємо, fooале ми явно переходимо в інший об'єкт для об’єкта. Це, коли ми приходимо до foo, thisце внутрішній об'єкт.

Це те, що bindі =>функції ефективно роблять. Вони більше синтаксичні цукру. Вони ефективно будують нову невидиму функцію точно так само, як barвище, що явно встановлює thisперед тим, як викликати будь-яку функцію, вказану. У разі прив’язки thisвстановлюється все, до чого ви переходите bind.

function foo() {
  console.log(this);
}

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

Зауважимо, що якби functionObject.bindне існувало, ми могли б зробити своє таким

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

і тоді ми могли б назвати це так

function foo() {
  console.log(this);
}

const bar = bind(foo, {name:'abc'});

Функції стрілки, =>оператор - синтаксичний цукор для зв’язування

const a = () => {console.log(this)};

те саме, що

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

Так само, як bindстворюється нова невидима функція, яка викликає дану функцію із обмеженим значенням для, objectForThisале на відміну від цьогоbind від об'єкта, який повинен бути пов'язаний, неявна. Це все, що thisстанеться, коли=> оператор.

Отже, як і правила, наведені вище

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()перекладається на те, const temp = obj.foo; temp.call(obj);що означає, що оператор стрілки всередині fooприв’яжеться objдо нової невидимої функції і поверне ту нову невидиму функцію, якій призначено b. b()буде працювати як завжди, b.call(window)або b.call(undefined)викликати нову невидиму функцію, яку fooстворили. Ця невидима функція ігнорує thisпередане в неї і проходитьobj як об'єктForTh` до функції стрілки.

Код вище перекладається на

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply - ще одна функція, схожа наcall

functionName.apply(objectForThis, arrayOfArgs);

Але щодо ES6 концептуально ви навіть можете це перекласти

functionName.call(objectForThis, ...arrayOfArgs);

0

Резюме thisJavascript:

  • Значення thisвизначається як функція викликається не там, де вона створена!
  • Зазвичай значення thisвизначається Об'єктом, який залишився від крапки. (window у глобальному просторі)
  • У слухачів подій значення this посилається на елемент DOM, на який покликано подію.
  • Коли у функції викликається newключове слово, значення thisпосилається на новостворений об'єкт
  • Ви можете маніпулювати значення thisз функціями: call, apply,bind

Приклад:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

Приклад слухачів подій:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

Приклад конструктора:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.


0

Щоб правильно зрозуміти "це", треба зрозуміти контекст, обсяг і різницю між ними.

Область застосування : javascript пов'язаний із видимістю змінних, обсяг досягається за рахунок використання функції. (Детальніше про сферу застосування)

Контекст : контекст пов'язаний з об'єктами. Він відноситься до об'єкта, до якого належить функція. Коли ви використовуєте ключове слово "це", воно посилається на об'єкт, якому належить функція. Наприклад, всередині функції, коли ви говорите: "this.accoutNumber", ви посилаєтесь на властивість "accoutNumber", що належить до об'єкта, якому належить ця функція.

Якщо об’єкт "myObj" має метод, який називається "getMyName", коли ключове слово JavaScript "це" використовується всередині "getMyName", воно посилається на "myObj". Якщо функція "getMyName" виконувалася в глобальному масштабі, то "це" стосується об'єкта вікна (за винятком суворого режиму).

Тепер давайте подивимось приклад:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

Код Runnig abobve у вихідному режимі браузера: введіть тут опис зображення

Згідно з результатом, який ви знаходитесь у контексті об’єкта вікна, також видно, що прототип вікна відноситься до Об'єкта.

Тепер спробуємо всередині функції:

    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>

Вихід:

введіть тут опис зображення Вихід той самий, тому що ми записали "цю" змінну в глобальній області і ми записали її у функціональній області, ми не змінили контекст. В обох випадках контекст був однаковий, пов’язаний із предметом вдови .

Тепер давайте створимо власний об’єкт. У javascript ви можете створити об’єкт багатьма способами.

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>

Вихід: введіть тут опис зображення

Отже, з наведеного вище прикладу ми з’ясували, що ключове слово 'це' посилається на новий контекст, пов’язаний з myObj, а myObject також має ланцюжок прототипу до Object.

Давайте кинемо ще один приклад:

<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>

вихід: має сенс правильно? (читати коментарі) введіть тут опис зображення

Якщо у вас виникли труднощі зрозуміти наведений вище приклад, спробуємо скористатися нашим власним зворотним дзвінком;

<script>
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2){
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            }
        }
        var callback2 = function (){
            console.log(this);
        }
        myObj.printName(function(data){
            console.log(data);
            console.log(this);
        }, callback2);
    </script>

вихід: введіть тут опис зображення

Тепер давайте розберемось у сфері застосування, самості, IIFE та ЦЕ як поводиться

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 

Вихід досить приголомшливий, правда? введіть тут опис зображення


-1

Проста відповідь:

Ключове слово "це" завжди залежить від контексту виклику. Вони згадуються нижче.

  1. ФУНКЦІЯ ПРИКЛАДАється НОВИМ КЛЮЧОВИМИ СЛОВОМ

    Якщо функція викликається ключовим словом NEW, ЦЕ буде прив’язане до новоствореного об'єкта.

    function Car(){
      this.name="BMW";
    }
    const myCar=new Car();
    myCar.name; // output "BMW"

    У вищесказаному це буде прив’язано до об’єкта 'myCar'

  2. ФУНКЦІЯ НАЗВАЄТЬСЯ ЕКСПЛІАТИЧНО, використовуючи методи дзвінка та застосувати методи

    У цьому випадку ЦЕ буде прив’язане до об'єкта, який явно передається функції.

    var obj1={"name":"bond"};
    function printMessage(msg){
        return msg+" "+this.name;
    }
    const message=printMessage.call(obj1,"my name is ");
    console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
  3. ЯКЩО ФУНКЦІЯ ПРИКЛАДАЄТЬСЯ З ОБ'ЄКТОМ БЕЗПЕЧНО, ЩО ЦЕ БУДЕ ПОВЕРНЕНО ДО ТЕМУ

    var obj1={
       "name":"bond",
        getName: function () {
                    return this.name;
                 }
    };
    const newname=obj1.getName();
    console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
  4. КОЛИ ФУНКЦІЯ НАЗВАЄТЬСЯ БЕЗ БУДЬ-ЯКОГО КОНТЕКСТУ, ЦЕ БУДЕ ПОВЕРНЕНО ДО ГЛОБАЛЬНОГО ОБ'ЄКТУ

    const util = {
       name: 'Utility',
       getName: function () {
                    return this.name;
    };
    
    const getName=util.getName;
    const newName=getName();
    console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE  BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
  5. У СТРИТИМУ РЕЖИМІ ЦЕ БУДЕ НЕ ВКАЗАНО

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.