JavaScript

Một số lỗi thường gặp trong JavaScript

Một số lỗi thường gặp trong JavaScript
Được viết bởi Minh Hoàng

Series lập trình JavaScript, ngôn ngữ lập trình linh động, thực thi phía client.

Một số lỗi thường gặp trong JavaScript

1. Sử dụng toán tử gán (=), thay vì toán tử so sánh (==) trong câu lệnh if

1. Sử dụng toán tử gán (=), thay vì toán tử so sánh (==) trong câu lệnh if

– Câu lệnh if này trả về false (như mong đợi) vì x không bằng 10:

[code language=”javascript”]var x = 0;
if (x == 10)[/code] Try it »

– Câu lệnh if này trả về true (có thể không như mong đợi), vì 10 là true:

[code language=”javascript”]var x = 0;
if (x = 10)[/code] Try it »

– Câu lệnh if này trả về false (có thể không như mong đợi), bởi vì 0 là false:

[code language=”javascript”]var x = 0;
if (x = 0)[/code] Try it »
2. So sánh các giá trị không cùng một kiểu dữ liệu

2. So sánh các giá trị không cùng một kiểu dữ liệu

– Trong so sánh thông thường (regular comparison), câu lệnh if này trả về true (vì bằng giá trị):

[code language=”javascript”]var x = 10;
var y = "10";
if (x == y)[/code] Try it »

– Trong so sánh nghiêm ngặt (strict comparison), câu lệnh if này trả về false (vì bằng giá trị, nhưng khác kiểu dữ liệu):

[code language=”javascript”]var x = 10;
var y = "10";
if (x === y)[/code] Try it »

– Câu lệnh switch sử dụng so sánh nghiêm ngặt (strict comparison) do đó:

Câu lệnh switch / case này sẽ hiển thị alert (vì bằng giá trị, và cùng kiểu dữ liệu):

[code language=”javascript”]var x = 10;
switch(x) {
case 10: alert("Hello World!");
}[/code] Try it »

Câu lệnh switch / case này sẽ không hiển thị alert (vì bằng giá trị, nhưng khác kiểu dữ liệu):

[code language=”javascript”]var x = 10;
switch(x) {
case "10": alert("Hello World!");
}[/code] Try it »
3. Thực hiện phép tính và ghép nối giá trị khác kiểu dữ liệu

3. Thực hiện phép tính và ghép nối giá trị khác kiểu dữ liệu

– Việc tính toán cộng (addition) là thao tác với kiểu số (Number).

– Việc ghép nối (concatenation) là thao tác với kiểu chuỗi (String).

– Trong JavaScript, cả hai thao tác đều sử dụng toán tử + để thực hiện.

– Do đó, việc thêm một số dưới dạng một số sẽ tạo ra một kết quả khác với việc thêm một số dưới dạng một chuỗi:

[code language=”javascript”]var x = 10 + 5; // return x = 15

var y = 10 + "5"; // return y = "105"[/code] Try it »

– Khi cộng hai biến với nhau, có thể khó dự đoán kết quả, nếu không để ý kiểu dữ liệu của biến khi thao tác:

[code language=”javascript”]var x1 = 10;
var y1 = 5;
var z1 = x1 + y1; // return z1 = 15

var x2 = 10;
var y2 = "5";
var z2 = x2 + y2; // return z2 = 105[/code] Try it »

4. Hiểu sai về Floats

4. Hiểu sai về Floats

– Tất cả các số trong JavaScript được lưu trữ dưới dạng số dấu chấm động 64 bit (Floats).

– Tất cả các ngôn ngữ lập trình, bao gồm JavaScript, gặp khó khăn khi so sánh hay tính toán chính xác các giá trị dấu phẩy động (floating point values):

[code language=”javascript”]var x = 0.1;
var y = 0.2;
var z = x + y // Kết quả của z không phải là 0.3[/code] Try it »

– Để giải quyết vấn đề trên, thực hiện nhân và chia với cơ số 10 tương ứng với phần thập phân sau dấu chấm động:

