2010-06-14 50 views
59

Tôi đang làm việc để làm cho tất cả các mã JS của chúng tôi đi qua jslint, đôi khi với rất nhiều tinh chỉnh với các tùy chọn để lấy mã kế thừa ngay bây giờ với mục đích sửa lỗi chính xác sau này.Cách sửa lỗi jslint 'Không thực hiện các chức năng trong vòng lặp.'?

Có một điều mà jslint phàn nàn về việc tôi không có workround cho. Đó là khi sử dụng các cấu trúc như thế này, chúng tôi nhận được lỗi 'Không thực hiện các chức năng trong vòng lặp.'

for (prop in newObject) { 
    // Check if we're overwriting an existing function 
    if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" && 
     fnTest.test(newObject[prop])) { 
     prototype[prop] = (function(name, func) { 
      return function() { 
       var result, old_super; 

       old_super = this._super; 
       this._super = _super[name]; 
       result = func.apply(this, arguments); 
       this._super = old_super; 

       return result; 
      }; 
     })(prop, newObject[prop]); 
    } 
} 

Vòng lặp này là một phần của một thực hiện JS thừa kế cổ điển mà các lớp học mở rộng các lớp học hiện có giữ lại các tài sản của các lớp mở rộng siêu khi gọi một thành viên của lớp mở rộng. Chỉ cần làm rõ, việc thực hiện ở trên được lấy cảm hứng từ điều này blog post bởi John Resig.

Nhưng chúng tôi cũng có các phiên bản khác của các hàm được tạo trong vòng lặp.

Cách giải quyết duy nhất cho đến nay là loại trừ các tệp JS này khỏi jslint, nhưng chúng tôi muốn sử dụng jslint để xác thực mã và kiểm tra cú pháp như một phần của quá trình tích hợp liên tục và xây dựng quy trình làm việc của chúng tôi.

Có cách nào tốt hơn để triển khai các chức năng như thế này hay có cách nào để tinh chỉnh mã như thế này thông qua jslint không?

Trả lời

64

Douglas Crockford có một cách thành ngữ mới để đạt được điều này - kỹ thuật cũ của ông là sử dụng một hàm bên trong để liên kết các biến, nhưng kỹ thuật mới sử dụng một trình tạo hàm. Xem slide 74 in the slides to his "Function the Ultimate" talk. [SlideShare này không còn tồn tại]

Đối với lười biếng, đây là mã:

function make_handler(div_id) { 
    return function() { 
     alert(div_id); 
    }; 
} 
for (i ...) { 
    div_id = divs[i].id; 
    divs[i].onclick = make_handler(div_id); 
} 
+20

Làm thế nào là một "nhà sản xuất chức năng" bất kỳ tốt hơn so với việc tạo ra một chức năng mới cho mỗi vòng lặp lặp? Nó không giống nhau sao? – Gili

+11

@Gili: Mã để tạo hàm make_handler được thực thi tại điểm nó nói 'function make_handler (div_id)'. Khi bên trong vòng lặp 'for',' make_handler' bây giờ là tham chiếu đến hàm đó và không được tạo lại cho mỗi lần lặp của vòng lặp. –

+0

Sẽ không hiệu quả hơn khi phân bổ chức năng này thành một var – Pascalius

7

JSLint chỉ là hướng dẫn, bạn không phải luôn tuân thủ các quy tắc. Vấn đề là, bạn không tạo ra các hàm trong một vòng lặp theo nghĩa mà nó đề cập đến. Bạn chỉ tạo các lớp học của bạn một lần trong ứng dụng của bạn, không phải hơn và hơn nữa.

+1

Tôi biết JSLint mà chỉ là một recomendation và rằng nó được dự định sẽ được sử dụng để phát hiện xấu Mã JS, nhưng nó vẫn là một công cụ tốt để sử dụng trước khi đủ điều kiện và kiểm tra tính bảo mật của bạn trong môi trường xây dựng/thử nghiệm tự động. Như tôi đã viết, tôi quan tâm đến cách giải quyết để làm cho mã vượt qua jslint, không tránh chạy jslint cả. – Ernelli

+11

Chắc chắn, nhưng nếu bạn nhìn vào câu trả lời dưới đây, bạn vẫn đang thực hiện một chức năng trong một vòng lặp. Bạn đang thêm mã bổ sung chỉ để xoa dịu JSLint. Tại sao bạn sẽ làm điều này? –

+1

