Khi tôi dạy cho các beginner cách lập trình và cho họ làm các bài tập về coding, một trong các thử thách mà tôi yêu thích nhất là: Hãy viết một đoạn code giải quyết vấn đề mà không sử dụng IF (hoặc ternary operators, hoặc switch statements).
Vì sao hữu ích?
Tôi nghĩ rằng thử thách này sẽ ép não của bạn nghĩ khác đi, và trong một vài trường hợp, giải pháp khác sẽ tốt hơn
Không có gì là sai trái khi sử dụng IF cả, nhưng tránh dùng nó đôi lúc sẽ khiến cho code của bạn dễ đọc hơn. Tránh dùng IF rõ ràng không phải là quy tắc chung, việc tránh dùng nó cũng chưa chắc làm cho code của bạn dễ đọc, việc quyết định thuộc về bạn.
Tránh dùng IF không chỉ là về việc dễ hiểu code. Có một khoa học đằng sau vụ này. Hãy xem một vài thử thách bên dưới, không sử dụng IF giúp bạn tiếp cận với code-as-data concept.
Trong tất cả trường hợp, sẽ rất thú vị khi giải quyết vấn đề mà không dùng các điều kiện
Đây là vài ví dụ có dùng IF và không dùng IF. Viết bằng Javascript. Bạn nghĩ cái nào dễ đọc hơn nha:
Thử thách #1: Đếm các số lẻ bên trong một array
Cho 1 array các integer và hãy đếm có bao nhiêu số lẻ
Sau đây là ví dụ:
1 2 3 |
const arrayOfIntegers = [1, 4, 5, 9, 0, -1, 5]; |
Đây là code có IF
1 2 3 4 5 6 7 8 9 10 |
let counter = 0; arrayOfIntegers.forEach((integer) => { const remainder = Math.abs(integer % 2); if (remainder === 1) { counter++; } }); console.log(counter); |
Đây là code không dùng IF
1 2 3 4 5 6 7 8 |
let counter = 0; arrayOfIntegers.forEach((integer) => { const remainder = Math.abs(integer % 2); counter += remainder; }); console.log(counter); |
Trong đoạn code không dùng IF, chúng ta thấy rằng kết quả của biến remainder là data, chúng ta chỉ việc sử dụng data đó trực tiếp
Thử thách #2: Hàm weekendOrWeekday
Viết một function lấy một cái date object argument (như là new Date()) và trả về chuỗi “weekend” or “weekday”.
Đây là code dùng IF
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const weekendOrWeekday = (inputDate) => { const day = inputDate.getDay(); if (day === 0 || day === 6) { return 'weekend'; } return 'weekday'; // Or, for ternary fans: // return (day === 0 || day === 6) ? 'weekend' : 'weekday'; }; console.log(weekendOrWeekday(new Date())); |
Còn đây là code không dùng IF
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const weekendOrWeekday = (inputDate) => { const day = inputDate.getDay(); return weekendOrWeekday.labels[day] || weekendOrWeekday.labels['default']; }; weekendOrWeekday.labels = { 0: 'weekend', 6: 'weekend', default: 'weekday' }; console.log(weekendOrWeekday(new Date())); |
Bạn đã nhận thấy là có vài data bên trong điều kiện IF đúng không? Nó cho ta biết ngày nào là cuối tuần hoặc không phải cuối tuần. Những gì chúng ta làm để tránh dùng IF là extract những data đó vào một object và sử dụng nó trực tiếp luôn.
Thử thách #3: Viết hàm xàm xí
Viết một function có chức năng xàm xí, dựa trên type của input, yêu cầu như sau:
- Khi input là number, double lên(ví dụ 5 => 10, -10 => -20)
- Khi input là string, lặp lại mỗi ký tự (ví dụ 'hello' => 'hheelloo')
- Khi input là 1 function, gọi nó 2 lần
- Khi input là 1 array, gọi từng phần tử bên trong array
- Khi input là 1 object, gọi từng value của object đó
Đây là code dùng switch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
const doubler = (input) => { switch (typeof input) { case 'number': return input + input; case 'string': return input .split(') .map((letter) => letter + letter) .join('); case 'object': Object.keys(input) .map((key) => (input[key] = doubler(input[key]))); return input; case 'function': input(); input(); } }; console.log(doubler(-10)); console.log(doubler('hey')); console.log(doubler([5, 'hello'])); console.log(doubler({ a: 5, b: 'hello' })); console.log( doubler(function() { console.log('call-me'); }), ); |
Đây là code không dùng switch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
const doubler = (input) => { return doubler.operationsByType[typeof input](input); }; doubler.operationsByType = { number: (input) => input + input, string: (input) => input .split(') .map((letter) => letter + letter) .join('), function: (input) => { input(); input(); }, object: (input) => { Object.keys(input) .map((key) => (input[key] = doubler(input[key]))); return input; }, }; console.log(doubler(-10)); console.log(doubler('hey')); console.log(doubler([5, 'hello'])); console.log(doubler({ a: 5, b: 'hello' })); console.log( doubler(function() { console.log('call-me'); }), ); |
Một nần nữa, chúng ta thấy data được extract ra khỏi switch đưa vào object. Sau đó object được dùng để chọn cách vận hành đúng và invoke nó với input ban đầu.
Bạn thấy thế nào về các ví dụ trên? Bạn có đồng tình hay phản đối 2 cái coding style trên?
Nếu có vài ly cafe, tôi sẽ viết thêm về việc coding mà không dùng loop. Cám ơn vì đã đọc!
TechTalk via Tourist Đệ Quy