Series lập trình với dữ liệu Array và Object trong Javascript - Xử lý dữ liệu như thế nào cho tốt?

Series lập trình với dữ liệu Array và Object trong Javascript - Xử lý dữ liệu như thế nào cho tốt?

Những mẩu tin ngắn hàng ngày dành cho bạn
  • Hẳn là nhiều người ở đây đã nghe đến kiểu tấn công bảo mật Clickjacking rồi nhỉ. Kẻ tấn công thường nhúng một website (thường là mục tiêu) vào trong một iframe trên website của chúng, sau đó làm mờ hoặc ẩn nó đi rồi đặt vào vị trí các nút bấm trên web, ví dụ "Bấm vào để nhận quà". Đâu ai ngờ rằng phía trên nút bấm đó là một nút bấm khác trong iframe. Khá nguy hiểm!

    Nhưng trình duyệt đã có cách ngăn chặn kiểu tấn công này bằng các quy tắc như tiêu đề X-Frame-Options, frame-ancestors của CSP và SameSite: Lax/Strict của Cookies...

    Mới đây, đã xuất hiện thêm kiểu tấn công mới - "DoubleClickjacking" 😨. Đại ý là "hắn" lợi dụng hành động double click để lừa người dùng bấm vào một nút mà hắn muốn. Chi tiết hơn trong bài viết này: DoubleClickjacking: A New Era of UI Redressing.

    » Xem thêm
  • Mọi người đã nghe nói đến Jujutsu - jj - một dạng quản lý phiên bản cho mã nguồn (version control system) chưa? Có vẻ như nó đang nhận được nhiều sự quan tâm.

    Chờ xíu! Chẳng phải git đã quá tốt rồi sao? Thế thì chế ra thằng jj để làm gì nữa? Cũng hơi khó trả lời nhỉ? Mỗi công cụ sinh ra chắc chắn phải cải thiện hoặc khắc phục được nhược điểm của cái trước. Cho nên jj ắt hẳn phải làm được điều gì đó mà git chưa làm được nên mới nổi lên như vậy.

    Thật ra mình đã nghe nói đến jj từ vài tháng trước rồi, nhưng vào đọc thì toàn kiến thức cao siêu. Hoặc là đang mang nặng cái lối suy nghĩ của git vào trong đầu rồi nên chưa lĩnh hội ra được điều gì cả.

    Mình hay có kiểu cái gì đọc lần 1 mà không hiểu thì đọc tiếp lần 2, lần 2 không hiểu thì đọc tiếp lần 3... đến lần thứ n mà vẫn không hiểu thì bỏ. Cơ mà không phải là từ bỏ mà một thời gian sau đó quay lại đọc tiếp. Đến một lúc nào đó khả năng mình sẽ hiểu ra một ít vấn đề, thế mới tài 😆.

    Thì cái jj này có vẻ như nó đang mở ra được tính linh hoạt trong việc "cam kết" mã. Tưởng tượng bạn đang làm việc trên một dự án, đang ở nhánh này, muốn sang nhánh khác để sửa, nhưng mà lại đang viết dở ở nhánh này, thế là phải stash, rồi checkout, rồi commit, rồi merge hoặc rebase lại vào nhánh cũ... nhìn chung quá trình làm việc với git nghiêm ngặt đến mức cứng nhắc, cần nhiều thao tác để giải quyết một vấn đề, chưa kể cái cây commit (commit-tree) nữa thì ôi thôi, khỏi xem cho đỡ nhức mắt. Thế nên ông jj này đang làm cách nào đó để bạn khỏi cần phải quan tâm đến các nhánh luôn, sửa trực tiếp vào commit. Nghe ảo nhỉ 😂.

    Đấy mới lĩnh hội được đến đấy, hy vọng sau n lần đọc lại nữa mình sẽ viết được một bài chi tiết hơn về công cụ này.

    » Xem thêm
  • Gòi gòi tới công chiện gòi 🤤🤤🤤

    » Xem thêm