Có, tôi vẫn thực hiện các chức năng trong vòng lặp, vấn đề của tôi là tôi muốn mã này vượt qua jslint. Bây giờ Skilldrick và Matt Eberts đã cho tôi giải pháp làm việc mà tôi đã thử nghiệm và bây giờ mã của tôi cả hai công trình và vượt qua jslint. Tôi là một lập trình viên C/C++ cũ, tôi được sử dụng để kiểm tra cú pháp như là một phần của giai đoạn biên dịch. Javascript thiếu biên dịch, jslint là gần như bạn nhận được để sử dụng một trình biên dịch c/C++ hiện đại với các cảnh báo. – Ernelli

3

Chỉ cần di chuyển của bạn:

(function (name, func) {...})()

khối ra khỏi vòng lặp và gán nó vào một biến, như:

var makeFn = function(name, func){...};

Sau đó, trong vòng có:

prototype[prop] = makeFn(...)

+1

Bạn thực sự nên học cách định dạng câu trả lời của mình tốt hơn một chút. Tôi sẽ chỉnh sửa cái này cho bạn. – TheCarver

11

(Tôi chỉ cần stumbled về các vấn đề này trong nhiều tháng sau khi nó đã được đăng ...)

Nếu bạn tạo một hàm trong một vòng lặp, một thể hiện của một hàm được tạo ra cho mỗi lần lặp của vòng lặp. Trừ khi chức năng đang được tạo ra là khác nhau cho mỗi lần lặp, sau đó sử dụng phương pháp đặt trình tạo hàm ngoài vòng lặp - làm như vậy không chỉ là Crockery, nó cho phép những người khác đọc mã của bạn biết rằng đây là ý định của bạn .

Nếu hàm thực sự là hàm được gán cho các giá trị khác nhau trong một lần lặp (hoặc đối tượng được tạo lặp lại), thì thay vào đó bạn cần gán hàm cho biến được đặt tên và sử dụng hàm duy nhất đó của hàm trong nhiệm vụ trong vòng lặp:

handler = function (div_id) { 
    return function() { alert(div_id); } 
} 

for (i ...) { 
    div_id = divs[i].id; 
    divs[i].onclick = handler(div_id); 
} 

Greater bình luận/thảo luận về vấn đề này đã được thực hiện bởi những người khác thông minh hơn tôi khi tôi đặt ra một câu hỏi tương tự ở đây trên stack Overflow: JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself

đối với JSLint: Vâng, nó là một giáo điều d thành ngữ. Điều đó nói rằng, nó thường là "đúng" - tôi phát hiện ra rằng nhiều người hát theo cách tiêu cực về JSLint thực sự không hiểu (sự tinh tế của) Javascript, vốn rất nhiều và ngớ ngẩn.

+0

vui lòng thêm các biến cho các biến (trình xử lý, div_id). –

+1

khi bạn gọi trình xử lý (div_id), bạn thực sự chạy hàm sẽ hiển thị cảnh báo. Điều này sẽ xảy ra khi chạy và không khi người dùng nhấp vào div. –

+1

Trong khi không có vars khai báo, đây là mã giả ... cũng khi bạn gọi trình xử lý (div_id); nó trả về một hàm, nó sẽ không chạy cảnh báo cho đến khi được bấm trong ví dụ này. Dưới đây là một ví dụ đầy đủ: http://jsfiddle.net/scottux/RWCje/ – Scottux

5

Nếu bạn đang sử dụng JQuery, bạn có thể muốn làm một cái gì đó như thế này trong một vòng lặp:

for (var i = 0; i < 100; i++) { 
    $("#button").click(function() { 
    alert(i); 
    }); 
} 

Để đáp ứng JSLint, một cách để làm việc xung quanh này là (trong JQuery 1.4.3+) để sử dụng thêm đối số dữ liệu xử lý để .click():

function new_function(e) { 
    var data = e.data; // from handler 
    alert(data); // do whatever 
} 

for (var i = 0; i < 100; i++) { 
    $("#button").click(i, new_function); 
} 
7

theo nghĩa đen, có xung quanh vấn đề bằng cách làm như sau:

  1. Tạo một file .jshintrc
  2. Thêm dòng sau vào tập tin .jshintrc bạn

    {"loopfunc" : true, // tolerate functions being defined in loops }

+1

Bỏ phiếu xuống này là hoàn toàn vô lý! – lifebalance

+0

Tôi thấy quan điểm của bạn. Nếu bạn đặt câu hỏi theo nghĩa đen thì đó là câu trả lời đúng. Bỏ phiếu xuống là bởi vì tôi nghĩ rằng đó là lời khuyên xấu. Bất cứ ai hỏi câu hỏi này cần phải được giáo dục để thay thế. SO không cho phép tôi hoàn nguyên phiếu bầu của mình trừ khi câu trả lời được chỉnh sửa ... –

+0

@ThijsKoerselman Tôi đã chỉnh sửa nó ngay bây giờ ... – lifebalance

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