Mục lục JavaScript & TypeScript

Docs / JavaScript & TypeScript

Số trong JavaScript

Số có mặt khắp nơi trong game: máu, sát thương, tốc độ, tỉ lệ rơi đồ. JavaScript dùng một kiểu number cho mọi loại số. Trang này nói cách đổi chuỗi sang số, làm tròn, tạo số ngẫu nhiên và cái giá trị kỳ lạ tên là NaN.

Đổi chuỗi sang số

Dữ liệu từ ô nhập liệu, từ URL hay từ split đều là chuỗi. Cộng thẳng thì ra kết quả sai:

const input = "50";
console.log(input + 10); // 5010

Phải đổi sang số trước. Có hai cách hay dùng.

Number() đổi cả chuỗi. Chuỗi có ký tự lạ thì trả về NaN.

console.log(Number("50"));    // 50
console.log(Number("12.5"));  // 12.5
console.log(Number("50hp"));  // NaN
console.log(Number(""));      // 0

parseInt() đọc từ đầu chuỗi, lấy phần số nguyên, gặp ký tự lạ thì dừng.

console.log(parseInt("50hp", 10));  // 50
console.log(parseInt("12.9", 10));  // 12
console.log(parseInt("hp50", 10));  // NaN

Số 10 ở cuối nghĩa là đọc theo hệ thập phân. Nên luôn ghi rõ, để không ai phải đoán.

Chọn cái nào: dữ liệu phải là số sạch (ô nhập điểm) thì dùng Number, sai là biết ngay. Cần lấy số ở đầu chuỗi lẫn chữ thì dùng parseInt. Có số thập phân thì dùng parseFloat.

Làm tròn

Chia số hay ra phần thập phân dài:

const dps = 100 / 3;
console.log(dps); // 33.333333333333336

toFixed(n) giữ n chữ số sau dấu phẩy, dùng để hiện lên màn hình:

console.log(dps.toFixed(1)); // 33.3
console.log(typeof dps.toFixed(1)); // string

Để ý toFixed trả về chuỗi, chỉ để hiển thị. Muốn tính tiếp thì dùng các hàm của Math:

console.log(Math.round(4.5));  // 5
console.log(Math.floor(4.9));  // 4, làm tròn xuống
console.log(Math.ceil(4.1));   // 5, làm tròn lên

Một điều nữa: 0.1 + 0.2 trong JS ra 0.30000000000000004. Không phải lỗi của JS, máy tính nào lưu số thập phân kiểu này cũng vậy. Với máu và vàng, dùng số nguyên cho an toàn.

Sát thương ngẫu nhiên với Math.random

Math.random() trả về một số thập phân từ 0 (có) tới 1 (không bao giờ đạt tới 1).

console.log(Math.random()); // ví dụ 0.7281...

Muốn sát thương ngẫu nhiên từ 10 tới 20, cả hai đầu đều có thể ra:

const min = 10;
const max = 20;
const damage = Math.floor(Math.random() * (max - min + 1)) + min;
console.log(damage); // một số nguyên từ 10 tới 20

Đọc từ trong ra: Math.random() * 11 cho số từ 0 tới dưới 11, Math.floor cắt thành 0 tới 10, cộng min thành 10 tới 20.

Lỗi hay gặp: viết Math.floor(Math.random() * max) và nghĩ nó ra 0 tới 20. Thật ra nó ra 0 tới 19, số 20 không bao giờ xuất hiện. Nhớ phần + 1.

Tỉ lệ chí mạng 25% thì so với 0.25:

const isCrit = Math.random() < 0.25;
console.log(isCrit); // true khoảng 1 trên 4 lần

NaN: không phải là số

NaN (Not a Number) xuất hiện khi phép tính không ra số hợp lệ. Nó vẫn có kiểu number, và lan sang mọi phép tính dính tới nó.

const bonus = Number("nhiều");
console.log(bonus);           // NaN
console.log(typeof bonus);    // number
console.log(100 + bonus);     // NaN

Máu của nhân vật thành NaN thì thanh máu biến mất mà không có lỗi đỏ nào. Để kiểm tra, dùng Number.isNaN. Không dùng ===, vì NaN không bằng chính nó:

console.log(NaN === NaN);         // false
console.log(Number.isNaN(bonus)); // true

Thói quen tốt: đổi dữ liệu người dùng nhập xong thì kiểm tra NaN ngay.

const typed = "abc";
const amount = Number(typed);
if (Number.isNaN(amount)) {
  console.log("Nhập số thôi nhé");
}

Bài tập

Viết code tạo sát thương ngẫu nhiên từ 5 tới 8. Có 20% cơ hội chí mạng, chí mạng thì nhân đôi. In ra Gây X sát thương.

Xem đáp án
const min = 5;
const max = 8;
let damage = Math.floor(Math.random() * (max - min + 1)) + min;

if (Math.random() < 0.2) {
  damage = damage * 2;
}

console.log(`Gây ${damage} sát thương`); // ví dụ: Gây 7 sát thương