update
This commit is contained in:
parent
962caebbb7
commit
87bf53d076
1825 changed files with 94929 additions and 0 deletions
228
1-js/6-objects-more/1-object-methods/article.md
Normal file
228
1-js/6-objects-more/1-object-methods/article.md
Normal file
|
@ -0,0 +1,228 @@
|
|||
# Методы объектов, this
|
||||
|
||||
До этого мы говорили об объекте лишь как о хранилище значений. Теперь пойдём дальше и поговорим об объектах как о сущностях со своими функциями ("методами").
|
||||
[cut]
|
||||
|
||||
## Методы у объектов
|
||||
|
||||
При объявлении объекта можно указать свойство-функцию, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: 'Василий',
|
||||
|
||||
*!*
|
||||
// метод
|
||||
*/!*
|
||||
sayHi: function() {
|
||||
alert('Привет!');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
*!*
|
||||
// Вызов
|
||||
user.sayHi();
|
||||
*/!*
|
||||
```
|
||||
|
||||
Свойства-функции называют "методами" объектов. Их можно добавлять и удалять в любой момент, в том числе и явным присваиванием:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: 'Василий'
|
||||
};
|
||||
|
||||
*!*
|
||||
user.sayHi = function() { // присвоили метод после создания объекта
|
||||
alert('Привет!');
|
||||
};
|
||||
*/!*
|
||||
|
||||
// Вызов метода:
|
||||
*!*user.sayHi();*/!*
|
||||
```
|
||||
|
||||
## Доступ к объекту через this
|
||||
|
||||
Для полноценной работы метод должен иметь доступ к данным объекта. В частности, вызов `user.sayHi()` может захотеть вывести имя пользователя.
|
||||
|
||||
**Для доступа к текущему объекту из метода используется ключевое слово `this`**.
|
||||
|
||||
Значением `this` является объект перед "точкой", в контексте которого вызван метод, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: 'Василий',
|
||||
|
||||
sayHi: function() {
|
||||
alert( *!*this.name*/!* );
|
||||
}
|
||||
};
|
||||
|
||||
user.sayHi(); // sayHi в контексте user
|
||||
```
|
||||
|
||||
Здесь при выполнении функции `user.sayHi()` в `this` будет храниться ссылка на текущий объект `user`.
|
||||
|
||||
Вместо `this` внутри `sayHi` можно было бы обратиться к объекту, используя переменную `user`:
|
||||
|
||||
```js
|
||||
...
|
||||
sayHi: function() {
|
||||
alert( *!*user.name*/!* );
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
...Однако, такое решение нестабильно. Если мы решим скопировать объект в другую переменную, например `admin = user`, а в переменную `user` записать что-то другое -- обращение будет совсем не по адресу:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: 'Василий',
|
||||
|
||||
sayHi: function() {
|
||||
alert( *!*user.name*/!* ); // приведёт к ошибке
|
||||
}
|
||||
};
|
||||
|
||||
var admin = user;
|
||||
user = null;
|
||||
|
||||
admin.sayHi(); // упс! внутри sayHi обращение по старому имени, ошибка!
|
||||
```
|
||||
|
||||
**Использование `this` гарантирует, что функция работает именно с тем объектом, в контексте которого вызвана!**
|
||||
|
||||
Через `this` метод может обратиться к любому свойству объекта, а, при желании, и передать объект куда-либо:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: 'Василий',
|
||||
|
||||
*!*
|
||||
sayHi: function() {
|
||||
showName(this); // передать текущий объект в showName
|
||||
}
|
||||
*/!*
|
||||
};
|
||||
|
||||
function showName(obj) {
|
||||
alert( obj.name );
|
||||
}
|
||||
|
||||
user.sayHi(); // Василий
|
||||
```
|
||||
|
||||
## Подробнее про this
|
||||
|
||||
Любая функция может иметь в себе `this`. Совершенно неважно, объявлена она в объекте или вне него.
|
||||
|
||||
Значение `this` называется *контекстом вызова* и будет определено в момент вызова функции.
|
||||
|
||||
Например, такая функция, объявленная без объекта, вполне допустима:
|
||||
|
||||
```js
|
||||
function sayHi() {
|
||||
alert( *!*this.firstName*/!* );
|
||||
}
|
||||
```
|
||||
|
||||
Эта функция ещё не знает, каким будет `this`. Это выяснится при выполнении программы.
|
||||
|
||||
**Если одну и ту же функцию запускать в контексте разных объектов, она будет получать разный `this`:**
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = { firstName: "Вася" };
|
||||
var admin = { firstName: "Админ" };
|
||||
|
||||
function func() {
|
||||
alert( this.firstName );
|
||||
}
|
||||
|
||||
user.f = func;
|
||||
admin.g = func;
|
||||
|
||||
*!*
|
||||
// this равен объекту перед точкой:
|
||||
user.f(); // Вася
|
||||
admin.g(); // Админ
|
||||
admin['g'](); // Админ (не важно, доступ к объекту через точку или квадратные скобки)
|
||||
*/!*
|
||||
```
|
||||
|
||||
**Значение `this` не зависит от того, как функция была создана, оно определяется исключительно в момент вызова.**
|
||||
|
||||
## Значение this при вызове без контекста
|
||||
|
||||
Если функция использует `this` -- это подразумевает работу с объектом. Но и прямой вызов `func()` технически возможен.
|
||||
|
||||
Как правило, такая ситуация возникает при ошибке в разработке.
|
||||
|
||||
При этом `this` получает значение `window`, глобального объекта:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function func() {
|
||||
alert(this); // выведет [object Window] или [object global]
|
||||
}
|
||||
|
||||
func();
|
||||
```
|
||||
|
||||
В современном стандарте языка это поведение изменено, вместо глобального объекта `this` будет `undefined`.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function func() {
|
||||
"use strict";
|
||||
alert(this); // выведет undefined (кроме IE<10)
|
||||
}
|
||||
|
||||
func();
|
||||
```
|
||||
|
||||
Это стоит иметь в виду для общего развития, но обычно если в функции используется `this`, то она, всё же, проектируется для вызова в контексте объекта.
|
||||
|
||||
[warn header="`this` теряется при операциях с методом"]
|
||||
Ещё раз обратим внимание: контекст `this` никак не привязан к функции, даже если она создана в объявлении объекта.
|
||||
|
||||
Чтобы `this` передался правильно, нужно вызвать функцию именно через точку (или квадратные скобки). Любой более хитрый вызов приведёт к потере контекста, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
name: "Вася",
|
||||
hi: function() { alert(this.name); },
|
||||
bye: function() { alert("Пока"); }
|
||||
};
|
||||
|
||||
user.hi(); // Вася (простой вызов работает)
|
||||
*!*
|
||||
// а теперь вызовем user.hi или user.bye в зависимости от имени
|
||||
(user.name == "Вася" ? user.hi : user.bye)(); // undefined
|
||||
*/!*
|
||||
```
|
||||
|
||||
В последней строке примера метод получен в результате выполнения тернарного оператора и тут же вызван. При этом `this` теряется.
|
||||
|
||||
Иначе говоря, такой вызов эквивалентен двум строкам:
|
||||
|
||||
```js
|
||||
var method = (user.name == "Вася" ? user.hi : user.bye);
|
||||
method(); // без this
|
||||
```
|
||||
|
||||
[/warn]
|
||||
|
||||
## Задачи
|
||||
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue