Binding Context with proxy()
In this page:
var bound = $.proxy(function, context);
What is proxy()?
$.proxy() returns a new function that always runs with a fixed this value, no matter how or where that function is later called. It exists because JavaScript's this binding depends on how a function is invoked, which can produce surprising results when a method is passed around as a callback.
Example: What is proxy()?
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
</style>
</head>
<body>
<button id="resetBtn">Reset</button>
<div id="output"></div>
<script>
function init() {
const obj = {
name: "Widget",
show: function() { $("#output").append($("<div>").text(String(this.name))); }
};
const bound = $.proxy(obj.show, obj);
bound();
}
init();
$("#resetBtn").click(function() {
$("#output").empty();
init();
});
</script>
</body>
</html>
Why Context Matters
A callback — like an event handler or a setTimeout function — often ends up running with a different this value than the object it was originally defined on, because the calling code, not the original object, determines this. $.proxy() lets you lock this to a specific object ahead of time so the callback always behaves predictably.
Example: Why Context Matters
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
.btn { display:inline-block; padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border-radius:4px; cursor:pointer; font:13px sans-serif; }
#resetBtn.btn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<span id="resetBtn" class="btn" role="button">Reset</span>
<section id="demo">
<button id="btn">Click</button>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
function init() {
const obj = {
name: "Widget",
handleClick: function() { $("#output").append($("<div>").text(String(this.name))); }
};
$("#btn").on("click", obj.handleClick);
// logs undefined -- this is the button, not obj
}
init();
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
init();
});
</script>
</body>
</html>
Pass Arguments with proxy()
proxy() can also bind arguments to a function in addition to fixing its this value, which is useful when an event handler or callback needs extra context data that isn't provided by the event itself.
Example: Pass Arguments with proxy()
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
</style>
</head>
<body>
<button id="resetBtn">Reset</button>
<div id="output"></div>
<script>
function init() {
function greet(greeting) { $("#output").append($("<div>").text(String(greeting) + " " + this.name)); }
const obj = {name: "Alice"};
const bound = $.proxy(greet, obj);
bound("Hello");
}
init();
$("#resetBtn").click(function() {
$("#output").empty();
init();
});
</script>
</body>
</html>
Use proxy with Events
Events frequently pass callbacks around in ways that break the expected this binding — for example, a method used directly as a click handler loses its connection to the object it came from. Wrapping that method with proxy() keeps this pointing at the right object even when the handler runs later, triggered by the browser rather than your own code.
Example: Use proxy with Events
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="resetBtn">Reset</button>
<section id="demo">
<button id="btn">Click</button>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
function init() {
const obj = {
name: "Widget",
handleClick: function() { $("#output").append($("<div>").text(String(this.name))); }
};
$("#btn").on("click", $.proxy(obj.handleClick, obj));
}
init();
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
init();
});
</script>
</body>
</html>
Small proxy() Project
proxy() is most valuable whenever an object's own methods get used as standalone callbacks — for timers, event handlers, or AJAX completion functions — and you need this inside that method to still refer back to the original object.
Example: Small proxy() Project
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<div id="output"></div>
<script>
$("#runBtn").click(function() {
const timer = {
label: "Countdown",
tick: function() { $("#output").text(String(this.label) + "ticking"); }
};
setTimeout($.proxy(timer.tick, timer), 100);
});
$("#resetBtn").click(function() {
$("#output").empty();
});
</script>
</body>
</html>
- Passing a method as a callback like
$("#btn").on("click", obj.greet)and gettingthisas the button instead ofobj, which is the problem$.proxy(obj.greet, obj)solves. - Swapping the argument order, when
$.proxy(function, context)takes the function first and the context second. - Using
$.proxy()in new code, when it is deprecated since jQuery 3.3 andFunction.prototype.bind()or arrow functions do the same.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: