11/08/2018, 20:37

Solution 1 : Một số lưu ý nhỏ về Closure

Lần đầu viết kipalog Bữa nay rảnh rỗi làm Series everyone else is trash ... à nhầm, Series how to become a master web dev (tạm dịch là trùm web) để cùng chia sẽ kiến thức và thảo luận về một số vấn đề nhé!. Solution 1 : Closure trong js Chắc các bạn đã biết, đã nghe ít hoặc nhiều đến cụm ...

Lần đầu viết kipalog

Bữa nay rảnh rỗi làm Series everyone else is trash ... à nhầm, Series how to become a master web dev (tạm dịch là trùm web) để cùng chia sẽ kiến thức và thảo luận về một số vấn đề nhé!.

Solution 1 : Closure trong js

Chắc các bạn đã biết, đã nghe ít hoặc nhiều đến cụm từ closure, các bạn có thể đọc và tìm hiểu khái niệm, bản chất .... blabla trên google hoặc kipalog này, nhưng trong phạm vì topic này chúng ta chỉ tìm hiểu một số thứ beside closure mà thôi.

Vì sao closure tồn tại

Từ thời mấy thím IQ tầm 200 phát triển nên Di ét (JS), và đem js lên dùng làm ngôn ngữ lập trình vào phát triển web thì chợt nhận ra răng ôi, callback nhiều thế này!
Vì tính chất bất đồng bộ (code chạy lộn xộn, cái này chạy trước cái kia, blabla) trên môi trường web xảy ra hơi bị thường xuyên, chớ không muốn nói là mọi nơi, nên callback từ đó được hình thành để giải quyết vấn đề này.
Mà callback là fuction mà nhắc tới function thì có variable. Do callback chạy bất đồng bộ, nên mấy thím IQ 200 đó phải nghĩ ra cách giải quyết dành cho variable, nên làm gì với nó đây ?
Bùm

Closure ra đời

Closure dịch sát nghĩa tiếng anh là đóng gói, đóng kín, đóng variable ở trong function.
Thường thường variable ở trong function chỉ tồn tại trong dấu { và }, nhưng nhờ cái phương pháp giải quyết bất đồng bộ được nêu ở trên,người ta đặt tên là closure, variable vẫn còn tồn tại khi lệnh nào đó trong callback bị trigger
Nào chúng ta cùng xem ví dụ sau:
alt text

Ảnh xí cho anh em đỡ nhàm :D.

function loadNews() {
    $.ajax({
    url : 'abcxyz',
    data: data,
    success : fuction(res) {
        var news = res['news']; //mảng chứa các đối tượng new
        for (var i = 0 ; i < news.length ; i++) {
            var id = getRandom(6); //Hàm này trả về random string có độ dài là 6
            var c_new = news[i]; //Ahihi jquery, lúc này value = news[index]
            var html = '<a href="#" id='+ id +'>Click me '+ i +'</a>';
            $('body').append(html);
            $('#' + id).click(funtion() {
                console.log(c_new.title); //giả sử log ra title của object new đi
           }
    } 

Chúng ta nhìn vào ví dụ ở trên, một ví dụ điển hình của kĩ thuật load more (request ajax, append html, xử lý sự kiện).
Nếu chạy thử code thì giả sử như có 6 đối tượng new, sẽ có 6 thẻ a xuất hiện, và bạn bấm vào button bất kỳ, chuyện gì xảy ra ?? Console sẽ luôn hiện ra title của new giống nhau cho dù bạn có bấm button nào đi chăng nữa .... cụ thể, nếu ta soi kỹ thì đó chính là title của news[6].
Cùng soi nguyên nhân một chút, đáng lẽ ra khi bấm vào button tương ứng, thì title của new tương ứng cũng sẽ hiện lên, đó là điều mà chúng ta mong muốn, nhưng do closure trong vòng FOR, cụ thể là khi chạy hết vòng FOR thì biến c_new đang ở news[6], dù chúng ta đã khai báo với var, ta click vào một button, console log ra c_new.title hay chính là news[6].title và kết quả là chúng ta có cùng một giá trị dù click bất kỳ nút nào!
Mình đã từng mắc lỗi chết người này, khi nhận ra thì đã quá muộn và rất vất vả để sửa code!
Vậy thì sau đây, chúng ta có thể sửa lỗi này bằng 2 cách mà mình phát hiện ra được (có thể còn nhiều cách khác, các bạn có thể comment để chia sẽ nhé :D)

Closure trong vòng FOR

Xài $.each của Jquery
Vâng, bạn chỉ cần thay vòng For phía trên bằng :
$.each(news, function(index, value) {
Là xong :D
Hàm each của each của Jquery đã giải quyết vấn đề này cho bạn, vấn đề ở đây là hàm callback function phía trên đã trở thành một hàm closure, biến value lúc này sẽ đồng nghĩa với news[index], bạn sẽ không lo biến value bị thay đổi bởi vòng lặp for nữa, vì .... closure function rồi mà :D , PROBLEM SOLVED!

Tách riêng ra , tự tạo 1 function closure
Nếu vẫn còn đang băng khoăn cách trên thì cách này cũng tương tự thôi, chỉ là concrete hơn mà thôi, bản chất của chúng là như nhau:
Ta vẫn giữ nguyên vòng FOR chỉ thay đổi ở chỗ lúc tạo sự kiện, ta tạo một function closure:

function event(ele, c_new) {
    ele.click(function() {
        console.log(c_new.title);
    )

Tương tự, ta gọi vào event($('#' + id) , c_new) trong vòng FOR
SoLvEd :D
Thật sự thì mình recommend phương pháp 2 hơn vì code sẽ clean, vòng FOR chỉ làm một việc, và theo kinh nghiệm của mình thì lệnh event sẽ khá là dài nên viết một function riêng sẽ dễ maintain hơn :D
Thanks for reading

Đôi lời

Thật ra đây là lần đầu viết kipalog nên có thể có sai sót, mong các anh các bác đừng soi qua tội em, em mới sv năm 3 lên chia sẽ chút ít :cry:
Tiện thể, em đặt cái tiêu đề cho sốc tí thôi chớ master web khó thấy mẹ :cry:

Minh Sacred.

Facebook để các thím ném gạch xây nhà : https://www.facebook.com/levan.minh.509

0