Из документов я понимаю, что .proxy()это изменило бы область действия функции, передаваемой в качестве аргумента. Может кто-нибудь объяснить мне это лучше? Почему мы должны это делать?
Из документов я понимаю, что .proxy()это изменило бы область действия функции, передаваемой в качестве аргумента. Может кто-нибудь объяснить мне это лучше? Почему мы должны это делать?
Ответы:
В конечном итоге он гарантирует, что значение thisв функции будет значением, которое вы желаете.
Типичным примером является то, setTimeoutчто происходит внутри clickобработчика.
Возьми это:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
Намерение достаточно простое. Когда myElementнажата кнопка, она должна получить класс aNewClass. Внутри обработчик thisпредставляет элемент, по которому щелкнули.
Но что, если мы хотим небольшую задержку перед добавлением класса? Мы могли бы использовать a setTimeoutдля достижения этой цели, но проблема в том, что независимо от того, какую функцию мы даем setTimeout, значение thisвнутри этой функции будет windowвместо нашего элемента.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Поэтому вместо этого мы можем вызвать $.proxy()функцию и значение, которое мы хотим присвоить this, и вызвать функцию, которая сохранит это значение.
$('#myElement').click(function() {
// ------------------v--------give $.proxy our function,
setTimeout($.proxy(function() {
$(this).addClass('aNewClass'); // Now "this" is again our element
}, this), 1000);
// ---^--------------and tell it that we want our DOM element to be the
// value of "this" in the function
});
Таким образом, после того, как мы дали $.proxy()функцию и значение, которое мы хотим this, она вернула функцию, которая будет гарантировать, что thisона установлена правильно.
Как это сделать? Он просто возвращает анонимную функцию, которая вызывает нашу функцию, используя .apply()метод, который позволяет ей явно установить значение this.
Упрощенный взгляд на возвращаемую функцию может выглядеть так:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Таким образом, эта анонимная функция дана setTimeout, и все, что она делает, это выполняет нашу исходную функцию с соответствующим thisконтекстом.
$.proxy(function () {...}, this)а не (function() {...}).call(this)? Есть ли разница?
.callвами вызов функции немедленно. С помощью $.proxy, это как Function.prototype.bindгде он возвращает новую функцию. Эта новая функция имеет thisпостоянное значение, поэтому, когда она передается setTimeoutи setTimeoutвызывает функцию позднее, она все равно будет иметь правильное thisзначение.
Не вдаваясь в подробности (что было бы необходимо, поскольку речь идет о Context в ECMAScript, переменной this context и т. Д.)
В ECMA- / Javascript есть три разных типа «Контекстов»:
Каждый код выполняется в контексте выполнения . Существует один глобальный контекст, и может быть много экземпляров функциональных (и eval) контекстов. Теперь интересная часть:
Каждый вызов функции входит в контекст выполнения функции. Контекст выполнения функции выглядит следующим образом:
Область
действия объекта активации Цепочка
этого значения
Таким образом, это значение является специальным объектом, который связан с контекстом выполнения. В ECMA- / Javascript есть две функции, которые могут изменять значение this в контексте выполнения функции:
.call()
.apply()
Если у нас есть функция, foobar()мы можем изменить значение this , вызвав:
foobar.call({test: 5});
Теперь мы можем получить доступ foobarк объекту, который мы передали:
function foobar() {
this.test // === 5
}
Это именно то, что jQuery.proxy()делает. Он принимает functionи context(который является ничем иным, как объектом) и связывает функцию, вызывая .call()или .apply()и возвращает эту новую функцию.
Та же цель может быть достигнута с помощью «Сразу-Вызывается функция Expression, короткий: IIFE» функция , выполняющейся сама :
$('#myElement').click(function() {
(function(el){
setTimeout(function() {
// Problem! In this function "this" is not our element!
el.addClass('colorme');
}, 1000);
})($(this)); // self executing function
});
.colorme{
color:red;
font-size:20px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="myElement">Click me</div>
</body>
</html>