Ví dụ:
[code language=”javascript”]var z = (x * 10 + y * 10) / 10; // z sẽ bằng 0.3[/code] Try it »
5. Xuống dòng, ngắt dòng một chuỗi String

5. Xuống dòng, ngắt dòng một chuỗi String

– JavaScript sẽ cho phép bạn chia một câu lệnh thành hai dòng:

Ví dụ 1:
[code language=”javascript”]var x =
"Hello World!";[/code]

– Tuy nhiên, xuống dòng / ngắt dòng ở giữa một chuỗi sẽ không được phép (not work):

Ví dụ 2:
[code language=”javascript”]var x = "Hello
World!";[/code] Try it »

– Bạn phải sử dụng dấu backslash \ nếu muốn xuống dòng hay ngắt dòng ở giữa câu lệnh trong chuỗi:

Ví dụ 3:
[code language=”javascript”]var x = "Hello \
World!";[/code] Try it »

Khi viết một câu lệnh JavaScript quá dài, bạn muốn xuống dòng thì vị trí tốt nhất để xuống dòng là sau một toán tử, như cách viết ở Ví dụ 1.

6. Đặt sai vị trí dấu chấm phẩy

6. Đặt sai vị trí dấu chấm phẩy

Vì dấu chấm phẩy bị đặt sai chỗ, nên khối mã lệnh (code block) sẽ thực thi bất kể giá trị của x:

Ví dụ:
[code language=”javascript”]if (x == 19);
{
// code block
}[/code] Try it »
7. Xuống dòng trong câu lệnh return

7. Xuống dòng trong câu lệnh return

– Theo mặc định, JavaScript sẽ tự động close một câu lệnh ở cuối dòng.

– Bởi vì điều này, hai ví dụ sau đây sẽ trả về cùng một kết quả:

Ví dụ 1:
[code language=”javascript”]myFunction(55); // return 550

function myFunction(a) {
var power = 10
return a * power
}[/code]

Ví dụ 2:
[code language=”javascript”]myFunction(55); // return 550

function myFunction(a) {
var power = 10;
return a * power;
}[/code]

– JavaScript cũng sẽ cho phép bạn chia một câu lệnh thành hai dòng.

– Bởi vì điều này, ví dụ 3 cũng sẽ trả về cùng một kết quả:

Ví dụ 3:
[code language=”javascript”]myFunction(55); // return 550

function myFunction(a) {
var
power = 10;
return a * power;
}[/code] Try it »

– Nhưng điều gì sẽ xảy ra nếu bạn xuống dòng trong câu lệnh return như ví dụ 4 sau:

Ví dụ 4:
[code language=”javascript”]myFunction(55); // return undefined

function myFunction(a) {
var
power = 10;
return
a * power;
}[/code] Try it »

– Vì viết như ví dụ 4, JavaScript sẽ nghĩ điều bạn muốn làm là:

[code language=”javascript”]function myFunction(a) {
var
power = 10;
return; // Kết thúc lệnh tại đây
a * power;
}[/code]

Never break a return statement.

8. Truy cập phần tử của mảng bằng Named Indexes

8. Truy cập phần tử của mảng bằng Named Indexes

– Nhiều ngôn ngữ lập trình hỗ trợ các mảng với các chỉ mục index là “name”.

– Một mảng có chỉ mục được đặt tên (named indexes) được gọi là mảng kết hợp / associative arrays (hoặc hashes).

– JavaScript không hỗ trợ các mảng với các named indexes.

– Trong JavaScript, các mảng luôn sử dụng numeric index (key). Chỉ mục (index) không thể là chuỗi hoặc bất kỳ loại dữ liệu nào khác.

Ví dụ:
[code language=”javascript”]var car = [];
car[0] = "Toyota";
car[1] = "Prius 2018";
car[2] = 850;

var x = car.length; // return 3
var y = car[0]; // return Toyota[/code] Try it »

