Чтобы понять это, исходя из того, где это находится, ситуация может быть примерно разделена на три типа:
1. В функции: это обычно неявный параметр.
2. вне функции (в верхней области): в браузере это относится к глобальному объекту; В Node.js относится к экспорту модулей.
3. Строка передается в eval (): если eval () называется непосредственно, это относится к текущему объекту; Если eval () называется косвенно, это относится к глобальному объекту.
Мы провели соответствующие тесты для этих категорий:
1. Это в функции
Функции могут в основном представлять все вызванные структуры в JS, так что это также наиболее распространенный сценарий, в котором это используется, и функции могут быть разделены на следующие три роли:
Реальные функции
Конструктор
метод
1.1 Это в реальных функциях
В реальных функциях значение этого - это шаблон, который зависит от контекста, в котором он находится.
Неаккуратный режим: это относится к глобальному объекту (окно в браузере).
Кода -копия выглядит следующим образом:
function sloppyfunc () {
console.log (это === окно); // истинный
}
sloppyfunc ();
Строгий режим: значение этого не определен.
Кода -копия выглядит следующим образом:
функция strictfunc () {
«Использовать строго»;
console.log (это === не определено); // истинный
}
strictfunc ();
Это неявный параметр функции, поэтому ее значение всегда одинаково. Тем не менее, вы можете определить это значение, используя методы call () или применить () для отображения значения.
Кода -копия выглядит следующим образом:
Функция func (arg1, arg2) {
console.log (это); // 1
console.log (arg1); // 2
console.log (arg2); // 3
}
func.call (1, 2, 3); // (это, arg1, arg2)
func.apply (1, [2, 3]); // (это, arraywithargs)
1.2 Это в конструкторе
Вы можете использовать функцию в качестве конструктора через новый. Новая операция создает новый объект и передает этот объект в конструктор через это.
Кода -копия выглядит следующим образом:
var сохранил это;
функция constr () {
Сохранить это = это;
}
var inst = new constr ();
console.log (savedThis === Inst); // истинный
Принцип реализации новой операции в JS примерно показан в следующем коде (см. Здесь для более точной реализации, эта реализация также более сложна):
Кода -копия выглядит следующим образом:
Функция Newoperator (Constry, ArrayWithargs) {
var thisvalue = object.create (const.prototype);
Const.apply (thisvalue, arraywithargs);
вернуть это значение;
}
1.3 Это в методе
В методах использование этого, как правило, больше на традиционном объектно-ориентированном языке: на это, на который указан приемник, то есть объект, содержащий этот метод.
Кода -копия выглядит следующим образом:
var obj = {
Метод: function () {
console.log (это === obj); // истинный
}
}
obj.method ();
2. Это по объему
В браузере объем является глобальная область, и это относится к этому глобальному объекту (например, окно):
Кода -копия выглядит следующим образом:
<Скрипт>
console.log (это === окно); // истинный
</script>
В node.js вы обычно выполняете функции в модулях. Следовательно, область на высшем уровне является очень особенным модулем:
Кода -копия выглядит следующим образом:
// `global` (не` window`) см. Global Object:
console.log (Math === Global.math); // истинный
// `Это не относится к глобальному объекту:
console.log (это! == Global); // истинный
// `Это относится к экспорту модуля:
console.log (this === module.exports); // истинный
3. Это в eval ()
eval () может быть вызван непосредственно (назвав имя функции «Eval») или косвенно (другими средствами, такими как Call ()). Для получения более подробной информации, пожалуйста, смотрите здесь.
Кода -копия выглядит следующим образом:
// реальные функции
function sloppyfunc () {
console.log (eval ('this') === window); // истинный
}
sloppyfunc ();
функция strictfunc () {
«Использовать строго»;
console.log (eval ('this') === не определено); // истинный
}
strictfunc ();
// конструкторы
var сохранил это;
функция constr () {
savedThis = eval ('this');
}
var inst = new constr ();
console.log (savedThis === Inst); // истинный
// методы
var obj = {
Метод: function () {
console.log (eval ('this') === obj); // истинный
}
}
obj.method ();
4. ловушки, связанные с этим
Вы должны быть осторожны с 3 ловушками, связанными с этим, которые будут представлены ниже. Обратите внимание, что в следующем примере использование строгого режима может улучшить безопасность кода. Поскольку в реальных функциях ценность этого не определена, вы получите предупреждение, когда что -то пойдет не так.
4.1 Забыл использовать новый
Если вы не используете новый для вызова конструктора, вы на самом деле используете реальную функцию. Так что это не будет то, что вы ожидаете. В неаккуратном режиме это указывает на окно, и вы создадите глобальные переменные:
Кода -копия выглядит следующим образом:
точка функции (x, y) {
this.x = x;
this.y = y;
}
var p = точка (7, 5); // Мы забываем новое!
console.log (p === не определен); // истинный
// были созданы глобальные переменные:
console.log (x); // 7
console.log (y); // 5
Однако, если вы используете строгий режим, вы все равно получите предупреждение (это === не определено):
Кода -копия выглядит следующим образом:
точка функции (x, y) {
«Использовать строго»;
this.x = x;
this.y = y;
}
var p = точка (7, 5);
// typeError: не может установить свойство «x» неопределенного
4.2 Неуместный метод использования
Если вы напрямую получаете значение метода (не вызывая его), вы используете этот метод в качестве функции. Если вы хотите передать метод в качестве параметра в функцию или метод вызова, вы, скорее всего, сделаете это. Это относится к обработчикам сетчиков SetTimeout () и регистрации. Я буду использовать метод Callit () для моделирования этого сценария:
Кода -копия выглядит следующим образом:
/** Аналогично settimeout () и setimmediate ()*/
Функция Callit (func) {
func ();
}
Если вы называете метод в качестве функции в небрежном режиме, * это * указывает на глобальный объект, поэтому создание впоследствии будет глобальными переменными.
Кода -копия выглядит следующим образом:
var счетчик = {
Подсчет: 0,
// метод небрежного режима
Inc: function () {
this.count ++;
}
}
Callit (counter.inc);
// не работал:
console.log (counter.count); // 0
// вместо этого была создана глобальная переменная
// (NAN является результатом применения ++ к неопределенному):
console.log (count); // НАН
Если вы сделаете это в строгом режиме, это не определено, и вы все равно не получите желаемый результат, но, по крайней мере, вы получите предупреждение:
Кода -копия выглядит следующим образом:
var счетчик = {
Подсчет: 0,
// метод строгого режима
Inc: function () {
«Использовать строго»;
this.count ++;
}
}
Callit (counter.inc);
// typeError: не удается прочитать свойство «количество» неопределенного
console.log (counter.count);
Чтобы получить ожидаемые результаты, вы можете использовать bind ():
Кода -копия выглядит следующим образом:
var счетчик = {
Подсчет: 0,
Inc: function () {
this.count ++;
}
}
Callit (counter.inc.bind (счетчик));
// это сработало!
console.log (counter.count); // 1
bind () Создает другую функцию, которая всегда может установить это значение на счетчик.
4.3 скрыть это
Когда вы используете функции в методах, вы часто игнорируете, что функции имеют свои собственные. Это отличается от метода, поэтому вы не можете смешать эти два вместе. Для получения подробной информации см. Следующий код:
Кода -копия выглядит следующим образом:
var obj = {
Имя: «Джейн»,
Друзья: [«Тарзан», «Чита»],
Loop: function () {
«Использовать строго»;
this.friends.foreach (
функция (друг) {
console.log (this.name+'знает'+друг);
}
);
}
};
obj.loop ();
// typeError: не удается прочитать «имя" имени "не определенного
Это имя в функции в приведенном выше примере не может быть использовано, потому что значение этой функции не определен, что отличается от этого в цикле метода (). Ниже приведены три идеи для решения этой проблемы:
1. Это = это, присваивайте это переменной, так что это явно проявляется (за исключением того, что я также является очень распространенным именем переменной, используемой для хранения), а затем используйте эту переменную:
Кода -копия выглядит следующим образом:
Loop: function () {
«Использовать строго»;
var that = это;
this.friends.foreach (function (друг) {
console.log (that.name+'знание'+друг);
});
}
2. bind (). Используйте bind (), чтобы создать функцию. Эта функция всегда содержит значение, которое вы хотите пройти (в следующем примере, этот метод):
Кода -копия выглядит следующим образом:
Loop: function () {
«Использовать строго»;
this.friends.foreach (function (друг) {
console.log (this.name+'знает'+друг);
} .bind (this));
}
3. Используйте второй параметр Foreach. Второй параметр foreach будет передаваться в функцию обратного вызова и будет использован в качестве функции обратного вызова.
Кода -копия выглядит следующим образом:
Loop: function () {
«Использовать строго»;
this.friends.foreach (function (друг) {
console.log (this.name+'знает'+друг);
}, этот);
}
5. Лучшие практики
Теоретически, я думаю, что реальная функция не принадлежит его собственной, и вышеупомянутое решение также основано на этой идее. Ecmascript 6 использует функцию стрелки для достижения этого эффекта, которая является функцией, которая не имеет своей собственной. В такой функции вы можете использовать это по желанию, не беспокоясь о том, есть ли какое -либо неявное существование.
Кода -копия выглядит следующим образом:
Loop: function () {
«Использовать строго»;
// параметр foreach () является функцией стрелки
this.friends.foreach (row => {
// `this` is Loop's` this`
console.log (this.name+'знает'+друг);
});
}
Мне не нравится некоторые API, рассматривая это как дополнительный параметр для реальной функции:
Кода -копия выглядит следующим образом:
oopeach (function () {
this.addmatchers ({
tobeinrange: function (start, end) {
...
}
});
});
Написание неявного параметра, как явно прошел, код будет выглядеть лучше, чтобы понять, и это согласуется с требованиями функции стрелки:
Кода -копия выглядит следующим образом:
Apiece (api => {
api.addmatchers ({
tobeinrange (start, end) {
...
}
});
});