З документів я розумію, що .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значення.
Не вникаючи в більш детальну інформацію (що було б необхідно, оскільки мова йде про контекст у ECMAScript, про цю змінну контексту тощо)
У ECMA- / Javascript є три різні типи "Контекстів":
Кожен код виконується в контексті його виконання . Є один глобальний контекст, і може бути багато випадків функціональних (і eval) контекстів. Тепер цікава частина:
Кожен виклик функції входить у контекст виконання функції. Контекст виконання функції виглядає так:
Це значення має
ланцюг об єктів активації
Отже, це значення є спеціальним об'єктом, який пов'язаний з контекстом виконання. У ECMA- / JavaScript є дві функції, які можуть змінювати це значення в контексті виконання функції:
.call()
.apply()
Якщо у нас є функція, foobar()ми можемо змінити це значення, зателефонувавши:
foobar.call({test: 5});
Тепер ми могли отримати доступ foobarдо об'єкта, який ми передавали:
function foobar() {
this.test // === 5
}
Це саме те, що jQuery.proxy()робить. Він займає a 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>