this
в функциях относится к тому, как вызывается функция. Хорошо, а как можно вызвать обычную функцию? Мы увидим это ниже. На это также влияют объекты, классы и стрелочные функции или обычные функции.
Я также расскажу о классах, объектах и стрелочных функциях.
Вызов функций:
Функции можно вызывать как функцию, как метод (функцию в объекте), с помощью new
и с помощью apply/call/bind.
Как функция:
function hey (){ console.log(this); } hey(); //prints the global this (window or globalThis in Node) //If the code is set to use strict, then this will be undefined.
Как метод (внутри объектов):
let obj = { prop1: "hello", prop2: "bye", prop3: function (myargs) { console.log(this); console.log(arguments); } } obj.prop3("I am Argument"); //the this now refers to the object itself. { prop1: 'hello', prop2: 'bye', prop3: [Function: prop3] } [Arguments] { '0': 'I am Argument' }
Как конструктор:
Когда функция используется в качестве конструктора, ее this
является одним из создаваемых объектов.
Во-первых, давайте посмотрим на this
обычной функции, которая получает this
изменение в коде.
//call function regularly function regF(){ this.a = "hey"; console.log("this calling function regularly"); console.log(this); } regF(); //displays //this calling function regularly //Object [global] { // global: [Circular], // … // a: ‘hey’, //...
Теперь у нас есть та же функция, но мы будем использовать ее как конструктор.
//use function as constructor but don't change anything function regF(){ this.a = "hey"; console.log("this calling function regularly"); console.log(this); } let obj1 = new regF(); console.log(obj1); //displays //this calling function regularly //regF { a: 'hey' } //regF { a: 'hey' }
Затем
//use new but now change the value of a. function regF(){ this.a = "hey"; console.log("this calling function regularly"); console.log(this); } let obj1 = new regF(); obj1.a = "Not so hey anymore"; console.log(obj1); //displays this calling function regularly regF { a: 'hey' } regF { a: 'Not so hey anymore' }
Теперь функция устанавливает это, но потом возвращает что-то другое.
function regF(){ this.a = "hey"; return {a: "hey hey hey"}; } let obj3 = new regF(); console.log(obj3); //displays { a: ‘hey hey hey’ }
Что бы мы ни установили в функции, используемой в качестве конструктора, это не будет иметь значения, потому что важно то, что мы вернем.
Как вызвать/применить/привязать:
const obj = { a: 'Custom' }; var a = 'Global'; function whatsThis() { console.log(this); } whatsThis(); // the global this whatsThis.call(obj); //{ a: 'Custom' } the one from the obj
С помощью bind мы можем привязаться к новому объекту только один раз:
function f() { console.log(this); } const g = f.bind({ a: 'bind 1' }); g();//shows bind 1
Если мы создадим другую функцию из этой и попытаемся привязаться к чему-то другому:
// bind only works once!, const h = g.bind({ a: 'bind 2 ' }); h(); // still shows bind 1
Теперь, если мы создадим объект, который содержит элемент, а также ранее созданные функции:
function f() { console.log(this); } const g = f.bind({ a: 'bind 1' }); const h = g.bind({ a: 'bind 2 ' }); const o = { a: 37, f, g, h }; o.f(); //will show the for the object: { a: 37, f: [Function: f], g: [Function: bound f], h: [Function: bound bound f] }
Если мы вызовем функцию g из объекта, мы получим исходную привязку:
function f() { console.log(this); } const g = f.bind({ a: 'bind 1' }); const h = g.bind({ a: 'bind 2 ' }); const o = { a: 37, f, g, h }; o.g(); // { a: 'bind 1' }, not the 37 //if we had done const o = { b: 37, f, g, h }; //we would still get { a: 'bind 1' } //o.h() will also have { a: 'bind 1' }
Это в классах
Классы — это функции под капотом, но не все точно так же.
В конструкторе класса это обычный объект, и к его прототипу добавляются любые НЕстатические методы. Статические методы не являются свойствами this
. Они являются свойствами самого класса.
class Example { constructor() { const proto = Object.getPrototypeOf(this); console.log(this); console.log(Object.getOwnPropertyNames(proto)); } first(){} second(){} static third(){} } new Example(); //display //Example{} //['constructor', 'first', 'second']
Конструкторы производных классов по умолчанию не получают this
binding. Мы можем позвонить super()
мы можем получить это. Вызов this
до вызова super()
вызовет ошибку. Некоторые сценарии:
Учитывая эту базу для всех примеров:
class Base { prop1 = "prop1 in base"; }
У нас может быть производный класс без конструктора, и все будет в порядке.
class Derived1NoConst extends Base {} console.log(new Derived1NoConst()); //Derived1NoConst { prop1: 'prop1 in base' }
Теперь у нас есть этот класс без конструктора, но возвращающий объект, все будет в порядке:
class Derived2ConstAndReturnsObj extends Base { constructor() { return {a: 5}; } } console.log(new Derived2ConstAndReturnsObj()); //{ a: 5 }
Теперь у нас есть класс, который ИМЕЕТ конструктор, НО НЕ возвращает объект. Не в порядке.
class Derived3ConsNoRet extends Base { constructor() {} } console.log(new Derived3ConsNoRet()); //return error ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
Чтобы исправить вышеперечисленное, вызовите super:
class Derived3ConsNoRet extends Base { constructor() { super() } } console.log(new Derived3ConsNoRet()); //Derived3ConsNoRet { prop1: 'prop1 in base' }
Стрелочные функции
Этот пример будет иметь this
, что и его «родитель», который является глобальным.
console.log(this);//{} const theThis = this; //the function just returns this const foo = () => this; console.log(foo()); //{} console.log( foo() === theThis);//true
если мы поместим эту функцию в объект, у нас все еще будет это.
const theThis = this; const foo = () => this; const obj = { func: foo }; console.log(obj.func() === theThis); // true
Посмотрите на этот код. У меня есть функция, которая изменяет свой this
, чтобы иметь пару свойств, одно из которых является функцией стрелки. Функция стрелки имеет this родительской функции.
const globalThis = this; function regFunc(){ let funcThis = this; this.a = "hello"; console.log(this); //regFunc { a: 'hello' } console.log(this === funcThis); //true console.log(this === globalThis);//false this.myf = ( () => { console.log(this);//regFunc{a:'hello',myf: [Function]} console.log(this === funcThis);//true console.log(this === globalThis);//false }) } //regFunc() var a = new regFunc(); a.myf()
Аналогично, если я сделаю это, за исключением того, что this
внутри функции не включает myf: [Function]
const globalThis = this; function regFunc(){ let funcThis = this; this.a = "hello"; console.log(this); //regFunc { a: 'hello' } console.log(this === funcThis); //true console.log(this === globalThis);//false return ( () => { console.log(this);//regFunc { a: 'hello' } console.log(this === funcThis);//true console.log(this === globalThis);//false }) } //regFunc() var a = new regFunc(); a()
Как обработчик событий
this
устанавливается на элемент, на котором находится прослушиватель. В некоторых браузерах это будет работать динамически только при использовании addEventListener. Вот почему вы можете делать вещи this.style.color = «red».
Это то, что у меня есть на данный момент. Я уверен, что снова забуду, так что буду возвращаться к этому снова и снова.