Обязательство "это" - PullRequest
1 голос
/ 15 мая 2019

Я изучаю, как значение «this» связывается в JavaScript. В следующем примере правильно ли говорить, что «this» связывается с методом getFriends () вместо объекта «details», что является причиной this.name = "» вместо this.name = "Joe"?

const details = {
    name: 'Joe',
    friends: [ 'Bob', 'Alex' ],
    getFriends: function() {
        this.friends.forEach( function( friend ) {
            console.log( this.name + " is friends with " + friend );
        } );
    }
};

details.getFriends();

// Output:
// is friends with Bob
// is friends with Alex

Как я понял из моих исследований, "это" не связывает один уровень выше в родительской области, верно? Это одно из преимуществ использования функций стрелок, которые связывают «this» с родительской областью.

Ответы [ 3 ]

3 голосов
/ 15 мая 2019

Нет, когда вы запускаете код таким образом this указывает на объект глобального окна. Вы можете console.log значение this. Чтобы проверить это, вы также можете поместить ключ my_name в окно (не используйте имя, так как оно используется окном). Теперь, когда вы запустите код, вы увидите глобальное:

const details = {
    my_name: 'Joe',
    friends: [ 'Bob', 'Alex' ],
    getFriends: function() {
        this.friends.forEach( function( friend ) {
            console.log( this.my_name + " is friends with " + friend );
        } );
    }
};
window.my_name = "What?"
details.getFriends();

К вашему сведению: forEach принимает второе значение, которое вы можете использовать, чтобы указать, что this будет в обратном вызове. Так это работает, например:

const details = {
    my_name: 'Joe',
    friends: [ 'Bob', 'Alex' ],
    getFriends: function() {
        this.friends.forEach( function( friend ) {
            console.log( this.my_name + " is friends with " + friend );
        }, this ); //<-- pass this into the forEach
    }
};

details.getFriends();

Конечно, вы всегда можете также использовать функцию стрелки.

1 голос
/ 16 мая 2019

Цитирование из w3schools

In a method, this refers to the owner object. Alone, this refers to the global object. In a function, this refers to the global object. In a function, in strict mode, this is undefined. In an event, this refers to the element that received the event. Methods like call(), and apply() can refer this to any object.

https://www.w3schools.com/js/js_this.asp

0 голосов
/ 16 мая 2019

Ключевое слово this относится к текущему контексту выполнения.

По умолчанию this в функции имеет глобальный контекст, который всегда является объектом окна в браузере:

function foo() {
  return this;
}

console.assert(foo() === window);

Однако при вызове в качестве конструктора оператор new устанавливает this для объекта, созданного из прототипа функции. Этот контекст уникален для каждого экземпляра.

function foo() {
  return this;
}

console.assert(new foo() !== window);
console.assert(new foo() !== new foo());

Если у объекта есть метод, this в этом методе является этим объектом по умолчанию:

const question = {
  ask: function () {
    return this;
  }
};

console.assert(question.ask() === question);

Теперь вот почему имеет значение текущий контекст выполнения.

Если вы возьмете этот метод за пределы его объекта, тогда контекст этого метода по умолчанию будет иметь глобальный контекст:

const question = {
  ask: function () {
    return this;
  }
};

const ask = question.ask;

console.assert(ask() === window);

Для решения этой проблемы вы можете использовать bind, call или apply:

const question = {
  ask: function () {
    return this;
  }
};

const ask = question.ask;

console.assert(ask.bind(question)() === question);
console.assert(ask.call(question) === question);
console.assert(ask.apply(question) === question);

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

Ранее нам приходилось сохранять this в переменной (обычно называемой that) для ссылки на правильный контекст. (Или используйте bind.)

function foo() {
  const that = this;
  // By the time the function executes, the execution context
  // will be different even though we invoked the function
  // as a constructor.
  setTimeout(function () {
    console.assert(that !== this);
    console.assert(this === window);
  }, 100);
}

new foo();

Эта техника стала устаревшей с функциями стрелок:

function foo() {
  setTimeout(() => {
    console.assert(this !== window);
  }, 100);
}

new foo();

Однако помните, что функции имеют ограниченную лексику, поэтому не даст ожидаемый результат:

const question = {
  ask: () => {
    return this;
  }
};

console.assert(question.ask() === window);

Почему? На момент определения функции стрелки единственным контекстом, доступным в лексической области, был глобальный контекст.

...