– Nếu bạn sử dụng named indexes, JavaScript sẽ định nghĩa lại (redefine) mảng thành đối tượng tiêu chuẩn (standard object).
– Sau đó, một số phương thức mảng và thuộc tính sẽ tạo ra kết quả không chính xác.

Ví dụ:
[code language=”javascript”]var car = [];
car["brand"] = "Toyota";
car["name"] = "Prius 2018";
car["weight"] = 850;

var x = car.length; // return 0
var y = car[0]; // return undefined[/code] Try it »

9. Kết thúc định nghĩa bằng dấu phẩy

9. Kết thúc định nghĩa bằng dấu phẩy

– Trong ECMAScript 5, dấu phẩy phía sau (trailing commas) trong định nghĩa của các đối tượng và mảng là hợp lệ. Tuy nhiên, ở phần tử cuối thì không nên có dấu phẩy theo sau:

Ví dụ: Object
[code language=”javascript”]var car = {brand:"Toyota", name:"Prius 2018", weight:850,} // Bad
var car = {brand:"Toyota", name:"Prius 2018", weight:850} // Good[/code]

Ví dụ: Array
[code language=”javascript”]var numbers = [40, 100, 1, 5, 25, 10,]; // Bad
var numbers = [40, 100, 1, 5, 25, 10]; // Good[/code]

– Với IE8, nếu ở phần tử cuối có dấu phẩy theo sau thì chương trình sẽ bị crash.
– JSON không cho phép trailing commas.

Ví dụ: JSON
[code language=”javascript”]example1 = {"brand":"Toyota", "name":"Prius 2018", "weight":46}

example2 =
{
"array": [
1,
2,
3
],
"boolean": true,
"color": "#82b92c",
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}[/code]

10. Undefined không phải là Null

10. Undefined không phải là Null

– Trong JavaScript, các objects, variables, properties, và methods có thể là undefined.

– Ngoài ra, giá trị của một đối tượng JavaScript rỗng (empty) có thể là null.

– Điều này có thể gây khó khăn cho việc kiểm tra xem một đối tượng có rỗng (empty) hay không.

– Bạn có thể kiểm tra xem một đối tượng có tồn tại (object exists) hay không bằng cách kiểm tra xem type của nó có phải là undefined hay không.

  • typeof trả về true: nếu đối tượng chưa tồn tại (chưa được khai báo), hoặc đã khai báo mà chưa khởi tạo. Ngược lại trả về false.
Ví dụ:
[code language=”javascript”]// biến myObj1 chưa được khai báo
typeof myObj1 === "undefined"; // true

// biến myObj2 chưa được khởi tạo
var myObj2;
typeof myObj2 === "undefined"; // true

// biến myObj3 được khai báo và khởi tạo
var myObj3 = {};
typeof myObj3 === "undefined"; // false[/code] Try it »

– Nhưng bạn không thể kiểm tra nếu một đối tượng là null, bởi vì sẽ throw ra error nếu đối tượng là undefined:

Ví dụ:
[code language=”javascript”]if (myObj === null) // Error: myObj is not defined[/code] Try it »

– Để giải quyết vấn đề này, bạn phải kiểm tra not undefined trước khi kiểm tra not null:

SAI:
[code language=”javascript”]if (myObj !== null && typeof myObj !== "undefined")[/code]

ĐÚNG:
[code language=”javascript”]if (typeof myObj !== "undefined" && myObj !== null)[/code] Try it »

11. Khối lệnh và giá trị của biến

11. Khối lệnh và giá trị của biến

– JavaScript không tạo ra một phạm vi mới (new scope) cho mỗi khối lệnh (code block).

– Nó là đúng trong nhiều ngôn ngữ lập trình, nhưng không đúng trong JavaScript.

– Với đoạn code sau sẽ hiển thị giá trị của ii là 10, thậm chí khi đã OUTSIDE của khối vòng lặp for():

Ví dụ:
[code language=”javascript”]for (var ii = 0; ii < 10; ii++) {
// some code
}

return ii; // ii = 10[/code] Try it »

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

Translate »