this

Контекст исполнения

Жигалов Сергей

В прошлой лекции

  • Функции. Аргументы. arguments

В прошлой лекции

  • Функции. Аргументы. arguments
  • Объявление функций

Объявление функции


// function declaration
function add(a, b) {
    return a + b;
}
        

// function expression
var add = function (a, b) {
    return a + b;
}
        

В прошлой лекции

  • Функции. Аргументы. arguments
  • Объявление функций
  • Область видимости

Область видимости


function greet() {
    var text = 'Привет';
    text; // 'Привет'
}

text;   // ReferenceError:
        //    text is not defined

┌{ greet }
├─┬{ text }
│ │
│ │
│
│
│
│
        

В прошлой лекции

  • Функции. Аргументы. arguments
  • Объявление функций
  • Область видимости
  • Всплытие переменных

В прошлой лекции

  • Функции. Аргументы. arguments
  • Объявление функций
  • Область видимости
  • Всплытие переменных
  • Замыкание

Замыкание


function makeCounter() {
    var currentCount = 0;

    return function () {
        return currentCount++;
    };
}

┌{ makeCounter } // 1
├─┬{ currentCount } // 2
│ │
│ │
│ ├─┬{ } // 3
│ │ │
│ │
│
        

this

this C#


class User
{
    private int age = 24;

    public void ShowAge()
    {
        Console.WriteLine(this.age);
    }
}

static void Main()
{
    User mike = new User();

    mike.ShowAge(); // 24
}
        

this Java


public class User {
    private int age = 24;

    public void showAge() {
        System.out.println(this.age);
    }
}

public static void main(String []args){
    User mike = new User();

    mike.showAge();
}
        

Свойства this

  • ключевое слово
  • указывает на текущий объект
  • нельзя перезаписать

this JavaScript


function User () {
    return {
        age: 24,

        showAge: function () {
            console.log(this.age);
        }
    }
}

var mike = new User();

mike.showAge(); // 24
        

Свойства this

  • ключевое слово
  • указывает на текущий объект
  • нельзя перезаписать
  • можно использовать за пределом объекта*

this за пределом объекта


this.innerWidth; // 1280
        

this.process.version; // v7.0.0
        

Контекст исполнения


function sum(a, b) {
    return a + b;
}

sum(1, 2); 

┌{ sum } // 1
├─┬{ a, b } // 2
│ │
│ │
│
│
        

function sum(a, b) {
    return a + b;
}

sum(1, 2); 

┌{ lE: { sum }            }
├─┬{ lE: { a, b }            }
│ │
│ │
│
│
        

function sum(a, b) {
    return a + b;
}

sum(1, 2); 

┌{ lE: { sum }, this: ??? }
├─┬{ lE: { a, b }, this: ??? }
│ │
│ │
│
│
        

Значение this зависит от:

  • I. Типа участка кода
  • II. Как мы попали на этот участок
  • III. Режима работы интерпретатора

I. Тип участка кода

I. Тип участка кода. Глобальный


this.innerWidth;   // 1280
        

window.innerWidth; // 1280
        

innerWidth;        // 1280
        

I. Тип участка кода. Глобальный


this.process.version;   // "v7.0.0"
        

global.process.version; // "v7.0.0"
        

process.version;        // "v7.0.0"
        

I. Тип участка кода. Глобальный


console.log('Hello!');
        

global.console.log('Hello!');
        

this.console.log('Hello!');
        

I. Тип участка кода. Глобальный


this === global; // true
        

I. Тип участка кода. Node.js модуль


// year-2016.js

module.exports.days = 366;
        

this.isLeapYear = true;
        

I. Тип участка кода. Node.js модуль


// index.js

var year2016 = require('./year-2016');

year2016.days; // 366;
year2016.isLeapYear; // true;
        

II. Как попали на участок кода. Простой вызов


function getSelf() {
    return this;
}

getSelf(); // global
        

II. Как попали на участок кода. Простой вызов

// year-2016.js

module.exports.days = 366;

function getSelf() {
    return this;
}

        

II. Как попали на участок кода. Простой вызов


// year-2016.js

module.exports.days = 366;

function getSelf() {
    return this;
}

getSelf(); // { days: 366 }

II. Как попали на участок кода. Метод объекта

var block = {
    innerHeight: 300,

    getHeight: function () {
        return this.innerHeight;
    }
}

        




???.innerHeight;



        

II. Как попали на участок кода. Метод объекта

var block = {
    innerHeight: 300,

    getHeight: function () {
        return this.innerHeight;
    }
}

block.getHeight(); // 300




block.innerHeight;



        

II. Как попали на участок кода. Метод объекта

var block = {
    innerHeight: 300,

    getHeight: function () {
        return this.innerHeight;
    }
}

var getHeight = block.getHeight;
        




???.innerHeight;




        

II. Как попали на участок кода. Метод объекта

var block = {
    innerHeight: 300,

    getHeight: function () {
        return this.innerHeight;
    }
}

var getHeight = block.getHeight;
getHeight(); // 1280




window.innerHeight;




        

Заимствование метода

call

