- Ключевое слово this в javascript — учимся определять контекст на практике
- 1. Теория
- 2. Разбираем задачу
- Вместо заключения
- Function inside function javascript this
- # Call a Function inside another Function in JavaScript
- # Returning the inner function from the outer function
- # Inner function remembers variables declared in the outer function
- # Returning an object from the outer function
- JavaScript this
- 1. this Inside Global Scope
- 2. this Inside Function
- 3. this Inside Constructor Function
- 4. this Inside Object Method
- 5. this Inside Inner Function
- 6. this Inside Arrow Function
- 7. this Inside Function with Strict Mode
- Table of Contents
Ключевое слово this в javascript — учимся определять контекст на практике
По просьбам некоторых читателей решил написать топик про контекст в javascript. Новички javascript часто не понимают значение ключевого слова this в javascript. Данный топик будет интересен не только новичкам, а также тем, кто просто хочет освежить данный аспект в памяти. Посмотрите пример ниже. Если вы затрудняетесь ответить на вопрос «что будет выведено в логе» хотя бы в одном из пунктов или хотите просто посмотреть ответы — добро пожаловать под кат.
var f = function() < this.x = 5; (function() < this.x = 3; >)(); console.log(this.x); >; var obj = >; f(); new f(); obj.m(); new obj.m(); f.call(f); obj.m.call(f);
1. Теория
В отличие от многих других языков программирования ключевое слово this в javascript не привязывается к объекту, а зависит от контекста вызова. Для упрощения понимания будем рассматривать примеры применительно к браузеру, где глобальным объектом является window.
1.1. Простой вызов функции
В данном случае this внутри функции f равен глобальному объекту (например, в браузере это window, в Node.js — global).
Самовызывающиеся функции (self-invoking) работают по точно такому же принципу.
1.2. В конструкторе
function f() < this.x = 5; console.log(this === window); // false >var o = new f(); console.log(o.x === 5); // true
При вызове функции с использованием ключевого слова new функция выступает в роли конструктора, и в данном случе this указывает на создаваемый объект.
1.3. В методе объекта
var o = < f: function() < return this; >> console.log(o.f() === o); // true
Если функция запускается как свойство объекта, то в this будет ссылка на этот объект. При этом не имеет значения, откуда данная функция появилась в объекте, главное — как она вызывается, а именно какой объект стоит перед вызовом функции:
var o = < f: function() < return this; >> var o2 = ; console.log(o.f() === o);//true console.log(o2.f() === o2);//true
1.4. Методы apply, call
Методы apply и call позволяют задать контекст для выполняемой функции. Разница между apply и call — только в способе передачи параметров в функцию. Первый параметр обеих функций определяет контекст выполнения функции (то, чему будет равен this).
function f(a,b,c) < return a * b + c; >f.call(f, 1, 2, 3); // аргументы перечисляются через запятую; var args = [1,2,3]; f.apply(f, args); // // аргументы передаются в виде массива; // В обоих случаях вызовется функция f с аргументами a = 1, b = 2, c = 3;
function f() < >f.call(window); // this внутри функции f будет ссылаться на объект window f.call(f); //this внутри f будет ссылаться на f
function f() < console.log(this.toString()); // 123 >f.call(123); // this внутри функции f будет ссылаться на объект Number со значением 123
2. Разбираем задачу
Применим полученные знания к приведенной в начале топика задаче. Опять же для упрощения будем рассматривать примеры применительно к браузеру, где глобальным объектом является window.
2.1. f()
var f = function() < // Функция f вызывается с помощью простого вызова - f(), // поэтому this ссылается на глобальный объект this.x = 5; // window.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this также ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(window.x) >;
2.2. new f();
var f = function() < // Функция f вызывается с использованием ключевого слова new, // поэтому this ссылается на создаваемый объект (обозначим его как object) this.x = 5; // object.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(object.x) >;
2.3. obj.m();
2.4. new obj.m();
2.5. f.call(f);
var f = function() < // Функция f вызывается с помощью метода call // первым параметром в call указана сама функция (точнее объект) f, поэтому // поэтому this ссылается на f this.x = 5; // f.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(f.x) >;
2.6. obj.m.call(f);
Внимание: Если данный пример рассматривать отдельно от остальных, то в логе будет не 5, а undefined. Попробуйте внимательно разобрать пример и объяснить поведение
var f = function() < this.x = 5; (function() < this.x = 3; >)(); console.log(this.x); >; var obj = >; obj.m.call(f);
Вместо заключения
В статье я постарался описать, как работает ключевое слово this в javascript. В ближайшее время я скорее всего напишу статью, в которой описывается для чего нужно знать эти тонкости (например, jQuery.proxy)
P.S. Если вы заметили ошибки/неточности или хотите что-то уточнить/добавить — напишите в ЛС, поправлю.
Function inside function javascript this
Last updated: Jan 8, 2023
Reading time · 3 min
# Call a Function inside another Function in JavaScript
To call a function inside another function, define the inner function inside the outer function and invoke it.
When using the function keyword, the function gets hoisted to the top of the scope and can be called from anywhere inside the outer function.
Copied!function outerFunc(a, b) function innerFunc(a, b) return a + b; > const result = innerFunc(a, b); return result; > console.log(outerFunc(10, 10)); // 👉️ 20 console.log(outerFunc(10, 20)); // 👉️ 30
The following example shows how we can call the inner function before it is declared.
This is because of how hoisting works in JavaScript.
Copied!function outerFunc() const num1 = 5; const num2 = 10; // 👇️ call inner function before it's declared const result = innerFunc(); function innerFunc() return num1 + num2; > return result; > console.log(outerFunc()); // 👉️ 15
This only works for functions declared using the function keyword (not for arrow functions).
You can imagine that the declaration of the function gets hoisted to the top of the scope, so it can be called from anywhere in the scope.
# Returning the inner function from the outer function
An alternative approach is to return the inner function from the outer one.
Copied!function outerFunc() function innerFunc(a, b) return a + b; > return innerFunc; > const innerFunc = outerFunc(); console.log(innerFunc(2, 3)); // 👉️ 5 console.log(innerFunc(3, 3)); // 👉️ 6
Notice that we didn’t use parentheses () to invoke the inner function inside the outer one.
We returned the function without invoking it. In other words, we returned a reference to the inner function, not the result of calling it.
This allows us to invoke the inner function as many times as necessary, passing it different arguments every time.
# Inner function remembers variables declared in the outer function
What’s most useful in this scenario is that the inner function remembers the variables declared in the outer function between invocations.
Copied!function outerFunc() const z = 100; function innerFunc(a, b) return a + b + z; > return innerFunc; > const innerFunc = outerFunc(); console.log(innerFunc(2, 3)); // 👉️ 105 console.log(innerFunc(3, 3)); // 👉️ 106
Notice that the inner function remembers the value of the z variable between invocations.
This concept is called a closure in JavaScript.
The inner function gets bundled with references to its surrounding state.
This means that the inner function has access to the variables declared inside of the outer function’s scope at any time.
This is useful in many different scenarios. For example, you could pass a parameter to the outer function that it will remember for any of the inner function calls.
Copied!function outerFunc(a) function innerFunc(b, c) return a + b + c; > return innerFunc; > const innerFunc = outerFunc(10); console.log(innerFunc(1, 1)); // 12 console.log(innerFunc(1, 2)); // 13
We passed 10 as a parameter to the outer function and stored the result in a variable.
The innerFunc variable stores a reference to the innerFunc function where the a variable points to a value of 10 .
Now we can omit 10 from the parameters when calling the inner function.
# Returning an object from the outer function
You can also return an object from the outer function.
Copied!function outerFunc() function innerFunc(a, b) return a + b; > return innerFunc>; > const outer = outerFunc(); console.log(outer.innerFunc(10, 10)); // 20 console.log(outer.innerFunc(20, 15)); // 35
The object contains a single property — the inner function.
You can call the inner function by accessing the property on the object.
I’ve written a detailed article on how to call a function in an object.
I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
JavaScript this
In JavaScript, this keyword refers to the object where it is called.
1. this Inside Global Scope
When this is used alone, this refers to the global object ( window object in browsers). For example,
let a = this; console.log(a); // Window <> this.name = 'Sarah'; console.log(window.name); // Sarah
Here, this.name is the same as window.name .
2. this Inside Function
When this is used in a function, this refers to the global object ( window object in browsers). For example,
function greet() < // this inside function // this refers to the global object console.log(this); >greet(); // Window <>
3. this Inside Constructor Function
In JavaScript, constructor functions are used to create objects. When a function is used as a constructor function, this refers to the object inside which it is used. For example,
function Person() < this.name = 'Jack'; console.log(this); >let person1 = new Person(); console.log(person1.name);
Here, this refers to the person1 object. That’s why, person1.name gives us Jack .
Note: When this is used with ES6 classes, it refers to the object inside which it is used (similar to constructor functions).
4. this Inside Object Method
When this is used inside an object’s method, this refers to the object it lies within. For example,
const person = < name : 'Jack', age: 25, // this inside method // this refers to the object itself greet() < console.log(this); console.log(this.name); >> person.greet();
In the above example, this refers to the person object.
5. this Inside Inner Function
When you access this inside an inner function (inside a method), this refers to the global object. For example,
const person = < name : 'Jack', age: 25, // this inside method // this refers to the object itself greet() < console.log(this); // console.log(this.age); // 25 // inner function function innerFunc() < // this refers to the global object console.log(this); // Window < . >console.log(this.age); // undefined > innerFunc(); > > person.greet();
Here, this inside innerFunc() refers to the global object because innerFunc() is inside a method.
However, this.age outside innerFunc() refers to the person object.
6. this Inside Arrow Function
Inside the arrow function, this refers to the parent scope. For example,
const greet = () => < console.log(this); >greet(); // Window
Arrow functions do not have their own this . When you use this inside an arrow function, this refers to its parent scope object. For example,
const greet = < name: 'Jack', // method sayHi () < let hi = () =>console.log(this.name); hi(); > > greet.sayHi(); // Jack
Here, this.name inside the hi() function refers to the greet object.
You can also use the arrow function to solve the issue of having undefined when using a function inside a method (as seen in Example 5). For example,
const person = < name : 'Jack', age: 25, // this inside method // this refers to the object itself greet() < console.log(this); console.log(this.age); // inner function let innerFunc = () => < // this refers to the global object console.log(this); console.log(this.age); >innerFunc(); > > person.greet();
Here, innerFunc() is defined using the arrow function. It takes this from its parent scope. Hence, this.age gives 25.
When the arrow function is used with this , it refers to the outer scope.
7. this Inside Function with Strict Mode
When this is used in a function with strict mode, this is undefined . For example,
'use strict'; this.name = 'Jack'; function greet() < // this refers to undefined console.log(this); >greet(); // undefined
Note: When using this inside a function with strict mode, you can use JavaScript Function call().
'use strict'; this.name = 'Jack'; function greet() < console.log(this.name); >greet.call(this); // Jack
When you pass this with the call() function, greet() is treated as the method of the this object (global object in this case).