2011-12-23 32 views
5

tôi định nghĩa hai hàm cho mảng:Làm thế nào để gọi bên ngoài "này" trong chức năng bên trong?

Array.prototype.remove = function(obj) { 
    var i = this.length; 
    while (i--) { 
     if (this[i] === obj) { 
      this.removeAt(i); 
     } 
    } 
}; 
Array.prototype.removeAll = function(array2) { 
    array2.forEach(function(item) { 
     this.remove(item); // remove not found!! 
    }); 
} 

Nhưng trong removeAll chức năng, nó báo cáo function remove is not found. Tôi sửa nó như sau:

Array.prototype.removeAll = function(array2) { 
    var outer = this; 
    array2.forEach(function(item) { 
     outer.remove(item); 
    }); 
} 

Nhưng nó xấu xí. Có cách nào tốt hơn?

+0

Tôi không nghĩ nó cực kỳ xấu xí và nó hoạt động. 'Điều này' trong foreach của bạn được thay đổi thành mục trong lần lặp lại, vì vậy tôi không thấy quá nhiều thứ xung quanh nó. – Paddy

Trả lời

6

Chuyển this qua biến khác như bạn làm là cách tiếp cận thành ngữ. Không có gì xấu về nó. (Thông thường, hãy gọi biến số that hoặc self)

1

Function.bind và tương tự.

array2.forEach((function(item) { 
    this.remove(item); 
}).bind(this)); 

Đó không phải là về mặt kỹ thuật như nhau, như trước đây "bên này" bây giờ được shadowed/bị mất (và một hàm wrapper mới được tạo ra), nhưng nó hoạt động độc đáo trong một số ngữ cảnh.

Đối với hầu hết các phần, tôi thích tiêu chuẩn var self = this ...

Mã hóa hạnh phúc.

+0

Theo như tôi biết 'Function.bind' là ECMAScript 5 chỉ hỗ trợ bởi trình duyệt mới nhất (không được hỗ trợ trong IE8, FF3.6, FF3.6, Safari 4, Safari 5, Safari 5.1 và Opera 10.50 - 11.50) –

+0

@StefanGehrig Bạn là chính xác, do đó "và tương tự" :-) Thật dễ dàng để thực hiện một hàm như vậy, và tài liệu MDC cung cấp một ví dụ như vậy. Chức năng tương tự này có thể được tìm thấy trong một số khung công tác. –

+0

Chỉ muốn lưu ý chi tiết quan trọng này ... ;-) –

2

Bằng cách chuyển một đối số tiếp theo tới forEach, sẽ là ngữ cảnh của this trong hàm gọi lại, trong trường hợp của bạn this là đối tượng cửa sổ.

Array.prototype.removeAll = function(array2) { 

    array2.forEach(function(item) { 
     this.remove(item); 
    },this); 
} 
+0

Rất đẹp, tôi không biết điều đó. –

+3

lưu ý rằng điều này không được hỗ trợ trong phiên bản ie8 và phiên bản cũ hơn. –

2

Một thay thế cho việc sử dụng bind (nếu bạn cần hỗ trợ các trình duyệt cũ và không muốn mở rộng Function.prototype) chỉ đơn giản là quấn callback của bạn trong một chức năng immidate và thức ăn this trong như một cuộc tranh cãi như thế này:

Array.prototype.removeAll = function(array2) { 
    array2.forEach(function(outer){ 
    return function(item) { 
     outer.remove(item); 
    };}(this)); 
} 

hoặc bạn có thể viết một hàm tiện ích cà ri đơn giản và sử dụng như thế này

function curry() { 
    var fn = Array.prototype.shift.call(arguments), 
     args = Array.prototype.slice.call(arguments); 
    return function curryed() { 
    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 
    }; 
}; 



Array.prototype.removeAll = function(array2) { 
    array2.forEach(curry(function(item) { 
     outer.remove(item); 
    },this)); 
} 

Nếu bạn không nhớ mở rộng Function.prototype bạn có thể sử dụng liên kết như đã được mô tả bởi những người khác, bạn có thể tìm thấy phần mở rộng khả năng tương thích tuyệt vời trên MDN tại đây: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

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