Vấn đề

Lưu ý: Bài viết dưới đây là những quan điểm cá nhân của tôi về vấn đề xử lý dữ liệu. Điều đó cũng bao gồm những kinh nghiệm của tôi trong các dự án thực tế. Các bạn đọc có thể mang tính chất tham khảo hoặc cũng có thể để lại những ý kiến để mọi người cùng thảo luận nhé.

Ở bài viết trước tôi có giới thiệu cho các bạn một vài cách xử lý dữ liệu thì bài viết ngày hôm nay tôi sẽ tập trung hơn vào việc tôi đã xử lý dữ liệu trong Javascript như thế nào, cũng như cách viết code dễ đọc hơn cho việc bảo trì dự án sau này.

Viết code để chạy được thì nhanh nhưng viết để dễ dàng trong bảo trì sau này đòi hỏi người viết phải có được những kinh nghiệm nhất định, đồng thời việc tổ chức mã, luồng cũng sẽ tốn nhiều thời gian hơn một chút. Thời gian để bảo trì một dự án thường sẽ lớn hơn nhiều so với thời gian để phát hành sản phẩm lần đầu tiên, chưa kể sẽ có những người mới tham gia vào dự án. Vì thế nếu tổ chức mã của bạn tốt sẽ tiết kiệm được kha khá thời gian sau này.

Xử lý dữ liệu là điều thường xuyên trong các chức năng của dự án, các bạn có thể hiểu nó bao gồm các hành động như lọc, ánh xạ, biến đổi dữ liệu trong các tập dữ liệu Array hay Object. 4 kĩ thuật tôi thường hay sử dụng dưới đây góp phần giữ cho code của tôi được rõ ràng hơn.

Bất biến

Bất biến có nghĩa là một khi đã khai báo biến rồi thì tuyệt đối không được thay đổi biến đó nữa. Nếu muốn sửa đổi dữ liệu thì hãy sao chép chúng sang một biến khác. Mới nghe thì có vẻ điều này không hợp lý cho lắm bởi biến trong các ngôn ngữ lập trình được phép thay đổi, gán đi gán lại một cách bình thường. Điều này cũng làm tăng hiệu năng, tiết kiệm bộ nhớ hơn so với việc phải tạo thêm nhiều biến nữa.

Trong Javascript không có định nghĩa kiểu của dữ liệu, việc khai báo một biến với từ khóa var hoặc let giúp cho chúng ta có thể dễ dàng thay đổi dữ liệu hoặc thâm chí là kiểu dữ liệu của nó sau này. Điều này tạo nên sự linh hoạt nhưng tác hại đằng sau sự linh hoạt đó có vẻ là nhiều hơn.

Trong một đoạn mã với hàng chục, hàng trăm dòng code thì việc thay đổi dữ liệu của một biến đôi khi sẽ gây khó khăn trong theo dõi giá trị của biến, bạn sẽ phải phân vân việc liệu giá trị của biến bị thay đổi ở đâu không hay thay đổi những gì... Để giải quyết vấn đề này hãy cố gắng sử dụng khai báo const nhiều nhất có thể, khi sử dụng const bạn sẽ không gán lại giá trị cho biến đó được nữa.

Nhưng mình const là chưa đủ, trong Javascript các kiểu dữ liệu không nguyên thủy như Array, Object... có tính tham chiếu. Dữ liệu đó khi được gán vẫn có thể thay đổi được giá trị của các phần tử, thuộc tính bên trong nó. Vì thế đôi khi chẳng may bạn sửa dữ liệu tham chiếu, các biến khác cũng vô tình bị thay đổi theo. Để tìm hiểu kĩ hơn, các bạn có thể đọc bài viết Đôi điều về Object Reference trong Javascript. Nhiều lúc quên thật phiền toái! của tôi trên estacks.

