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 setTimeoutdiễn ra bên trong một clickxử 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ị thisbên trong chức năng đó sẽ windowthay 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 thisvà 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 setTimeoutvà 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 thisbố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?
.callbạn đang gọi hàm ngay lập tức. Với $.proxy, nó giống như Function.prototype.bindnơi nó trả về một chức năng mới. Hàm mới đó có thisgiá trị bị ràng buộc vĩnh viễn, do đó, khi nó được chuyển đến setTimeoutvà setTimeoutgọi hàm sau, nó vẫn sẽ có thisgiá 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 functionvà 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>