2010-04-15 36 views
6

Tôi có đoạn mã này:JavaScript biểu thức chính quy vẫn tồn tại theo nghĩa đen giữa chức năng gọi

function func1(text) { 

    var pattern = /([\s\S]*?)(\<\?(?:attrib |if |else-if |else|end-if|search |for |end-for)[\s\S]*?\?\>)/g; 

    var result; 
    while (result = pattern.exec(text)) { 
     if (some condition) { 
      throw new Error('failed'); 
     } 
     ... 
    } 
} 

này hoạt động, trừ trường hợp tuyên bố ném được thực thi. Trong trường hợp đó, lần sau tôi gọi hàm, lệnh exec() bắt đầu từ khi nó dừng lại, mặc dù tôi đang cung cấp nó với một giá trị mới của 'văn bản'.

Tôi có thể sửa lỗi bằng cách viết

var pattern = new RegExp ('.....');

thay vào đó, nhưng tôi không hiểu tại sao phiên bản đầu tiên bị lỗi. Biểu thức chính quy tồn tại như thế nào giữa các cuộc gọi hàm? (Điều này đang xảy ra trong các phiên bản mới nhất của Firefox và Chrome.)

Sửa Hoàn thành kiểm tra trường hợp:

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Test Page</title> 
<style type='text/css'> 
body { 
    font-family: sans-serif; 
} 
#log p { 
    margin:  0; 
    padding: 0; 
} 
</style> 
<script type='text/javascript'> 
function func1(text, count) { 

    var pattern = /(one|two|three|four|five|six|seven|eight)/g; 

    log("func1"); 
    var result; 
    while (result = pattern.exec(text)) { 
     log("result[0] = " + result[0] + ", pattern.index = " + pattern.index); 
     if (--count <= 0) { 
      throw "Error"; 
     } 
    } 
} 

function go() { 
    try { func1("one two three four five six seven eight", 3); } catch (e) { } 
    try { func1("one two three four five six seven eight", 2); } catch (e) { } 
    try { func1("one two three four five six seven eight", 99); } catch (e) { } 
    try { func1("one two three four five six seven eight", 2); } catch (e) { } 
} 

function log(msg) { 
    var log = document.getElementById('log'); 
    var p = document.createElement('p'); 
    p.innerHTML = msg; 
    log.appendChild(p); 
} 

</script> 
</head> 
<body><div> 
<input type='button' id='btnGo' value='Go' onclick='go();'> 
<hr> 
<div id='log'></div> 
</div></body> 
</html> 

Các biểu hiện thường xuyên tiếp tục với 'bốn' như các cuộc gọi thứ hai trên FF và Chrome, không phải trên IE7 hoặc Opera.

+1

Tôi đã tự do đăng một bài kiểm tra đầy đủ, đơn giản, hy vọng bạn không phiền. Tôi đã nhìn thấy hành vi này là tốt và tự hỏi tại sao nó sẽ được. Nó trông và có mùi giống như một con bọ, nhưng sau đó, đôi khi mọi thứ rất tinh tế, và thật đáng ngạc nhiên khi cả FF và Chrome sẽ có nó cho các công cụ Javascript hoàn toàn khác nhau của họ *. –

+0

Chỉ cần rõ ràng, nó hoạt động miễn là lỗi/ngoại lệ không được ném, nhưng nếu 'một số điều kiện' trở thành sự thật và ngoại lệ được ném, thì hàm sẽ thất bại trong lời gọi tiếp theo vì mẫu tiếp tục từ đó ngoại lệ đã được ném? Điều đó chắc chắn giống như một con bọ không nằm trong tầm tay bạn. – PatrikAkerstrand

Trả lời

7

RegExp đối tượng được tạo bằng phương tiện của một regex literal được lưu trữ, nhưng new RegExp luôn tạo một đối tượng mới. Các đối tượng được lưu trữ cũng lưu trạng thái của chúng, nhưng các quy tắc điều chỉnh khía cạnh đó dường như không rõ ràng lắm. Steve Levithan nói về điều đó trong this blog post (gần phía dưới cùng).

+0

Blog cho biết nó sẽ được sửa trong Firefox 3.7 (và tôi đang sử dụng 3.6.3). Tôi nghĩ rằng tôi sẽ chỉ ngừng sử dụng RE literals, như một giải pháp cross-browser cho hành vi này. –

+0

Tuyệt vời, cảm ơn. Lưu ý rằng "... được lưu trong bộ nhớ cache ..." nên được "... * được * lưu vào bộ nhớ cache bởi một số triển khai như của phiên bản ECMAScript thứ 3 ..." theo sau là tuyên bố rằng chúng có thể không còn được lưu vào bộ nhớ cache theo thông số mới nhất (may mắn!). –

+0

@Charles: Nếu bạn ngừng sử dụng literals, bạn đang ở trong một thế giới bị tổn thương với quy tắc thoát. :-) Chỉ cần thiết lập lại 'lastIndex' trước khi sử dụng (trừ khi bạn cũng muck về với cờ khác sau khi instantiation). Và vui mừng vì thông số kỹ thuật mới nhất đã khắc phục được chút ngớ ngẩn này. –

0

Tôi không biết câu trả lời, nhưng tôi sẽ đánh bạo đoán:

Khái niệm theo nghĩa đen đó là mô hình có phạm vi toàn cầu, và được đánh giá (vào một đối tượng RegExp) chỉ một lần, trong khi đó nếu bạn sử dụng new Regexp đối số của nó vẫn là toàn cầu, nhưng chỉ là một chuỗi, không phải là một RegExp.

+0

@Colin: Ngoại trừ nó * không * có phạm vi toàn cục, nhiều hơn đối tượng trong 'var x = {};' có phạm vi toàn cục. Đó cũng là một chữ, nhưng bạn sẽ nhận được các đối tượng khác nhau trên mỗi lời gọi hàm. –

1

Tôi sẽ đi ra ngoài một chi ở đây: Tôi nghĩ rằng hành vi bạn đang thấy là một lỗi trong công cụ Javascript của FF và Chrome (dị giáo!). Đáng ngạc nhiên là nó sẽ xảy ra trong hai động cơ khác nhau như vậy, mặc dù. Có vẻ như lỗi tối ưu hóa. Cụ thể, phần 7.8.5 của the spec nói:

Một biểu thức chính quy là phần tử đầu vào được chuyển đổi thành đối tượng RegExp (xem 15.10) mỗi lần được đánh giá theo thứ tự chữ.

Phòng lung lay duy nhất tôi thấy nằm trong cụm từ "..thời gian theo nghĩa đen được đánh giá" (nhấn mạnh của tôi). Nhưng tôi không hiểu tại sao các đối tượng gây nên kỳ diệu giữ lại bất kỳ hơn bất kỳ đối tượng khác theo nghĩa đen, như:

function func1() { 
    var x = {}; 
    return x; 
} 

Ở đó, cuộc gọi tiếp theo để func1 sẽ cung cấp cho bạn biệt đối tượng. Do đó tôi nói nó trông giống như một lỗi đối với tôi.

Cập nhật Alan Moore points to một article by Steve Levithan trong đó Levithan cũng tuyên bố rằng ECMAScript 3rd edition đặc điểm kỹ thuật phép loại bộ nhớ đệm. May mắn thay, nó không được phép như của ECMAScript 5th edition (spec tôi đã làm việc từ) và do đó, sẽ là một lỗi Real Soon Now. Cảm ơn Alan!

Các vấn đề liên quan