Метод call() вызывает функцию с указанным значением this и индивидуально предоставленными аргументами.
Function.prototype.call() - JavaScript | MDN

fun.call(thisArg, arg1, arg2, ...);
        

II. Как попали на участок кода. Заимствование метода

var mike = {
    age: 24,

    getAge: function () {
        return this.age;
    }
}

var anna = {
    age: 21
}

        




???.age;







        

II. Как попали на участок кода. Заимствование метода

var mike = {
    age: 24,

    getAge: function () {
        return this.age;
    }
}

var anna = {
    age: 21
}

mike.getAge.call(anna); // 21




anna.age;







        

II. Как попали на участок кода. Заимствование метода


function func() {
  var args = Array.prototype.slice.call(arguments);
}
        
Метод apply() вызывает функцию с указанным значением this и аргументами, предоставленными в виде массива.
Function.prototype.apply() - JavaScript | MDN

fun.apply(thisArg, [arg1, arg2]);
        

apply


Math.min(4, 7, 2, 9); // 2
        

var arr = [4, 7, 2, 9];
Math.min(arr); // NaN
        

Math.min.apply(Math, arr); // 2
        

Math.min.apply(null, arr); // 2
        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        });
    }
}







???.items
???.name




        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        });
    }
}

person.showItems();





person.items
???.name




        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        });
    }
}

person.showItems();





person.items
global.name




        

🍅 Результат


'undefined has keys'
'undefined has phone'
'undefined has banana'
        

II. Как попали на участок кода. Callback


var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],
    showItems: function () {
        var _this = this;
        return this.items.map(function (item) {
            return _this.name + ' has ' + item;
        });
    }
}

person.showItems();
        

┌{ person }
│
│
│
├─┬{ _this }
│ │
│ │
│ ├─┬{ item }
│ │ │
│ │ │
│ │
│
│
│
        

Замыкание!

🍏 Результат


'Sergey has keys'
'Sergey has phone'
'Sergey has banana'
        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        }, this);
    }
}







???.items
???.name




        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        }, this);
    }
}

person.showItems();





person.items
person.name




        
Метод bind() создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение. <...>
Function.prototype.bind() - JavaScript | MDN

fun.bind(thisArg, arg1, arg2, ...);
        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        }.bind(this));
    }
}







???.items
???.name




        

II. Как попали на участок кода. Callback

var person = {
    name: 'Sergey',
    items: ['keys', 'phone', 'banana'],

    showItems: function () {
        return this.items.map(function (item) {
            return this.name + ' has ' + item;
        }.bind(this));
    }
}

person.showItems();





person.items
person.name




        

myBind


Function.prototype.myBind = function(_this) {
    var fn = this;
    var args = [].slice.call(arguments, 1);

    return function () {
       var curArgs = [].slice.call(arguments);

       return fn.apply(_this, args.concat(curArgs));
    };
};
        

Частичное применение


Math.pow(2, 3);  // 8
Math.pow(2, 10); // 1024
        

var binPow = Math.pow.bind(null, 2);
        

binPow(3);  // 8
binPow(10); // 1024
        

II. Как попали на участок кода. Конструктор

function User () {
    return {
        age: 24,

        showAge: function () {
            console.log(this.age);
        }
    }
}









???.age






        

II. Как попали на участок кода. Конструктор

function User () {
    return {
        age: 24,

        showAge: function () {
            console.log(this.age);
        }
    }
}

var mike = new User();
mike.showAge(); // 24





mike.age






        

Строгий режим

Строгий режим


'use strict';

function sum(a, b) {
    return a + b;
}
        

Строгий режим


function sum(a, b) {
    'use strict';

    return a + b;
}
        

Строгий режим


function func() {
    var eval = 42; // OK
}

function strictFunc() {
    'use strict';

    var eval = 42; // SyntaxError
}
        

Строгий режим


function func() {
    randomNumber = 4; // OK
}

function strictFunc() {
    'use strict';

    randomNumber = 4; // ReferenceError
}
        

III. Режим работы интерпретатора. Режим совместимости


function getSelf() {
    return this;
}

getSelf(); // global
        

III. Режим работы интерпретатора. Строгий режим


function getSelf() {
    'use strict';

    return this;
}

getSelf(); // undefined
        

eval

eval


var temperature = 12;

eval('temperature + 5'); // 17
        

eval

var person = {
    name: 'Sergey',

    showName: function () {
        return eval('this.name');
    }
}






???.name



        

eval

var person = {
    name: 'Sergey',

    showName: function () {
        return eval('this.name');
    }
}

person.showName(); // Sergey




person.name



        

eval

var person = {
    name: 'Sergey',

    showName: function () {
        var evil = eval;

        return evil('this.name');
    }
}








???.name



        

eval

var person = {
    name: 'Sergey',

    showName: function () {
        var evil = eval;

        return evil('this.name');
    }
}

person.showName(); // ''






general.name



        

Сегодня

  • Контекст исполнения
  • this
    • Определяется в момент интерпретации
    • Тип участка кода
    • Как мы на него попали
    • Режим интерпретатора