2010-10-26 3 views
8

Tôi muốn làm điều này trong Javascript:Đề cập đến "này" trong một mẹ đóng cửa trong javascript

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    this.b = function() 
    { 
    Z(function() { this.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

Nó có thể được thực hiện theo cách này:

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    var self = this; 
    this.b = function() 
    { 
    Z(function() { self.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

Có cách nào tốt hơn?

Trả lời

6

Giữ một tham chiếu đến phụ huynh (như bạn có) là một phương pháp tốt, tuy nhiên ví dụ cụ thể của bạn không có nhu cầu sử dụng wrapper nặc danh, bạn có thể vượt qua các chức năng trực tiếp, như thế này:

var self = this; 
this.b = function() 
{ 
    Z(self.c); 
} 

You can test it out here, và không có wrapper này có thực sự là không cần cho biến self, quý vị có thể chỉ cần sử dụng trực tiếp this, như thế này:

this.b = function() 
{ 
    Z(this.c); 
} 

You can test that version here.


Vì có vẻ là một số nhầm lẫn trong các ý kiến ​​dưới đây, các mã trên duy trì thischo câu hỏi, nếu bạn muốn duy trì this/bối cảnh bên trong gọi lại là tốt, sử dụng .call()like this:

this.b = function() 
{ 
    Z.call(this, this.c); 
} 

Và đối với Z:

function Z(f) 
{ 
    f.call(this); 
} 

You can test it here.

+0

Đúng vậy, trong ví dụ đơn giản này, không có lý do cho sự wrapper. Nó không phải là khó để thụ thai của một ví dụ mà nó là cần thiết. (Thay đổi các thông số, vv) Nếu bạn không bọc, mặc dù, tôi cho rằng đóng cửa được thông qua như người ta có thể mong đợi? –

+2

không có trình bao bọc ẩn danh, 'c' được gọi với tham chiếu' this' sai. – Lee

+0

@ Jonathan - Vâng, đúng vậy, trong trường hợp đó, bạn muốn chuyển một biến số giống như bạn có 'self' giúp bạn truy cập vào những gì đang đóng. –

1

Có một mẫu thường được gọi là "Ủy quyền", giải quyết vấn đề này.

Trong javascript, một thực hiện không-quá-lạ mắt có thể trông như thế này:

/** class Delegate **/ 
var Delegate = function(thisRef, funcRef, argsArray) { 
    this.thisRef=thisRef; 
    this.funcRef=funcRef; 
    this.argsArray=argsArray; 
} 
Delegate.prototype.invoke = function() { 
    this.funcRef.apply(this.thisRef, this.argsArray); 
} 
/** static function Delegate.create - convenience function **/ 
Delegate.create = function(thisRef, funcRef, argsArray) { 
    var d = new Delegate(thisRef, funcRef, argsArray); 
    return function() { d.invoke(); } 
} 

Trong ví dụ của bạn, bạn sẽ sử dụng nó như thế này:

this.b = function() { 
    Z(Delegate.create(this, this.c)); 
} 

bạn cũng có thể viết các chức năng mong nhận được một Đại biểu:

function Z(d) { 
    d.invoke(); 
} 

sau đó, trong A, impl của bạn của b trở thành:

this.b = function() { 
    var d = new Delegate(this, this.c); 

    Z(d); 
    SomeOtherFunc(d); 
} 

Các Delegate chỉ cung cấp một cách phù hợp đơn giản của việc đóng gói this tài liệu tham khảo (mà bạn đã gọi self), trong một trường hợp đối tượng có thể được xử lý giống như bất kỳ trường hợp đối tượng khác. Đó là dễ đọc hơn, và nó giúp bạn khỏi bị ô nhiễm phạm vi chức năng của bạn với các biến không cần thiết như self. Một thực hiện đại biểu fancier có thể có phương pháp riêng của mình và trạng thái liên quan khác. Nó cũng có thể xây dựng các đại biểu theo cách mà nó giúp giảm thiểu một số vấn đề quản lý bộ nhớ liên quan đến phạm vi (mặc dù mã tôi đã hiển thị ở đây chắc chắn không phải là một ví dụ về điều đó).

+0

Tôi không nghĩ rằng điều này hoạt động: 'Z (function() {Delegate.create (this, c)});'. Nếu không có trình bao bọc, không cần 'self' và không có lý do gì cho Delegate vì nó ngắn hơn để viết' Z (this.c); '. –

+0

@ Jonathan - bạn đã thêm một trình bao bọc phụ không có trong ví dụ của tôi. nó chỉ là 'Z (Delegate.create (this, c))'; Tôi mở rộng ví dụ Delegate một chút để nó linh hoạt hơn và rõ ràng hơn những gì đang diễn ra. – Lee

+0

@Jonathan - 'Z (this.c)' sẽ hoạt động, miễn là bạn không quan tâm đối tượng 'this' tham chiếu khi chạy bên trong' c'. Mã bạn đã hiển thị không sử dụng 'this' từ trong' c', vì vậy nó sẽ không hiển thị bất kỳ vấn đề nào. Nếu bạn kiểm tra (sửa đổi nhỏ ví dụ của Nick @) [http://jsfiddle.net/UQpnX/], bạn sẽ thấy vấn đề tiềm ẩn, được giải quyết bởi trình bao bọc ẩn danh, trong ví dụ ban đầu của bạn - hoặc với một cấu trúc chính thức hơn như Đại biểu. Một trong hai là tốt. – Lee

1

Hoặc bạn có thể sử dụng

this.b = function() 
{ 
    Z((function() { this.c() }).apply(this)); 
}