2016-08-12 20 views
14

Đoạn mã nàyReferenceError trên Google Chrome nhưng không phải trên Firefox (trình duyệt Bug?)

eval(` 
 
    let a = 0; 
 
    function f() {} 
 
    function g() { a; } 
 
    console.log(f); 
 
`);

hoạt động tốt trên Firefox 48,0 trong khi gây Uncaught ReferenceError: f is not defined trên Google Chrome 52.0.2743.116 (64 bit).

Nó cũng hoạt động tốt trên Google Chrome nếu

  • eval không được sử dụng, hoặc
  • mã bên eval được bao quanh với {}, hoặc
  • a không được tham chiếu trong g, hoặc
  • let được đổi thành var hoặc
  • "use strict" được thêm vào trước mã

Điều gì đang xảy ra ở đây? tờ khai

Trả lời

1

Có vẻ như đó là a novel V8 bug! Một trường hợp thử nghiệm tối thiểu hơn là

eval(` 
    var f; 
    let a; 
    ()=>a 
`); 
f; 

tờ khai Variable-scoped (bao gồm tờ khai chức năng cấp cao nhất) đều không nhận được kéo lên đúng cách rời khỏi cuộc gọi không nghiêm ngặt eval khi cuộc gọi cũng có một tuyên bố từ vựng không tầm thường.

2
eval(` 
    "use strict"; 
    let a = 0; 
    console.log(f); 
    function f(){ 
    } 
    function g(){ 
     a; 
    } 
`); 

Block-scoped (let, const, chức năng, lớp) chưa được hỗ trợ chế độ bên ngoài nghiêm ngặt

+1

'let' được hỗ trợ ở chế độ sloppy kể từ Chrome 49.0 theo [MDN] (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/let#Browser_compatibility). – johnchen902

+1

Ah ... Tôi đang sử dụng v47 ... – strah

5

Tinh chỉnh ví dụ của bạn, bạn có thể xem những gì đang xảy ra, và trong khi lệnh là một chút mâu thuẫn, nó trông giống như một con bọ. Xác định a làm chức năng và ghi nhật ký thay vì f, sau đó xem bảng điều khiển. Bạn sẽ thấy rằng việc đóng được tạo bằng a, f và g. Kể từ một được tham chiếu trong g, và f và g sẽ được hiển thị với nhau, nó có ý nghĩa một chút. Nhưng eval hoạt động trong phạm vi toàn cầu. Vì vậy, khi bạn cố gắng truy cập chúng, bạn sẽ không được xác định. Nó giống như đóng cửa này không thể được truy cập từ bất cứ nơi nào.

Hãy thử:

eval('let a = function(){}; function f() {};function g(){a;};console.dir(a);'); 

Bạn sẽ thấy điều này trong bảng điều khiển

<function scope> 
    Closure 
     a: function() 
     f: function f() 
     g: function g() 

Mọi trường hợp khác của bạn khiến tình hình rõ ràng hơn, và ngăn ngừa các vấn đề:

  • eval không được sử dụng: phạm vi sai đối sánh ít rõ ràng hơn,
  • mã bên trong eval được bao quanh với {}: các biến được liên kết thông qua phạm vi Chặn.
  • a không được tham chiếu trong g: không cần đóng cửa nếu các biến không được liên kết.
  • cho thay đổi thành var: var trong phạm vi toàn cầu được xác định trong phạm vi toàn cầu . Vì vậy, không cần thiết Đóng
  • "sử dụng nghiêm ngặt" được thêm vào trước khi mã: use strict trong eval ngăn biến được bổ sung vào phạm vi toàn cầu, vì vậy một lần nữa, "dễ dàng hơn" để xử lý. Không có sự không phù hợp giữa việc cho phép cần thiết để được liên kết với các chức năng toàn cầu.
Các vấn đề liên quan