Vấn đề với việc cố gắng tìm ra môi trường mà mã của bạn đang chạy là bất kỳ đối tượng nào cũng có thể được sửa đổi và tuyên bố khiến nó gần như không thể tìm ra đối tượng nào có nguồn gốc từ môi trường và đã được chương trình sửa đổi.
Tuy nhiên, có một vài thủ thuật chúng ta có thể sử dụng để tìm ra chắc chắn bạn đang ở trong môi trường nào.
Hãy bắt đầu với giải pháp được chấp nhận chung được sử dụng trong thư viện gạch dưới:
typeof module !== 'undefined' && module.exports
Kỹ thuật này thực sự hoàn toàn tốt cho phía máy chủ, vì khi require
hàm được gọi, nó đặt lại this
đối tượng thành một đối tượng trống và xác định lại module
cho bạn một lần nữa, nghĩa là bạn không phải lo lắng về bất kỳ sự giả mạo nào bên ngoài. Miễn là mã của bạn được tải vào require
, bạn an toàn.
Tuy nhiên, điều này sụp đổ trên trình duyệt, vì bất kỳ ai cũng có thể dễ dàng xác định module
để làm cho nó có vẻ như đó là đối tượng bạn đang tìm kiếm. Một mặt đây có thể là hành vi bạn muốn, nhưng nó cũng chỉ ra những biến mà người dùng thư viện có thể sử dụng trong phạm vi toàn cầu. Có lẽ ai đó muốn sử dụng một biến với tên module
có exports
bên trong của nó để sử dụng khác. Không thể, nhưng chúng ta là ai để đánh giá biến người khác có thể sử dụng, chỉ vì môi trường khác sử dụng tên biến đó?
Tuy nhiên, mẹo nhỏ là nếu chúng tôi giả định rằng tập lệnh của bạn đang được tải trong phạm vi toàn cầu (sẽ là nếu nó được tải thông qua thẻ tập lệnh) thì một biến không thể được bảo lưu trong bao đóng bên ngoài, vì trình duyệt không cho phép điều đó . Bây giờ hãy nhớ trong nút, this
đối tượng là một đối tượng trống, tuy nhiên, module
biến vẫn có sẵn. Đó là bởi vì nó được tuyên bố trong một đóng cửa bên ngoài. Vì vậy, sau đó chúng tôi có thể sửa lỗi kiểm tra gạch dưới bằng cách thêm một kiểm tra bổ sung:
this.module !== module
Với điều này, nếu ai đó tuyên bố module
trong phạm vi toàn cầu trong trình duyệt, nó sẽ được đặt trong this
đối tượng, điều này sẽ khiến thử nghiệm thất bại, bởi vì this.module
, sẽ là cùng một đối tượng như mô-đun. Trên nút, this.module
không tồn tại và module
tồn tại trong một bao đóng bên ngoài, do đó thử nghiệm sẽ thành công, vì chúng không tương đương.
Do đó, bài kiểm tra cuối cùng là:
typeof module !== 'undefined' && this.module !== module
Lưu ý: Mặc dù điều này hiện cho phép module
biến được sử dụng tự do trong phạm vi toàn cầu, nhưng vẫn có thể bỏ qua điều này trên trình duyệt bằng cách tạo một bao đóng mới và khai báo module
trong đó, sau đó tải tập lệnh trong bao đóng đó. Tại thời điểm đó, người dùng đang sao chép hoàn toàn môi trường nút và hy vọng biết họ đang làm gì và đang cố gắng thực hiện một kiểu nút yêu cầu. Nếu mã được gọi trong thẻ script, nó sẽ vẫn an toàn trước mọi đóng cửa bên ngoài mới.