Nó chủ yếu là một vấn đề của phong cách.
Khi var
khai báo tự động hoisted up lên đầu phạm vi, bạn nên đặt chúng ở đầu phạm vi của chúng để bạn có thể đọc mã gần hơn cách trình thông dịch sẽ thực thi nó.
Khai báo biến ở đầu phạm vi của chúng là Crockford's recommendation. Và nó có ý nghĩa như nó làm sáng tỏ một số quan niệm sai lầm phổ biến.
Ví dụ:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
Kể từ var
có chức năng phạm vi, tất cả lặp (và các chức năng bên trong của chúng) tham khảo với cùng i
. Vì tất cả ba hàm thời gian sẽ thực thi sau khi vòng lặp kết thúc, đoạn mã trên ghi nhật ký 3
ba lần.
Bây giờ đối với những người có trải nghiệm phạm vi khối, hành vi trên không rõ ràng. Viết lại đoạn mã:
var i;
for (i = 0; i < 3; i++) {
// ...
}
Hiện tại, i
được khai báo trong phạm vi toàn cục, chính xác như đoạn trước. Tuy nhiên, điều này là rõ ràng hơn về điều đó.
Một quan niệm sai lầm:
(function() {
if (true) {
var foo = 1;
} else {
var foo = 1;
}
}());
Một lần nữa, trong khối scoped languages¹ ở trên là hoàn toàn hợp lệ. Tuy nhiên, như var
tờ khai được treo lên đến đỉnh của phạm vi chức năng hiện tại thời gian phân tích, phía trên là tương đương với:
(function() {
var foo;
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
Biến được khai báo hai lần. Hầu hết các trình duyệt sẽ chỉ bỏ qua khai báo thứ hai và mã sẽ "hoạt động", nhưng các công cụ phân tích mã tĩnh như JSHint sẽ hét lên với bạn.
Bạn có thể viết lại nó chỉ với một lời tuyên bố và nó là hoàn toàn hợp lệ:
(function() {
if (true) {
var foo = 1;
} else {
foo = 1;
}
}());
Nhưng lập trình giống như chứng OCD như tôi sẽ tìm thấy nó khá xấu xí. Vì vậy, một lần nữa, tuyên bố ở trên cùng của phạm vi:
(function() {
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
Dường như gọn gàng hơn nhiều.
Một lần nữa, nó chủ yếu là vấn đề về phong cách. Cá nhân, nếu tôi có một chức năng khổng lồ, tôi ghét để cuộn tất cả các con đường lên chỉ để kiểm tra xem một biến đã được khai báo và thêm nó vào danh sách.Trong trường hợp đó, tôi có thể chỉ cần thêm một vài tờ khai var
ở giữa chức năng (chống lại khuyến cáo của Crockford) mà cá nhân tôi thấy dễ đọc và duy trì hơn.
Vì đây là vấn đề về phong cách, chỉ cần đảm bảo giữ mã của bạn được duy trì và súc tích nhất có thể.
Ở phía bên kia của đồng xu, tôi sẽ thừa nhận rằng, cá nhân tôi, tôi đã bắt đầu và chủ yếu sử dụng var
tờ khai khi biến được sử dụng đầu tiên. Đây là một khía cạnh của ngôn ngữ và bạn có thể sử dụng nó theo cách này mà không gặp vấn đề gì. Nhưng tôi cũng sẽ thừa nhận rằng, nếu tôi đã làm theo các khuyến nghị của Crockford ngay từ đầu, tôi đã có ít đau đầu hơn (như với các quan niệm sai được trình bày ở trên) và sẽ nắm bắt được khía cạnh phạm vi chức năng của JavaScript nhanh hơn nhiều.
¹ Lưu ý rằng JS 1,7 biến khối chỉnh phạm vi giới thiệu qua let
, nhưng nó không được hỗ trợ rộng rãi được nêu ra.
Chủ yếu chỉ là vấn đề về phong cách. Crockford khuyên bạn nên khai báo tất cả các biến ở đầu phạm vi và đôi khi giúp xóa một số quan niệm sai lầm phổ biến (ví dụ: khai báo 'var' bên trong' for' loop thực sự thuộc phạm vi bên ngoài 'for'). –
@ FabrícioMatté Cảm ơn! Thậm chí không nghĩ về các vòng lặp for', nhưng nó có ý nghĩa. – Hendrik