Từ tài liệu tôi hiểu rằng .proxy()
sẽ thay đổi phạm vi của hàm được truyền dưới dạng đối số. Ai đó có thể vui lòng giải thích cho tôi điều này tốt hơn? Tại sao chúng ta nên làm điều này?
Từ tài liệu tôi hiểu rằng .proxy()
sẽ thay đổi phạm vi của hàm được truyền dưới dạng đối số. Ai đó có thể vui lòng giải thích cho tôi điều này tốt hơn? Tại sao chúng ta nên làm điều này?
Câu trả lời:
Những gì nó cuối cùng làm là nó đảm bảo rằng giá trị của this
hàm sẽ là giá trị bạn mong muốn.
Một ví dụ phổ biến là trong một setTimeout
diễn ra bên trong một click
xử lý.
Thực hiện việc này:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
Ý định là đủ đơn giản. Khi myElement
được nhấp, nó sẽ nhận được lớp aNewClass
. Bên trong trình xử lý this
đại diện cho các yếu tố đã được nhấp.
Nhưng nếu chúng ta muốn một sự chậm trễ ngắn trước khi thêm lớp thì sao? Chúng ta có thể sử dụng một setTimeout
để thực hiện nó, nhưng rắc rối là bất kỳ chức năng nào chúng ta cung cấp setTimeout
, giá trị this
bên trong chức năng đó sẽ window
thay vì phần tử của chúng ta.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
Vì vậy, những gì chúng ta có thể làm thay vào đó là gọi $.proxy()
, gửi cho nó hàm và giá trị chúng ta muốn gán this
và nó sẽ trả về một hàm sẽ giữ lại giá trị đó.
$('#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
});
Vì vậy, sau khi chúng tôi đưa ra $.proxy()
hàm và giá trị chúng tôi muốn this
, nó trả về một hàm sẽ đảm bảo this
được đặt đúng.
Làm thế nào để nó làm điều đó? Nó chỉ trả về một hàm ẩn danh gọi hàm của chúng ta bằng .apply()
phương thức, cho phép nó đặt giá trị của this
.
Một cái nhìn đơn giản về chức năng được trả về có thể trông như sau:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
Vì vậy, chức năng ẩn danh này được trao cho setTimeout
và tất cả những gì nó thực hiện là chức năng ban đầu của chúng tôi với this
bối cảnh thích hợp .
$.proxy(function () {...}, this)
chứ không phải là (function() {...}).call(this)
gì? Có sự khác biệt?
.call
bạn đang gọi hàm ngay lập tức. Với $.proxy
, nó giống như Function.prototype.bind
nơi nó trả về một chức năng mới. Hàm mới đó có this
giá trị bị ràng buộc vĩnh viễn, do đó, khi nó được chuyển đến setTimeout
và setTimeout
gọi hàm sau, nó vẫn sẽ có this
giá trị đúng .
Không đi sâu vào chi tiết hơn (điều này sẽ cần thiết bởi vì đây là về Ngữ cảnh trong ECMAScript, biến bối cảnh này, v.v.)
Có ba loại "Bối cảnh" khác nhau trong ECMA- / Javascript:
Mỗi mã được thực thi trong bối cảnh thực hiện của nó . Có một bối cảnh toàn cầu và có thể có nhiều trường hợp bối cảnh chức năng (và eval). Bây giờ là phần thú vị:
Mỗi cuộc gọi của một chức năng đi vào bối cảnh thực hiện chức năng. Một bối cảnh thực hiện của một chức năng trông giống như:
Chuỗi phạm vi đối tượng kích hoạt
giá trị này
Vì vậy, này giá trị là một đối tượng đặc biệt có liên quan với bối cảnh thực hiện. Có hai hàm trong ECMA- / Javascript có thể thay đổi giá trị này trong ngữ cảnh thực thi chức năng:
.call()
.apply()
Nếu chúng ta có một chức năng, foobar()
chúng ta có thể thay đổi giá trị này bằng cách gọi:
foobar.call({test: 5});
Bây giờ chúng ta có thể truy cập vào foobar
đối tượng chúng ta đã truyền vào:
function foobar() {
this.test // === 5
}
Đây là chính xác những gì jQuery.proxy()
làm. Nó nhận một function
và context
(không gì khác hơn là một đối tượng) và liên kết hàm bằng cách gọi .call()
hoặc .apply()
trả về hàm mới đó.
Có thể đạt được cùng một mục tiêu bằng cách sử dụng chức năng tự thực hiện "Biểu hiện chức năng được gọi ngay lập tức, gọi tắt là: 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>