Cửa sổ khoảng thuộc tính - Xâu chuỗi lệnh gọi .bind() trong JavaScript. Kêt quả bât ngơ? Thay đổi nhiều phần tử và gọi một chuỗi phương thức

Một trong những điều làm cho jQuery trở nên sắc nét và biểu cảm là việc gọi một phương thức trên đối tượng jQuery thường sẽ thay đổi tất cả các phần tử mà nó chứa. đối tượng này. Tôi nói "thường" vì một số phương thức thực hiện các thao tác không có ý nghĩa trên nhiều phần tử; bạn sẽ thấy điều này trong các chương sau. Nó cho thấy jQuery giúp cuộc sống trở nên dễ dàng hơn nhiều so với API DOM cơ bản.

Liệt kê 5-21: Làm việc với nhiều phần tử ... ; var labelElems = document.getElementsByTagName("nhãn"); với (var i = 0; i< labelElems.length; i++) { labelElems[i].style.color = "blue"; } }); ...

Trong ví dụ này, tôi chọn tất cả các thành phần nhãn trong tài liệu và thay đổi giá trị của thuộc tính color thành blue . Trong jQuery, tôi thực hiện việc này bằng một biểu thức, nhưng với DOM API thì việc này tốn nhiều công sức hơn. Ngoài ra, tôi nghĩ ý nghĩa của biểu thức jQuery rất rõ ràng, nhưng đó là ý kiến ​​​​cá nhân của tôi.

Một tính năng rất hay khác của đối tượng jQuery là nó thực hiện giao diện chất lỏng. Điều này có nghĩa là bất cứ khi nào bạn gọi một phương thức làm thay đổi nội dung của một đối tượng thì kết quả của phương thức đó sẽ là một đối tượng jQuery khác. Điều này có vẻ đơn giản nhưng nó cho phép thực hiện một chuỗi các phương thức như trong .

Liệt kê 5-22: Xâu chuỗi các phương thức trên một đối tượng jQuery ... $(document).ready(function () ( $("label").css("color", "blue").css("font-size" , ".75em"); var labelElems = document.getElementsByTagName("label");< labelElems.length; i++) { labelElems[i].style.color = "blue"; labelElems[i].style.fontSize = ".75em"; } }); ...

Trong ví dụ này, tôi đã tạo một đối tượng jQuery bằng cách sử dụng hàm $, được gọi là phương thức css và đặt giá trị cho thuộc tính color, sau đó gọi lại phương thức css, lần này để đặt giá trị cho thuộc tính font-size. Tôi cũng đã trình diễn giải pháp tương đương bằng cách sử dụng API DOM. Bạn thấy rằng nó không mất nhiều thời gian làm việc nhiều hơnđể có được kết quả tương tự bởi vì có vòng lặp for, liệt kê các mục đã chọn.

Lợi ích thực sự đến khi bạn sử dụng một chuỗi các phương thức tạo ra những thay đổi quan trọng hơn đối với tập hợp các phần tử có trong đối tượng jQuery. Một ví dụ được hiển thị.

Liệt kê 5-23: Thêm ví dụ phức tạp sử dụng một chuỗi các phương thức $(document).ready(function () ( $("label").css("color", "blue").add("input") .filter("").css(" cỡ chữ", ".75em"); var elems = document.getElementsByTagName("label"); for (var i = 0; i< elems.length; i++) { elems[i].style.color = "blue"; if (elems[i].getAttribute("for") != "snowdrop") { elems[i].style.fontSize = ".75em"; } } elems = document.getElementsByTagName("input"); for (var i = 0; i < elems.length; i++) { if (elems[i].getAttribute("name") != "rose") { elems[i].style.fontSize = ".75em"; } } });

Ví dụ này thể hiện rõ tính linh hoạt của jQuery. Chúng ta hãy xem xét từng phương pháp riêng lẻ để hiểu cách thức hoạt động của nó. Hãy bắt đầu với điều này:

$("nhãn").css("màu", "xanh")

Đây là một khởi đầu tốt và đơn giản. Tôi đã chọn tất cả các thành phần nhãn trong tài liệu và cho tất cả chúng Thuộc tính CSS màu được đặt thành màu xanh. Bước tiếp theo:

$("nhãn").css("màu", "xanh").add("đầu vào")

Phương thức add thêm các phần tử khớp với bộ chọn đã chỉ định vào đối tượng jQuery. TRONG trong trường hợp này Tôi đã chọn tất cả các yếu tố đầu vào, giá trị thuộc tính tên hoa hồng nào không. Các phần tử này được kết hợp với các phần tử đã chọn trước đó và tôi có một tổ hợp các phần tử nhãn và đầu vào. Phương thức add sẽ được thảo luận chi tiết hơn trong Chương 6. Đây là phép cộng sau:

