+13

['1', '5', '11'].map(parseInt) trả về [1, NaN, 3] trong Javascript: Bài học xương máu về code dễ đọc

Một câu chuyện về tầm quan trọng của việc viết code sạch, dễ hiểu.

ThànhCry, anh chàng lập trình viên tự xưng là thiên tài, luôn tự hào về những đoạn code ngắn gọn và hack não của mình. Dù còn rất mới trong nghề, anh ta luôn tự coi mình giỏi hơn cả team, bướng bỉnh làm theo ý mình, mặc kệ mọi lời khuyên chân thành của đồng nghiệp.

Nhưng rồi ThànhCry sắp phải đối mặt với sự sụp đổ thảm hại của bản thân. Một trải nghiệm đau đớn mà anh sẽ không bao giờ quên.

Mọi chuyện bắt đầu khi ThànhCry và Jake5C được giao nhiệm vụ cho phép người dùng xem sản phẩm trên website thương mại điện tử mà team đang phát triển. Họ vẫn đang trong giai đoạn khởi nghiệp nên tất cả dữ liệu được lưu trữ và cập nhật trong file CSV. Tên sản phẩm, giá cả, số lượng,... y chang mấy thứ bạn thường thấy trên Shopee hay Lazada ấy.

ThànhCry cười khẩy khi biết mình phải hợp tác. "Em không cần làm việc với BẤT KỲ AI hết, OK?", anh ta nói với anh ĐộTộcTrưởng, trưởng nhóm lập trình hiền lành, trong khi gõ máy tính lách cách. "Chỉ cần lấy dữ liệu từ DB và hiển thị trong JSX thôi mà, việc nhỏ!"

"ThànhCry, em cần học cách làm việc nhóm. Anh đã nói bao nhiêu lần rồi", anh ĐộTộcTrưởng đáp lại với nụ cười kiên nhẫn gượng gạo. Anh đã quen với thái độ tự mãn của gã này.

"Em không cần làm việc với ai hết. Em có thể tự làm. Jake5C chỉ làm chậm em lại với mấy thứ vớ vẩn về code dễ đọc thôi."

"Jake5C là một trong những người giỏi nhất của chúng ta và bạn ấy luôn cẩn thận vì lý do chính đáng. Code nhanh hay ngắn gọn không phải là tất cả..."

"Anh lúc nào cũng bảo em làm này làm kia nhưng chẳng bao giờ nghe em cả. Lần này em muốn tự làm một mình thôi, được chứ?", ThànhCry nhanh chóng thêm vào để tránh có vẻ thô lỗ, tất nhiên vẫn giữ nụ cười đểu trên mặt.

Anh ĐộTộcTrưởng thở dài. "Được rồi, anh sẽ cho em làm một mình nếu em có thể chuyển mảng string này", anh viết lên tờ giấy gần đó, "thành mảng số giống hệt vậy."

ThànhCry không thể tin nổi. Trên giấy là một mảng đơn giản.

['1', '5', '11']

Chắc chắn đây là câu hỏi bẫy. Anh ta nhìn anh ĐộTộcTrưởng một cách nghi ngờ.

"Thật á? Anh nghĩ em ngu đến mức không parse nổi cái này sao?"

"Cứ làm đi, em chỉ có một cơ hội thôi." Anh ĐộTộcTrưởng xứng đáng nhận huy chương kiềm chế bản thân vì sự kiên nhẫn phi thường với gã trẻ tuổi này.

Với vẻ mặt tự mãn, ThànhCry mở terminal VS Code mới và gõ lời giải có vẻ hiển nhiên trong Node:

['1', '5', '11'].map(parseInt)

Anh ta cười đắc thắng, chỉ để quay lại và thấy nụ cười hiểu biết trên mặt anh ĐộTộcTrưởng - ThànhCry lập tức bị đánh bại.

"Em chắc chứ ThànhCry? Sao không nhấn Enter xem mảng kết quả thực sự là gì nhỉ?"

Hơi bất an, anh ta quét qua đoạn code ngắn trên terminal để chắc chắn tuyệt đối, trước khoảnh khắc quyết định.

Những gì anh ta thấy tiếp theo làm anh rúng động tận sâu thẳm.

[1, NaN, 3]

Làm thế quái nào mà thế này? parseInt bị hỏng à? map() có bug sao?

ThànhCry hoảng hốt nhìn lên, khiến anh ĐộTộcTrưởng bật cười sắc lẻm đáng sợ.

"ThànhCry, em đã thấy rồi chứ..."

"CÁI GÌ?!", ThànhCry hét lên.

Các bạn thấy đấy, sự sụp đổ của ThànhCry KHÔNG phải do không hiểu map và parseInt, mặc dù hiểu chúng có thể đã giúp ích. Nhưng trong thực tế thì không phải vậy, đa phần chúng ta đều không nhớ hết tất cả các quy tắc và cách hoạt động của các hàm. Khi nào cần thì tra Google, MDN, StackOverflow là xong!

Tuy nhiên lý do ở đây là, ThànhCry quá ám ảnh với việc viết code ngắn nhất có thể, bất chấp tính dễ đọc và rõ ràng...

Thực tế là trong 99% trường hợp, chúng ta dùng map và parseInt kiểu này:

['1', '5', '11'].map(item => parseInt(item))

Nhưng bạn sẽ sốc khi thấy chuyện gì xảy ra nếu dùng map với console.log:

['1', '5', '11'].map(console.log)

Nó log ra 3 cặp số cho mỗi phần tử!

1 0 ['1', '5', '11']
5 1 ['1', '5', '11'] 
11 2 ['1', '5', '11']

Đó là vì callback của map() thực ra nhận 3 đối số:

['1', '5', '11'].map((item, index, array) => {
  console.log(item, index, array)
})

Nên thực ra bạn đang gọi parseInt với 3 đối số:

['1', '5', '11'].map((item, index) => {
  return parseInt(item, index)
})

ThànhCry không hề biết rằng parseInt nhận 1 hoặc 2 đối số và hoạt động khác nhau cho mỗi trường hợp:

Khi có đối số thứ 2, nó trở thành cơ số cho số ở đối số đầu:

parseInt('1', 0) // 1
parseInt('5', 1) // NaN 
parseInt('11', 2) // 3

Dù kiến thức về map và parseInt của anh ta chỉ ở mức trung bình, anh ta đã có thể tránh tất cả những rắc rối này bằng cách code rõ ràng:

['1', '5', '11'].map(item => parseInt(item, 10))

Rút gọn code có thể tuyệt vời để giảm sự lộn xộn, nhưng chúng ta luôn nên ưu tiên code rõ ràng, dễ đọc:

// Khó đọc, khó hiểu
['1', '5', '11'].map(parseInt)

// Rõ ràng, dễ hiểu  
['1', '5', '11'].map(item => parseInt(item, 10))

Đặc biệt là khi độ dài code tăng thêm không đáng kể, đúng không nào?

Vậy đấy các bạn, hãy luôn nhớ viết code sao cho dễ đọc, dễ hiểu nhé. Đừng như anh bạn ThànhCry đáng thương của chúng ta. Một bài học đắt giá về tầm quan trọng của clean code, phải không nào? Hy vọng câu chuyện vui này sẽ giúp các bạn ghi nhớ bài học. Hẹn gặp lại trong những bài viết hài hước và bổ ích tiếp theo nhé! Happy coding!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí