Strict mode là biến thể chặt chẽ hơn của JavaScript
JavaScript có lịch sử dài và mang theo nhiều quyết định đáng ngờ: phép gán âm thầm tạo ra biến toàn cục, this đổi nghĩa tùy cách bạn gọi hàm, tham số trùng tên mà vẫn... chạy được. Sửa bất kỳ điều nào trong số đó cũng sẽ làm hỏng web, nên TC39 (ủy ban duy trì ngôn ngữ) chọn một hướng khác: một chế độ tự chọn bật, nơi các góc cạnh sắc nhọn được mài bớt.
Chế độ tự chọn đó gọi là strict mode. Bạn bật nó bằng một dòng duy nhất ở đầu tệp hoặc đầu hàm:
Chạy đoạn này, bạn sẽ gặp ReferenceError: x is not defined. Không có chỉ thị, cùng đoạn code đó vui vẻ tạo ra một biến toàn cục tên x và in ra 10. Cùng một ngôn ngữ, hai bộ quy tắc khác nhau.
Chỉ thị 'use strict'
Chỉ thị này chỉ là một literal chuỗi: 'use strict'; hoặc "use strict";. Nó phải là câu lệnh đầu tiên của script hoặc hàm. Có bất cứ thứ gì đứng trước, dù chỉ là một biểu thức lạc lõng, engine sẽ coi nó là chuỗi bình thường và bỏ qua.
Bạn có thể giới hạn strict mode trong một hàm bằng cách đặt chỉ thị bên trong hàm đó. Thực tế giờ không ai làm vậy nữa: hoặc bạn viết module (mặc định strict), hoặc bật cho cả tệp.
Strict mode thực sự thay đổi những gì
Strict mode không phải một quy tắc mà là cả một gói. Những điểm chính:
- Gán cho biến chưa khai báo sẽ ném lỗi thay vì tạo biến toàn cục.
thisbên trong lời gọi hàm thông thường làundefined, không phải đối tượng toàn cục.- Trùng tên tham số (
function f(a, a) {}) là lỗi cú pháp. - Gán cho thuộc tính chỉ đọc sẽ ném lỗi thay vì thất bại trong im lặng.
- Xóa một biến hoặc hàm thông thường sẽ ném lỗi.
- Một số từ dành riêng cho tương lai (
implements,interface,package,private,protected,public,static,yield) không dùng được làm tên biến.
Đi một vòng nhanh:
Mỗi điều trên đều là "engine phát hiện sớm hơn một lỗi có khả năng xảy ra". Toàn bộ giá trị của strict mode nằm ở đó.
Bug biến toàn cục âm thầm
Đây là lý do lớn nhất khiến strict mode tồn tại. Không có nó, một lỗi gõ sẽ thành biến toàn cục:
// Non-strict mode (don't do this)
function setup() {
usernmae = 'Ada'; // typo - creates window.usernmae
}
setup();
console.log(username); // undefined - the real variable was never set
Chương trình vẫn chạy. Không có lỗi. Bug chỉ lộ ra sau này, khi một chỗ đáng lẽ đọc username lại nhận được undefined. Ở strict mode, cùng lỗi gõ đó ném lỗi ngay khi chạy, và bạn sửa trong vài giây thay vì vài giờ.
JavaScript hiện đại mặc định là strict
Đây là phần hay làm người học bất ngờ: phần lớn JavaScript bạn viết hôm nay đã ở strict mode, dù bạn chưa gõ 'use strict' ở đâu cả.
Hai nguồn lớn tự động bật strict:
- ES module. Mọi tệp
.mjs, mọi<script type="module">và mọi thứ được nạp quaimport/exportđều chạy ở strict mode. Không cần chỉ thị. - Thân class. Mọi câu lệnh bên trong
class { ... }đều strict, kể cả khi tệp bao quanh không strict.
Vậy khi nào bạn thực sự cần tự viết 'use strict';? Chỉ trong script cổ điển: JavaScript kiểu cũ được tải bằng thẻ <script> thông thường, hoặc các tệp Node.js cũ dùng require mà không qua bundler module. Với mọi thứ mới, module đã làm việc đó giúp bạn.
Strict mode thay đổi this trong hàm thông thường
Có một hành vi đáng nhắc riêng vì nó hay làm khó người mới. Ở chế độ thường, gọi một hàm thông thường mà không có đối tượng đứng trước sẽ gắn this vào đối tượng toàn cục (window trong trình duyệt, global trong Node). Ở strict mode, nó gắn vào undefined:
Đó thường là điều bạn muốn. Nếu this là undefined, bug do quên gắn phương thức sẽ lộ ra ngay. Nếu nó âm thầm trỏ tới đối tượng toàn cục, bug sẽ ẩn mình cho tới khi thứ gì đó ở xa hơn bị hỏng.
Những gì strict mode không làm
Strict mode là việc siết chặt lúc biên dịch và lúc chạy: nó không cho bạn kiểu dữ liệu, không bắt lỗi truy cập null, không cảnh báo biến không dùng tới. Đó là việc của TypeScript, ESLint và trình soạn thảo. Hãy coi strict mode là cách sửa một nhóm cạm bẫy cụ thể ở cấp ngôn ngữ, không phải một tấm lưới an toàn toàn diện.
Nó cũng không đồng nghĩa với "JavaScript hiện đại". Bạn vẫn có thể viết code tệ ở strict mode và code xuất sắc mà không có chỉ thị. Nó chỉ khiến một vài lỗi cụ thể khó mắc hơn.
Điều cần nhớ
'use strict';ở đầu tệp hoặc đầu hàm bật một biến thể chặt chẽ hơn của JavaScript.- Lỗi gõ không còn tạo ra biến toàn cục,
thiskhông còn âm thầm trở thành đối tượng toàn cục, và một loạt cạm bẫy khác trở thành lỗi. - ES module và thân
classtự động ở strict mode: bạn hiếm khi phải tự viết chỉ thị. - Mục đích là bắt bug sớm hơn, không phải mở khóa tính năng mới.
Tiếp theo: chú thích
Bạn đã thấy chỉ thị, dấu chấm phẩy và các quy tắc engine quan tâm. Tiếp theo là những ghi chú bạn để lại cho người đọc sau này: chú thích (comment) trong JavaScript hoạt động thế nào và khi nào đáng viết.
Câu hỏi thường gặp
Strict mode trong JavaScript là gì?
Strict mode là một biến thể JavaScript bạn tự chọn bật, biến một số lỗi âm thầm thành lỗi thật. Bạn bật nó bằng cách đặt chuỗi 'use strict'; ở đầu tệp hoặc đầu hàm. Nó siết chặt ngôn ngữ: gán cho biến chưa khai báo sẽ ném lỗi, trùng tên tham số là không hợp lệ, và this trong lời gọi hàm thông thường là undefined thay vì đối tượng toàn cục.
Làm sao bật strict mode trong JavaScript?
Đặt 'use strict'; làm câu lệnh đầu tiên của script hoặc hàm. Chú thích và dòng trống có thể đứng trước nó, nhưng bất kỳ câu lệnh nào khác đứng trước sẽ biến nó thành một chuỗi bình thường, không có tác dụng gì. Trong code hiện đại, bạn hiếm khi phải tự viết: ES module (tệp .mjs hoặc <script type="module">) và thân của mọi class đều tự động ở strict mode.
Vì sao nên dùng strict mode trong JavaScript?
Nó bắt bug sớm hơn. Một lỗi gõ như usernmae = 'Ada' âm thầm tạo ra biến toàn cục ở chế độ thường; ở strict mode nó ném ReferenceError. Strict mode còn giữ chỗ cho các từ khóa tương lai, cấm trùng tên thuộc tính trên các engine cũ và làm this hoạt động dễ đoán, tất cả giúp code dễ hiểu hơn.
JavaScript hiện đại có cần 'use strict' không?
Thường là không. ES module và thân class mặc định đã ở strict mode, và phần lớn dự án hiện đại dùng một trong hai. Bạn chỉ cần tự viết 'use strict'; trong các script cổ điển kiểu cũ, loại được tải bằng thẻ <script> thông thường không có type="module".