Thay vì update trực tiếp vào dữ liệu tham chiếu, chúng ta nên sao chép "sâu" (deep copy) dữ liệu có tính chất tham chiếu sang một biến khác để xử lý. Tránh việc thay đổi gây ra những lỗi tiềm ẩn sau này.

Tập trung vào làm gì thay vì làm như thế nào

Để giải thích cho điều này, tôi sẽ lấy một ví dụ về một hàm lấy ra thuộc tính name trong một mảng dữ liệu:

const users = [
  {
    name: "A",
    age: 18
  },
  {
    name: "B",
    age: 19
  },
  {
    name: "C",
    age: 20
  },
];

// cách thứ nhất viết một hàm dùng map để lấy ra name
function usersWithName(users) {
  return users.map(function(user) {
    return {
      name: user.name,
    };
  });
};

// cách thứ hai, vẫn dùng map nhưng ứng dụng curry function
const get = (attribute) => (data) => data[attribute];
const usersWithName = users.map(get("name"));

Trong ví dụ tôi có sử dung Curry function, nếu bạn chưa biết về curry function cũng như ứng dụng của nó thì có thể đọc thêm tại Curry function là gì? Một món "cà ri" ngon và làm sao để thưởng thức nó?.

Trở lại với ví dụ trên, tôi có hai cách viết để cùng đạt được kết quả.

Cách thứ nhất là cách viết thông thường, tôi viết theo dòng suy nghĩ cần phải làm từng bước để có kết quả.

Cách thứ hai, thay vì viết theo dòng suy nghĩ thì tôi tạo ra một hàm get dùng để lấy dữ liệu của thuộc tính trong một object, sau đó đưa nó vào hàm map.

Bằng cách thứ hai, nếu chúng ta tạo thói quen định nghĩa những hàm như get sẽ giúp tạo sự thống nhất trong toàn dự án mặt khác người đọc khi thấy get họ cũng hiểu được đoạn mã đó đang làm gì.

Mã tái sử dụng càng nhiều càng tốt

Hãy cố gắng tạo ra những đoạn mã chỉ tập trung vào một chức năng nào đó sẽ giúp cho mã của bạn có thể tái sử dụng lại. Đồng thời nó cũng tạo sự thống nhất trong toàn dự án, điều đó cũng đồng nghĩa với việc khi bạn thấy nó, bạn có thể biết được nó đang làm gì.

Nhìn vào ví trụ trên ở cách thứ hai, hàm get có thể tái sử dụng nhiều lần, thay vì get("name") tôi có thể get("age")... Hơn nữa mỗi khi nhìn thấy hàm get chúng ta có thể biết ngay là nó "lấy giá trị của thuộc tính" thay vì phải đọc một đoạn code dài như cách một để hiểu được người viết đang muốn làm gì.

Áp dụng những thư viện xử lý dữ liệu phổ biến

Những lợi ích của việc tạo ra những đoạn mã có thể tái sử dụng được nhiều lần đã được cộng đồng phát hiện từ rất lâu về trước. Họ đã tạo ra những thư viện gồm có tập hợp của các hàm giúp chúng ta trong việc xử lý dữ liệu. Một trong số đó có thể kể đến như underscore, lodash, ramda... Chúng cũng được sử dụng rộng rãi trong các dự án trên github, cũng như có số lượng commit và collaborators rất lớn.

Một ví dụ như trong lodash, có đến gần 50 hàm tiện ích để xử lý dữ liệu là Object. Trong đó có cả những hàm tương tự như get ở trong ví dụ trên của tôi và hầu như bạn muốn làm gì cũng có hàm có thể đáp ứng.

Ví dụ tôi sẽ kết hợp các hàm trong lodash để giải quyết ví dụ ban đầu, hơn nữa còn thêm một điều kiện là thứ tự name được lấy ra sắp xếp theo mức độ giảm dần của age:

_.chain(users).orderBy("age", "desc").map("name").value();
Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...
Bấm hoặc cuộn mạnh để sang bài mới