Как работает ключевое слово "this"? - PullRequest
1210 голосов
/ 27 июня 2010

Я заметил, что нет четкого объяснения, что такое ключевое слово this и как оно правильно (и неправильно) используется в JavaScript на сайте переполнения стека.

Iбыли свидетелями какого-то очень странного поведения с ним и не смогли понять, почему это произошло.

Как работает this и когда его следует использовать?

Ответы [ 22 ]

9 голосов
/ 08 ноября 2016

Вероятно, самая подробная и полная статья о this выглядит следующим образом:

Нежное объяснение ключевого слова this в JavaScript

Идея this означает, что типы вызова функций имеют большое значение при установке значения this.


Если возникают проблемы с идентификацией this, , не задайте себе вопрос:

Где this взято из ?

но do Задайте себе вопрос:

Как вызывается функция ?

Для функции стрелки (особый случай прозрачности контекста) спросите себя:

Какое значение имеет this, где функция стрелки определена ?

Это правильное мышление при работе с this и избавит вас от головной боли.

7 голосов
/ 12 июля 2016

Это лучшее объяснение, которое я видел: Понимание скриптов Java это с ясностью

Ссылка this ВСЕГДА относится (и содержит значение) к объект - единственный объект - и он обычно используется внутри функции или метод, хотя он может быть использован вне функции в глобальном объем. Обратите внимание, что когда мы используем строгий режим, он содержит значение не определено в глобальных функциях и в анонимных функциях, которые не являются привязан к любому объекту.

Существует четыре сценария, в которых этот может сбить с толку:

  1. Когда мы передаем метод (который использует this ) в качестве аргумента для использования в качестве функции обратного вызова.
  2. Когда мы используем внутреннюю функцию (замыкание). Важно отметить, что замыкания не могут получить доступ к внешней переменной this с помощью ключевого слова this, поскольку переменная this доступна только самой функции, а не внутренним функциям.
  3. Когда метод, основанный на , этот назначается переменной в разных контекстах, и в этом случае этот ссылается на другой объект, чем первоначально предполагалось.
  4. При использовании это вместе с привязкой, применением и вызовом методов.

Он приводит примеры кода, объяснения и решения, которые, на мой взгляд, были очень полезны.

6 голосов
/ 17 сентября 2017

В псевдоклассических терминах, во многих лекциях учат ключевое слово «this», это как объект, созданный классом или конструктором объекта. Каждый раз, когда новый объект создается из класса, представьте, что под капотом создается и возвращается локальный экземпляр объекта this. Я помню, этому учили так:

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;
6 голосов
/ 28 июня 2010

Трудно получить хорошее представление о JS или написать в нем больше, чем что-либо тривиальное, если вы не понимаете его полностью.Вы не можете позволить себе просто окунуться :) Я думаю, что лучший способ начать работу с JS - это сначала посмотреть эти видео-лекции Дугласа Крокфорда - http://yuiblog.com/crockford/,, которые охватывают то и это, и все остальное о JS.

5 голосов
/ 03 июля 2017

Значение «this» зависит от «контекста», в котором выполняется функция. Контекст может быть любым объектом или глобальным объектом, то есть окном.

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

В обоих случаях это установлено в окно.

5 голосов
/ 09 августа 2014

this - это одна из неправильно понятых концепций в JavaScript, потому что она ведет себя немного по-разному в разных местах. Проще говоря, this относится к «владельцу» функции, которую мы сейчас выполняем .

this помогает получить текущий объект (a.k.a. контекст выполнения), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, что текущий this равен

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, а другой внутри innerMethod of 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

Когда выполняется строка 1, 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, который сгенерировал событие.


3 голосов
/ 25 июля 2018

Немного информации о этом ключевом слове

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

console.log(this)

In Клиент / браузер this - это глобальный объект, который window

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

и

В Сервер / Узел / Javascript runtime this Ключевое слово также является глобальным объектом, который module.exports

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

Имейте в виду, exports это просто ссылка на module.exports

3 голосов
/ 27 июня 2010

Как это поможет?(Большая путаница с «этим» в javascript связана с тем, что он, как правило, связан не с вашим объектом, а с текущей областью выполнения - это может быть не совсем так, как это работает, но мне всегда так кажется -см. статью для полного объяснения)

1 голос
/ 28 января 2019

У меня есть другое мнение о 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.b JavaScript сначала ищет объект, на который ссылается a, для свойства b. Если b не найден в объекте, тогда JavaScript будет искать в прототипе объекта, чтобы найти b.

Существуют различные способы определения прототипа объекта, наиболее распространенным в 2019 году является ключевое слово class. Для целей this хотя это не имеет значения. Важно то, что, когда он смотрит в объекте a свойство b, если он находит свойство b объекта или в цепочке его прототипов, если b становится функцией, то применяются те же правила, что и выше. Ссылка на функцию b будет вызываться с использованием метода call и передачей a как objectForThis, как показано в верхней части этого ответа.

Теперь. Давайте представим, что мы создаем функцию, которая явно устанавливает 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, но мы явно передаем другой объект для objectForThis, поэтому, когда мы достигаем foo this, этот внутренний объект.

Это то, что эффективно выполняют функции bind и =>. Они более синтаксические сахара. Они эффективно создают новую невидимую функцию в точности как bar выше, которая явно устанавливает this, прежде чем она вызовет любую указанную функцию. В случае bind 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 как objectForThis` в функцию стрелки.

Код выше переводится как

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);

1 apply - другая функция, аналогичная call

functionName.apply(objectForThis, arrayOfArgs);

Но с ES6 концептуально вы можете даже перевести это в

functionName.call(objectForThis, ...arrayOfArgs);
1 голос
/ 06 апреля 2016

это использование для 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') равно Same

...