$("nhãn").css("color", "blue").add("input").filter("")

Phương thức lọc sẽ loại bỏ tất cả các phần tử khỏi đối tượng jQuery không khớp với điều kiện đã chỉ định. Tôi sẽ nói về phương pháp này chi tiết hơn trong Chương 6, và trong khoảnh khắc này Chỉ cần biết rằng điều này cho phép tôi xóa bất kỳ phần tử nào khỏi đối tượng jQuery có giá trị thuộc tính là snowdrop là đủ.

$("nhãn").css("color", "blue").add("input") .filter("").css("font-size", ".75em");

Bước cuối cùng là gọi lại phương thức css, lần này để chỉ định giá trị .75em cho thuộc tính font-size. Và vì thế kết quả cuối cùng công việc này:

  • Tất cả các thành phần nhãn đều có thuộc tính màu CSS được đặt thành màu xanh lam.
  • Tất cả các thành phần nhãn ngoại trừ một thành phần có giá trị thuộc tính là snowdrop , đều có thuộc tính CSS cỡ chữ được đặt thành .75em.
  • Tất cả các phần tử đầu vào có giá trị thuộc tính tên khác với hoa hồng đều có thuộc tính kích thước phông chữ CSS được đặt thành .75em.
  • Việc đạt được kết quả tương tự khi sử dụng API DOM sẽ khó khăn hơn nhiều và tôi đã gặp một số khó khăn khi viết tập lệnh này. Ví dụ: tôi nghĩ rằng tôi có thể sử dụng phương thức document.querySelectorAll được mô tả trong Chương 2 để chọn các phần tử đầu vào bằng bộ chọn đầu vào, nhưng hóa ra loại bộ lọc thuộc tính này không hoạt động với phương thức này. Sau đó, tôi đã cố gắng tránh lặp lại lệnh gọi phương thức để chỉ định giá trị cho cỡ chữ bằng cách kết hợp kết quả của hai getElementsByTagName, nhưng trải nghiệm này khá khó khăn. Tôi không muốn làm bạn nhàm chán với các chi tiết, đặc biệt nếu bạn rất quan tâm đến jQuery và đang đọc cuốn sách này. Nhưng điều tôi muốn nói là jQuery cung cấp mức độ linh hoạt và tính biểu cảm mà DOM API cơ bản không thể đạt được.

    Khi jQuery Thư viện JavaScript, được phát hành vào tháng 1 năm 2006, mọi người đều nghĩ: “thêm một món đồ chơi đẹp nữa”. Sử dụng các bộ chọn CSS làm cơ sở chắc chắn là một ý tưởng hay, nhưng việc sử dụng các phép biến đổi theo chuỗi có vẻ hơi phức tạp và bản thân thư viện dường như không bao gồm được mọi thứ trường hợp có thể xảy ra. jQuery khi đó chỉ được coi là một giải pháp tạm thời và tạm thời.

    Phải đến vài tháng sau, người ta mới thấy rõ rằng jQuery chỉ đơn giản là một sản phẩm kỹ thuật. Cô khéo léo che đậy đủ phạm vi rộng các chức năng hàng ngày, đồng thời cung cấp API tiện lợi cho các tiện ích mở rộng mà bạn có thể thêm bất kỳ chức năng nào khác. Tính trừu tượng vốn có ở cấp độ cốt lõi - Chúng ta đang nói về về việc lựa chọn các phần tử mô hình đối tượng tài liệu (DOM) - và cô ấy tận dụng tối đa nó. Và quan trọng nhất, việc sử dụng thư viện này bao hàm việc tuân theo phong cách tốt trong lập trình và phù hợp với các phần khác của mã JavaScript.

    Số đông đánh giá hiện đại jQuery tập trung vào các nhà thiết kế và nhà phát triển thiếu kinh nghiệm. Tôi sẽ cố gắng giải thích tại sao nó cũng cần thiết đối với những lập trình viên có kinh nghiệm.

    Không gian tên (không gian tên)

    Chìa khóa để tạo mã JavaScript tốt cho sử dụng thêm là quản lý không gian tên cẩn thận. JavaScript có một không gian tên chung duy nhất (đối tượng window) và nhiều lập trình viên (và thậm chí một số thư viện) vứt bỏ nó một cách không cần thiết. Biến toàn cầu là xấu xa! Các nhà phát triển thận trọng hơn sẽ giảm thiểu sự xâm nhập của họ vào không gian này bằng cách sử dụng một số kỹ thuật, chẳng hạn như mô hình mô-đun.
    jQuery đi vào đối tượng duy nhất vào không gian tên chung - hàm/đối tượng jQuery. Mọi thứ khác đều là thuộc tính jQuery trực tiếp hoặc là phương thức của đối tượng được trả về bởi lệnh gọi hàm jQuery.

    Còn cải tiến ngôn ngữ thì sao? Hầu hết các thư viện đều cung cấp một số chức năng hiển thị, lọc và cắt xén mà không may bị thiếu trong các công cụ JavaScript có trong hầu hết các trình duyệt. Một số thư viện trực tiếp mở rộng các thư viện tích hợp sẵn của JavaScript Các lớp chuỗi và Array nhưng cũng không hoàn toàn an toàn. String.prototype và Array.prototype là các không gian tên toàn cầu độc lập và việc thêm bất kỳ thuộc tính nào vào chúng sẽ dẫn đến nguy cơ xung đột liên quan đến việc sử dụng cùng tên biến trong các ngữ cảnh khác nhau.

    jQuery có một số hàm mở rộng Khả năng JavaScript, nhưng mỗi thuộc tính chỉ có thể truy cập được dưới dạng thuộc tính của đối tượng jQuery: jQuery.each, jQuery.extend, jQuery.grep, jQuery.map, jQuery.merge và jQuery.trim. Theo định nghĩa, chúng sẽ không xung đột với bất kỳ mã nào khác.

    Hàm $ khét tiếng
    Trên thực tế, jQuery đưa nhiều hơn một ký tự vào không gian tên chung, ngoài ra còn có $: nó được sử dụng làm cách viết tắt của jQuery. Việc này được thực hiện khá nhẹ nhàng: nếu bạn cần lại hàm $ cũ (ví dụ: nếu bạn có một đoạn mã dựa trên Prototype), bạn có thể gọi jQuery.noConflict() để trả về chức năng cũ $.
    Nếu bạn cần hạn chế việc sử dụng hàm $ cho jQuery mà không sợ xung đột với bất kỳ cách sử dụng nào khác của hàm $ toàn cục, tài liệu jQuery gợi ý phương pháp sau:

    (function($) ( // Bên trong khối này, $ đề cập đến jQuery // Đẹp, phải không? ))(jQuery);

    Việc sử dụng phổ biến $ trong jQuery không gì khác hơn là một thủ thuật thông minh. Nhưng nếu chúng ta chỉ xem xét nó trong ngữ cảnh của jQuery thì giải pháp này có vẻ rất linh hoạt.

    Lựa chọn các phần tử
    Mỗi câu lệnh jQuery bắt đầu bằng việc chọn một hoặc nhiều nút DOM. Cú pháp bộ chọn jQuery (ngôn ngữ nội bộ của thư viện này) là sự kết hợp thú vị giữa CSS 1, 2, một chút CSS 3, một chút XPath và một vài tiện ích mở rộng khác. Chúng tôi sẽ không đi vào chi tiết mà chỉ đưa ra một vài ví dụ hữu ích:

    JQuery("div.panel") Tất cả các div có class="panel" jQuery("p#intro") Đoạn có id="intro" jQuery("div#content a:visible") Tất cả các liên kết hiển thị bên trong div có id= "content" jQuery("input[@name=email]") Tất cả các trường đầu vào có name="email" jQuery("table.orders tr:odd") Tất cả các hàng chẵn trong một bảng có class="orders" jQuery(" a [@href^="http://"]") Tất cả các liên kết bên ngoài (những liên kết bắt đầu bằng http://) jQuery("p[a]") Tất cả các đoạn văn có chứa ít nhất một liên kết

    Điều đáng quan tâm nhất ở trên là :visible và :odd, chỉ dành riêng cho jQuery. Cũng cần lưu ý rằng lựa chọn thuộc tính sử dụng ký hiệu @, phù hợp với XPath hơn CSS 2.

    Ngôn ngữ bộ chọn rất phong phú và rất giống với biểu thức chính quy, nên thời gian bỏ ra để nghiên cứu nó sẽ rất xứng đáng.

    Chúng tôi làm điều gì đó với họ
    Đối tượng mà bộ chọn jQuery trả về là một đối tượng khá thú vị. Nó là một tập hợp các phần tử DOM và hoạt động hơi giống một mảng: nó có thuộc tính độ dài, các phần tử của nó có thể được truy cập bằng chỉ mục và (quan trọng hơn) Firebug coi nó như một mảng khi hiển thị nó trong bảng điều khiển của nó. Đây không gì khác hơn là một ảo ảnh đẹp đẽ: trên thực tế, một tập hợp các phần tử là một đối tượng jQuery có con số lớn phương pháp lựa chọn, thay đổi hoặc mở rộng tập hợp hiện có.
    jQuery có ba danh mục khác nhau phương thức: phương thức đầu tiên thao tác tất cả các phần tử khớp với mẫu, phương thức thứ hai trả về giá trị từ phần tử đầu tiên được tìm thấy và phương thức thứ ba thay đổi chính lựa chọn.

    Chúng tôi sẽ không liệt kê mọi thứ phương pháp có sẵn(bạn cũng có thể thấy điều này trên visualjquery.com), nhưng đây là một số ví dụ. Nếu bạn có Firebug, bạn có thể tự mình thử chúng: chỉ cần sử dụng tab Insert jQuery (javascript:void(function())(var s=document.createElement('script');
    s.src=’http://code.jquery.com/jquery-1.1.2.js’; document.getElementsByTagName('head').appendChild(s);)())) để tải chính thư viện cho bất kỳ trang nào, sau đó dán các ví dụ mã vào bảng điều khiển Firebug (lưu ý: bạn có thể làm điều đó mà không cần Firebug: chỉ cần tải jQuery sử dụng các liên kết đã chỉ định và gọi các ví dụ được đưa ra trong thanh địa chỉ trình duyệt, không quên javascript: ở đầu và một số loại cảnh báo ở cuối (để giá trị trả về không được hiển thị trên trang)).

    JQuery("div#primary").width(300); Đặt chiều rộng của div id="primary" thành 300 pixel. jQuery("p").css("line-height", "1.8em"); Đặt chiều cao của dòng thành 1,8em cho tất cả các đoạn văn. jQuery("li:odd").css((color: "white", BackgroundColor: "black")); Áp dụng 2 quy tắc CSS cho từng mục danh sách; xin lưu ý rằng chức năng css() có thể lấy một đối tượng biểu định kiểu thay vì hai chuỗi. jQuery("a[@href^="http://"]").addClass("external").attr("target", "_blank"); Thêm lớp "bên ngoài" cho mọi người liện kết ngoại(những cái bắt đầu bằng http://), sau đó thêm target="_blank" để tăng sự khác biệt. TRONG trong ví dụ này Chuỗi cuộc gọi được mô tả dưới đây được sử dụng. jQuery("blockquote").each(function(el) ( Alert(jQuery(this).text()) )); Đối với mỗi thẻ blockquote trên trang, nó sẽ hiển thị cảnh báo cùng với nội dung văn bản của nó (bao gồm cả thẻ HTML). jQuery("a").html("Click vào đây!"); Thay thế tất cả văn bản trong các liên kết trên một trang bằng thông báo “Click Here!”. Dưới đây là một số ví dụ về các phương thức trả về giá trị từ phần tử đầu tiên được tìm thấy trong mẫu: var width = jQuery("div").width(); Chiều rộng của div đầu tiên trên trang là bao nhiêu? var src = jQuery("img").attr("src"); Ý nghĩa của là gì thuộc tính srcở hình ảnh đầu tiên trên trang? var color = jQuery("h1").css("color"); H1 đầu tiên màu gì?

    Chúng ta hãy lưu ý tính đối xứng thuận tiện của các phương thức như vậy: chúng được sử dụng cả để đặt thuộc tính (khi chúng lấy 2 đối số hoặc đối tượng được truyền có một số thuộc tính) và để đọc giá trị của các thuộc tính này (nếu chỉ một đối số được truyền) . Sự đối xứng này được sử dụng xuyên suốt thư viện jQuery, điều này giúp bạn dễ dàng ghi nhớ API.
    Ngoài ra còn có một số phương pháp sửa đổi toàn bộ tập hợp các phần tử được tìm thấy. Nhiều người trong số họ cũng cung cấp điều hướng cây DOM:

    JQuery("div").not("[@id]") Trả về tất cả các div không có thuộc tính id. jQuery("h2").parent() Trả về tất cả các phần tử là phần tử cha trực tiếp của h2. jQuery("blockquote").children() Trả về tất cả các phần tử được lồng trong blockquote. jQuery("p").eq(4).next() Tìm đoạn thứ năm trên trang, sau đó tìm phần tử tiếp theo(tức là người hàng xóm ngay bên phải). jQuery("input:text:first").parents("form") Tìm thấy phần tử chađối với biểu mẫu chứa trường input type="text" đầu tiên trên trang. Tham số tùy chọn cho parent() là một bộ chọn khác.

    Chuỗi cuộc gọi

    Nhóm jQuery thường tự hào về sự hỗ trợ của thư viện đối với các cuộc gọi theo chuỗi, thậm chí còn đưa ra các tuyên bố như "jQuery được thiết kế để thay đổi cách bạn viết mã bằng JavaScript" ngay trên trang chủ. Kỹ thuật này được coi là một nhánh phụ hơn là một con đường dẫn đến tương lai, nhưng bạn có thể sử dụng jQuery mà không cần phải xử lý các chuỗi lệnh gọi dài.
    Dây chuyền có thể được sử dụng cho một số thủ thuật thú vị. Ngoài việc sử dụng một tập hợp các lựa chọn DOM, bạn có thể sử dụng phương thức end() của jQuery để điều hướng qua chồng đối tượng và thoát khỏi ngữ cảnh hiện tại. Hơi khó giải thích một chút, nhưng khi bạn sử dụng một phương thức làm thay đổi ngữ cảnh (đối tượng) hiện tại (chẳng hạn như trẻ em() hoặc bộ lọc()), bạn có thể sử dụng end() sau đó một chút để quay lại lựa chọn trước đó. Jesse Skinner dẫn đầu ví dụ tốt sử dụng tính năng này trong hướng dẫn của tôi Giúp phát triển AJAX dễ dàng hơn với jQuery:

    $("form#login") // ẩn tất cả các nhãn có lớp tùy chọn bên trong form.find("label.Optional").hide().end() // thêm đường viền màu đỏ vào tất cả các trường loại mật khẩu trong form.find( "input:password").css("border", "1px Solid red").end() // thêm một trình xử lý vào sự kiện gửi cho biểu mẫu (function())( return confirm(. "Bạn có chắc chắn muốn gửi dữ liệu không?" ));

    Tất cả điều này sự chuyển đổi lớn Nó sẽ chỉ mất một dòng. Nó tìm biểu mẫu, tìm một số phần tử bên trong nó, áp dụng các thay đổi cho chúng, quay lại biểu mẫu và thêm trình xử lý sự kiện submit() vào biểu mẫu đó.

    Thao tác DOM

    jQuery có một số cách để thực hiện thao tác DOM rộng rãi. Điều đầu tiên có phần bất ngờ: hàm jQuery có thể lấy một đoạn mã HTML làm đối số, được chuyển đổi thành phần tử DOM (trên thực tế, nó chỉ là một chuỗi):

    var div = jQuery(" Một số văn bản ");

    Bạn có thể sử dụng chuỗi lệnh gọi để thêm thuộc tính vào div sau khi nó được tạo:

    var div = jQuery("Một số văn bản").addClass("insert").attr("id", "foo"); Bây giờ, hãy thêm nó vào thẻ body: div.appendTo(document.body) Hoặc chèn nó bằng bộ chọn vào mã hiện có: div.prependTo("div#primary")

    Chặn sự kiện

    Tất cả các thư viện JavaScript đều cần các phương thức để xử lý các sự kiện và jQuery cũng không ngoại lệ. Như với attr() và css(), các phương thức cho sự kiện có thể phục vụ hai mục đích: gọi chúng bằng một hàm làm đối số sẽ gán một trình xử lý sự kiện, gọi chúng mà không có đối số mô phỏng sự xuất hiện của sự kiện đó:

    JQuery("p").click(function() ( jQuery(this).css("background-color", "red"); )); Chúng tôi đặt trình xử lý nhấp chuột cho tất cả các đoạn văn mà chúng chuyển sang màu đỏ. jQuery("p:first").click() Mô phỏng một cú nhấp chuột cho đoạn đầu tiên trên trang. Các chức năng tương tự được sử dụng cho các sự kiện khác của trình duyệt: di chuột qua, gõ phím, v.v. Cần lưu ý rằng khi gọi trình xử lý sự kiện từ khóađiều này đề cập đến yếu tố gây ra sự kiện này; Sử dụng jQuery(this) là một thủ thuật phổ biến để gọi các phương thức jQuery trên phần tử này. Một số hàm liên quan đến sự kiện đáng được đề cập đặc biệt: jQuery("a").hover(function() ( jQuery(this).css("background-color", "orange"); ), function() ( jQuery( this).css("background-color", "white" )); hover() là cách viết tắt của hai sự kiện: onmouseover và onmouseout. jQuery("p").one("click", function() ( Alert(jQuery(this).html()); )); one() hiển thị trình xử lý sự kiện sẽ bị xóa sau lệnh gọi đầu tiên. Trong ví dụ trên, tất cả các đoạn văn sẽ thông báo về nội dung của chúng sau lần nhấp chuột đầu tiên vào chúng. jQuery cũng hỗ trợ các sự kiện gốc thông qua các phương thức bind() và trigger() (tương tự như click()). Các sự kiện tùy chỉnh có thể lấy các đối số được truyền bằng cách sử dụng một mảng trong lệnh gọi trigger(): jQuery(document).bind("stuffHappened", function(event, msg) ( Alert("Chuyện gì đã xảy ra: " + msg); )); jQuery(document).trigger("stuffHappened", ["Xin chào!"]);

    Lập trình không phô trương

    Các ứng dụng web tốt nhất là những ứng dụng có thể hoạt động với cả tập lệnh bị vô hiệu hóa và phương pháp tốt nhấtĐể đạt được mục tiêu này sẽ có JavaScript kín đáo, trong đó các sự kiện chỉ được gán cho các phần tử sau khi toàn bộ trang HTML của người dùng đã được tải (để biết thêm thông tin chi tiết Bạn có thể làm quen với lập trình kín đáo và Hijax).
    jQuery hỗ trợ tuyệt vời cho phương pháp này. Đầu tiên, mô hình bộ chọn để chọn một nút là nền tảng cho cả jQuery và lập trình đơn giản nói chung. Thứ hai, jQuery cung cấp giải pháp cho vấn đề window.onload, dựa trên nghiên cứu của Dean Edwards về cách hoạt động của sự kiện "DOM loading" đối với các trình duyệt khác nhau. Bạn có thể thiết lập chức năng xử lý khi DOM sẵn sàng cho nó:

    jQuery(document).ready(function() ( Alert("DOM đã sẵn sàng!"); ));

    Và hơn thế nữa, bạn có thể rút ngắn mục này bằng cách gán trực tiếp hàm của mình cho jQuery():

    jQuery(function() ( cảnh báo("DOM đã sẵn sàng!"); ));

    jQuery và AJAX

    bạn jQuery là tốt nhất API AJAX tôi từng thấy trong các thư viện lớn. Hầu hết mâu đơn giản Cuộc gọi AJAX trông như thế này:
    jQuery('div#intro').load('/some/fragment.html');

    Nó sẽ thực hiện một yêu cầu GET tới /some/fragment.html và chèn mã HTML mà nó nhận được vào div#intro.
    Điều gì sẽ xảy ra nếu bạn cần thứ gì đó phức tạp hơn, chẳng hạn như hiển thị chỉ báo tải AJAX? jQuery cung cấp một bộ sự kiện riêng(ajaxStart, ajaxComplete, ajaxError và những thứ khác) để sử dụng nếu cần. Thư viện này cũng có API nâng cao hơn. cấp thấp cho các tương tác AJAX phức tạp:

    jQuery.get("/some/script.php", ("name": "Simon"), function(data) ( notification("Server đã phản hồi: " + data); )); // NHẬN yêu cầu tới /some/script.php?name=Simon jQuery.post("/some/script.php", ("name": "Simon"), function(data) ( Alert("Server đã phản hồi: " + dữ liệu); )); // POST yêu cầu tới /some/script.php jQuery.getJSON("/some.json", function(json) ( Alert("JSON return: " + json.foo + " " + json.bar); )) ; // Trả về và chuyển đổi phản hồi từ /some.json thành JSON jQuery.getScript("/script.js"); // NHẬN yêu cầu tới /script.js và eval()

    Tiện ích mở rộng

    Xem xét toàn bộ tập hợp các chức năng này trong giao hàng tiêu chuẩn, cần lưu ý rằng phiên bản nén của jQuery chỉ chiếm 20 KB và thậm chí còn ít hơn nếu bạn sử dụng tính năng lưu trữ (.gz). Chức năng bổ sung ngoài phạm vi này có thể được cung cấp thông qua các tiện ích mở rộng, có thể (và thực hiện) thêm các phương thức mới vào đối tượng jQuery hiện có. Bạn có thể làm một cái gì đó như thế này nếu bạn muốn.

    Lời hứa chỉ mang tính tương đối tính năng mới JavaScript, cho phép bạn thực hiện các hành động bị trì hoãn - điều mà trước đây đã được giải quyết bằng lệnh gọi lại. Giới thiệu tốt công nghệ này có trên trang web HTML5Rocks, tôi sẽ không kể lại.

    Promise có hai phương thức (hiện chúng tôi đang quan tâm) - .then() và .catch() , trong đó các hàm xử lý được truyền tương ứng cho trạng thái “đã hoàn thành” và “bị từ chối”. Các phương thức này có thể được xâu chuỗi:prom.then().then().catch().then().catch().catch().… . Câu hỏi: những trình xử lý này được gọi theo thứ tự nào, chúng nhận được gì và tất cả phụ thuộc vào điều gì?

    Trước tiên, chúng ta hãy xem cấu trúc của vũ hội.then().then() (ở đây vũ hội là một loại Promise nào đó). Prom.then() ở đây là gì? Đó rõ ràng là một Promise vì nó có các phương thức .then() và .catch(). Nó như thế nào nghĩa Lời hứa này? Có vẻ “tự nhiên” khi cho rằng đó là cùng một buổi vũ hội được truyền dọc theo chuỗi, nhưng thực tế không phải vậy (và thật tốt là không phải như vậy).

    Mỗi trình xử lý .then() và .catch() trả về một giá trị nào đó. Ngay cả khi một hàm không trả về một giá trị rõ ràng thì kết quả của nó vẫn là nghĩa không xác định. Các quy tắc sau được áp dụng:

    • Nếu hàm trả về một Promise thì hàm đó sẽ trở thành Promise mới trong chuỗi;
    • Nếu hàm trả về bất kỳ giá trị nào khác thì hàm đó được gói trong Promise.resolve(...) và trở thành Promise ở trạng thái hoàn thành;
    • Cuối cùng, nếu một ngoại lệ xảy ra trong một hàm, giá trị của ngoại lệ đó sẽ được gói trong Promise.reject(...) và trở thành Promise ở trạng thái bị từ chối.

    Ứng dụng hữu ích nhất của các quy tắc này là khả năng xử lý dữ liệu trên chuỗi. Ví dụ như thế này:

    Get("data.json") .then(function(response) ( // phản hồi là dữ liệu văn bản return JSON.parse(response); )).then(function(response) ( // và ở đây phản hồi là đối tượng nhận được trong trình xử lý trước đó console.log("Yey JSON!", reply ));

    Nhưng hãy quay trở lại chuỗi tùy ý. Chúng ta có một Promise, tùy thuộc vào trạng thái của nó, nó gọi .then() hoặc .catch() , gần nhất với nó trong chuỗi. Trình xử lý được gọi trả về một Promise mới, nó lại gọi .then() hoặc .catch() , tùy theo giá trị nào gần nhất trong chuỗi. Và như thế.

    Hãy đưa ra một ví dụ (tôi sẽ viết nó theo cú pháp ES6, nó đơn giản hơn):

    Promise.reject("A") .then(x => ( console.log("THEN1", x); )) .catch(x => ( console.log("CATCH1", x); )) .then (x => ( console.log("THEN2", x); )).catch(x => ( console.log("CATCH2", x); ));

    Chúng ta sẽ nhận được gì trong bảng điều khiển? Đó là gì:

    CATCH1 A THEN2 không xác định

    Tại sao vậy? Chúng ta có một Promise ở trạng thái không thành công, có nghĩa là nó sẽ gọi trình xử lý .catch() gần nhất trong chuỗi, đó là CATCH1. Trình xử lý này không trả về bất cứ thứ gì (tức là nó trả về không xác định), có nghĩa là đầu ra từ nó là hoàn thành Lời hứa có giá trị không xác định. Lời hứa đã hoàn thành sẽ gọi .then() gần nhất, đó là THEN2.

    Một vi dụ khac:

    Promise.reject("A") .catch(x => ( console.log("CATCH1", x); return Promise.reject("B"); )) .then(x => ( console.log(" THEN1", x); )).catch(x => ( console.log("CATCH2", x); )).then(x => ( console.log("THEN2", x); ));

    Kết quả (tự tìm hiểu tại sao lại như vậy):

    CATCH1 A CATCH2 B THEN2 không xác định

    Nhân tiện, ở đây có vài cái cào dưới nước. Giả sử rằng .catch() gặp lỗi trong buổi vũ hội. Nếu buổi lễ thành công thì .then() sẽ được gọi, nhưng nếu xảy ra lỗi hoặc ngoại lệ nào đó trong trình xử lý của nó thì nó sẽ trả về một Promise mới ở trạng thái không thành công, điều này sẽ khiến .catch() được thực thi, điều này sẽ rất có thể không hoạt động chính xác.k. mong đợi dữ liệu hoàn toàn khác.

    Do đó, để đảm bảo rằng cả hai trình xử lý .then() và .catch() chỉ xử lý Promise đã cho, bạn không nên sử dụng một chuỗi lệnh gọi mà hãy gọi .then() với hai đối số. Như thế này: vũ hội.then(onResolve, onReject). Sau đó, bất kể điều gì xảy ra trong onResolve, onReject sẽ không được gọi.

    Câu trả lời tuyệt vời của torazaburo đã cho tôi một ý tưởng. Có thể đối với một hàm như liên kết, thay vì nướng bộ thu (cái này) trong lệnh gọi bên trong bao đóng, hãy đặt nó làm thuộc tính trên đối tượng hàm và sau đó sử dụng nó khi gọi nó. Điều này sẽ cho phép thử lại cập nhật thuộc tính trước khi thực hiện lệnh gọi, mang lại kết quả mong đợi của lần thử lại một cách hiệu quả.

    Ví dụ,

    function original_fn() ( document.writeln(JSON.stringify(this)); ) Function.prototype.rebind = function(obj) ( var fn = this; varbound = function func() ( fn.call(func.receiver, đối số); ràng buộc.receiver = obj; ràng buộc.rebind = function(obj) ( this.receiver = obj; return this; ) returnbound_fn = original_fn.rebind((foo: "bar")) ; ràng buộc_fn(); var rebound_fn =bound_fn.rebind((fred: "barney")); hồi phục_fn();

    Hoặc đầu ra từ node.js trông như thế này.

    ( foo: "bar" ) ( fred: "barney" )

    Lưu ý rằng lệnh gọi rebind đầu tiên gọi lệnh đã được thêm vào Function.prototype như nó được gọi trong hàm original_fn thông thường, nhưng lệnh gọi thứ hai gọi rebind đã được thêm làm thuộc tính của hàm bị ràng buộc (và mọi lệnh gọi tiếp theo sẽ cũng gọi như vậy). Việc rebind này chỉ đơn giản là cập nhật bộ thu và trả về cùng một đối tượng hàm.

    Có thể truy cập thuộc tính người nhận trong hàm bị ràng buộc bằng cách thực hiện nó biểu thức hàm được đặt tên .

    2018-12-04T00:00Z

    Thật hấp dẫn khi nghĩ tới ràng buộc như một loại sửa đổi sử dụng tính năng mới này. Theo cách giải thích (không chính xác) này, mọi người nghĩ đến liên kết bằng cách thêm một loại cờ ma thuật nào đó vào một hàm yêu cầu nó sử dụng cái gì đó khác vào lần tiếp theo nó được gọi. Nếu đúng như vậy thì có thể "ghi đè" và thay đổi lá cờ thần kỳ. Rồi hỏi, lý do gì mà tự ý hạn chế khả năng làm việc này?

    Nhưng thực tế đó không phải là cách nó hoạt động. liên kết tạo và trả về mới một hàm mà khi được gọi sẽ gọi hàm đầu tiên với một giá trị cụ thể. Hành vi của hàm mới được tạo này để sử dụng hàm đã chỉ định để gọi hàm ban đầu sẽ được ghi lại khi hàm được tạo. Nó không thể được thay đổi nhiều hơn các phần bên trong của bất kỳ hàm nào khác được hàm trả về có thể được thay đổi sau khi thực tế.

    Nó có thể hữu ích để nhìn vào thực tế thực hiện đơn giản trói buộc:

    // KHÔNG phải là ràng buộc thực sự; chỉ là một ví dụ Function.prototype.bind = function(ctxt) ( var fn = this; return function bind_fn() ( return fn.apply(ctxt, đối số); ); ) my_bound_fn = original_fn.bind(obj);

    Như bạn có thể thấy, không nơi nào trong bind_fn hàm được trả về từ bind tham chiếu đến this mà hàm liên kết được gọi. Nó bị bỏ qua, vì vậy

    My_bound_fn.call(999, arg) // 999 bị bỏ qua

    Obj = ( fn: function () ( console.log(this); ) ); obj.fn = obj.fn.bind(other_obj); obj.fn(); // xuất ra other_obj; obj bị bỏ qua

    Vì vậy, tôi có thể liên kết hàm được trả về từ liên kết "một lần nữa", nhưng điều này không đẩy lùi hàm ban đầu; nó chỉ liên kết với một chức năng bên ngoài mà không ảnh hưởng đến chức năng nội tại, vì nó đã được cấu hình để gọi chức năng cơ bản với bối cảnh (giá trị này) được chuyển tới bind . Tôi có thể liên kết nhiều lần, nhưng tất cả những gì tôi làm là tạo thêm chức năng bên ngoài, có thể bị ràng buộc bởi thứ gì đó, nhưng cuối cùng lại gọi hàm trong cùng được trả về từ liên kết đầu tiên.

    Do đó, hơi sai lầm khi nói rằng liên kết "không thể bị ghi đè".

    Nếu tôi muốn "khôi phục" một hàm, thì tôi chỉ cần tạo một ràng buộc mới cho hàm ban đầu. Vì vậy, nếu tôi liên kết nó một lần:

    Hàm orig() ( ) my_bound_fn = orig.bind(my_obj);

    và sau đó tôi muốn của tôi chức năng ban đầuđược gọi cùng với một số người khác thì tôi không kiểm tra lại chức năng liên quan.