Các kỹ thuật "eval ()" và "JSON.parse ()" sử dụng các định dạng loại trừ lẫn nhau.
- Với dấu ngoặc đơn "eval ()" là bắt buộc .
- Với dấu ngoặc "JSON.parse ()" bị cấm .
Hãy lưu ý, có các hàm "stringify ()" tạo ra định dạng "eval". Đối với ajax, bạn chỉ nên sử dụng định dạng JSON.
Trong khi "eval" kết hợp toàn bộ ngôn ngữ JavaScript, JSON chỉ sử dụng một tập hợp con nhỏ của ngôn ngữ. Trong số các cấu trúc trong ngôn ngữ JavaScript mà "eval" phải nhận ra là "Câu lệnh khối" (hay còn gọi là "câu lệnh ghép") ; là một cặp hoặc dấu ngoặc nhọn "{}" với một số câu lệnh bên trong. Nhưng dấu ngoặc nhọn cũng được sử dụng trong cú pháp của các đối tượng. Việc giải thích được phân biệt theo ngữ cảnh mà mã xuất hiện. Một cái gì đó có thể trông giống như một đối tượng theo nghĩa đen đối với bạn, nhưng "eval" sẽ xem nó như một câu lệnh ghép.
Trong ngôn ngữ JavaScript, các ký tự đối tượng xuất hiện ở bên phải của một phép gán.
var myObj = { ...some..code..here... };
Các ký tự đối tượng không tự xảy ra.
{ ...some..code..here... } // this looks like a compound statement
Quay trở lại câu hỏi ban đầu của OP, được hỏi vào năm 2008, anh ấy hỏi tại sao phần sau không thành công trong "eval ()":
{ title: "One", key: "1" }
Câu trả lời là nó trông giống như một câu lệnh ghép. Để chuyển đổi nó thành một đối tượng, bạn phải đặt nó vào ngữ cảnh mà câu lệnh ghép là không thể. Điều đó được thực hiện bằng cách đặt dấu ngoặc đơn xung quanh nó
( { title: "One", key: "1" } ) // not a compound statment, so must be object literal
OP cũng hỏi tại sao một tuyên bố tương tự lại đánh giá thành công:
[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]
Câu trả lời tương tự cũng áp dụng - dấu ngoặc nhọn nằm trong ngữ cảnh mà câu lệnh ghép là không thể. Đây là một ngữ cảnh mảng, " [...]
" và các mảng có thể chứa các đối tượng, nhưng chúng không thể chứa các câu lệnh.
Không giống như "eval ()", JSON rất hạn chế về khả năng của nó. Hạn chế là cố ý. Người thiết kế JSON dự định một tập hợp con JavaScript tối giản, chỉ sử dụng cú pháp có thể xuất hiện ở phía bên phải của nhiệm vụ. Vì vậy, nếu bạn có một số mã phân tích cú pháp chính xác trong JSON ...
var myVar = JSON.parse("...some...code...here...");
... điều đó ngụ ý rằng nó cũng sẽ phân tích cú pháp hợp pháp ở phía bên phải của một bài tập, như thế này ..
var myVar = ...some..code..here... ;
Nhưng đó không phải là hạn chế duy nhất đối với JSON. Đặc tả ngôn ngữ BNF cho JSON rất đơn giản. Ví dụ: nó không cho phép sử dụng các dấu ngoặc kép để biểu thị chuỗi (như JavaScript và Perl do) và nó không có cách nào để diễn đạt một ký tự dưới dạng byte (như 'C'). Thật không may, nó cũng không cho phép nhận xét (điều này thực sự tốt khi tạo tệp cấu hình). Mặt trái của tất cả những hạn chế đó là việc phân tích cú pháp JSON nhanh và không có cơ hội cho việc chèn mã (một mối đe dọa bảo mật).
Do những hạn chế này, JSON không được sử dụng cho dấu ngoặc đơn. Do đó, một dấu ngoặc trong chuỗi JSON là một ký tự không hợp lệ.
Luôn sử dụng định dạng JSON với ajax, vì những lý do sau:
- Một đường ống ajax điển hình sẽ được định cấu hình cho JSON.
- Việc sử dụng "eval ()" sẽ bị chỉ trích là một rủi ro bảo mật.
Ví dụ về đường ống ajax, hãy xem xét một chương trình liên quan đến máy chủ Node và máy khách jQuery. Chương trình khách sử dụng một cuộc gọi jQuery có dạng $.ajax({dataType:'json',...etc.});
. JQuery tạo một đối tượng jqXHR để sử dụng sau này, sau đó đóng gói và gửi yêu cầu liên quan. Máy chủ chấp nhận yêu cầu, xử lý yêu cầu và sau đó sẵn sàng phản hồi. Chương trình máy chủ sẽ gọi phương thức res.json(data)
để đóng gói và gửi phản hồi. Quay lại phía máy khách, jQuery chấp nhận phản hồi, tham vấn đối tượng jqXHR được liên kết và xử lý dữ liệu có định dạng JSON. Tất cả đều hoạt động mà không cần chuyển đổi dữ liệu thủ công. Phản hồi không liên quan đến lệnh gọi rõ ràng tới JSON.stringify () trên máy chủ Node và không có lệnh gọi rõ ràng nào đến JSON.parse () trên máy khách; đó là tất cả giải quyết cho bạn.
Việc sử dụng "eval" có liên quan đến rủi ro bảo mật khi đưa mã vào. Bạn có thể nghĩ rằng không có cách nào có thể xảy ra, nhưng các hacker có thể khá sáng tạo. Ngoài ra, "eval" là vấn đề đối với việc tối ưu hóa Javascript.
Nếu bạn thấy mình đang sử dụng một hàm "stringify ()", hãy lưu ý rằng một số hàm có tên đó sẽ tạo chuỗi tương thích với "eval" chứ không phải với JSON. Ví dụ: trong Node, phần sau cung cấp cho bạn hàm tạo chuỗi ở định dạng tương thích "eval":
var stringify = require('node-stringify'); // generates eval() format
Điều này có thể hữu ích, nhưng trừ khi bạn có nhu cầu cụ thể, nó có thể không phải là thứ bạn muốn.