2011-08-30 5 views
9

Tôi đang viết một số mã Actioncript3 cố gắng áp dụng một phương thức cho đối tượng được xác định khi chạy. Tài liệu AS3 cho Function.applyFunction.call đều cho biết đối số đầu tiên cho các hàm đó là đối tượng sẽ được sử dụng làm giá trị 'this' khi hàm được thực hiện.Function.apply không sử dụng tham số nàyArg

Tuy nhiên, tôi đã thấy rằng trong mọi trường hợp khi hàm được thực hiện là phương thức, tham số đầu tiên áp dụng/cuộc gọi không được sử dụng và 'this' luôn đề cập đến đối tượng gốc mà phương thức đó đã bị ràng buộc. Dưới đây là một số ví dụ mã và đầu ra của nó:

package 
{ 
    import flash.display.Sprite;  
    public class FunctionApplyTest extends Sprite 
    { 
     public function FunctionApplyTest() 
     { 
      var objA:MyObj = new MyObj("A"); 
      var objB:MyObj = new MyObj("B"); 

      objA.sayName(); 
      objB.sayName(); 

      objA.sayName.apply(objB, []); 
      objA.sayName.call(objB); 
     } 
    } 
} 

internal class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(_name); 
    } 
} 

Output:

A 
B 
A 
A 

Một thay đổi nhỏ vào mã ở trên để tạo ra một in-line chức năng ẩn danh trong đó đề cập đến 'này' cho thấy đúng hành vi xảy ra khi hàm được áp dụng/gọi không phải là phương thức được ràng buộc.

Tôi có sử dụng áp dụng/gọi không chính xác khi tôi cố gắng sử dụng nó trên phương pháp không? Các tài liệu AS3 đặc biệt cung cấp mã cho trường hợp này, tuy nhiên:

myObject.myMethod.call(myOtherObject, 1, 2, 3); 

Nếu đây thực sự là bị hỏng, là có bất kỳ công việc xung quanh bên cạnh làm cho phương pháp mục tiêu vào chức năng (đó sẽ là khá xấu xí, theo ý kiến ​​của tôi)?

+0

Tôi sẽ phải nói rằng bạn đang làm điều gì đó cực kỳ sai nếu bạn cần loại mã hóa này. Chính xác những gì bạn đang cố gắng thực hiện bằng cách làm điều này? –

+0

Thử nghiệm nó trên đầu của tôi. có vẻ như một lỗi. Hãy thử tìm kiếm trong JIRA: http://bugs.adobe.com/jira/browse và nếu bạn không tìm thấy nó, hãy gửi nó – divillysausages

+0

lỗi không phải ngôn ngữ của nó, nhưng tài liệu viết kém kém –

Trả lời

17

Không phải là "lỗi", nhưng tài liệu cho callapply rất gây hiểu lầm và không thực hiện tốt công việc giải thích những gì đang diễn ra. Vì vậy, đây là một giải thích về những gì đang xảy ra.

Methods khác với Functions trong ActionScript. Methods được định nghĩa là một phần của một lớp học defintion, và các phương pháp luôn luôn bị ràng buộc với trường hợp đó. Xem các phương pháp giây thứ hai của this link. Để trích dẫn từ đó:

Phương thức là các hàm thuộc định nghĩa lớp. Khi một cá thể của lớp được tạo ra, một phương thức được ràng buộc với cá thể đó. Không giống như một hàm được khai báo bên ngoài một lớp, một phương thức không thể được sử dụng ngoài trường hợp nó được đính kèm.

Vì vậy, khi bạn tạo new thể hiện của MyObj, tất cả các phương pháp của nó đều bị ràng buộc với trường hợp đó. Đó là lý do tại sao khi bạn cố gắng sử dụng call hoặc apply, bạn không thấy số this bị ghi đè. Xem phần trên Bound Methods để biết chi tiết.

Xem, this document để được giải thích về đối tượng đặc điểm traits, mà hành động sử dụng để giải quyết các phương pháp và được sử dụng vì lý do hiệu suất đằng sau hậu trường có thể là nguyên nhân. Đó hoặc các phương pháp lớp là đường chỉ là cú pháp cho mô hình ECMAScript sau:

var TestClass = function(data) { 
    var self = this; 
    this.data = data; 
    this.boundWork = function() { 
     return self.constructor.prototype.unboundWork.apply(self, arguments); 
    }; 
}; 

TestClass.prototype.unboundWork = function() { 
    return this.data; 
}; 

Sau đó:

var a = new TestClass("a"); 
var b = new TestClass("b"); 

alert(a.boundWork()); // a 
alert(b.boundWork()); // b 

alert(a.unboundWork()); // a 
alert(b.unboundWork()); // b 

alert(a.boundWork.call(b)); // a 
alert(a.boundWork.call(undefined)); // a 

alert(a.unboundWork.call(b)); // b 

hoặc thậm chí thú vị hơn:

var method = a.unboundWork; 
method() // undefined. ACK! 

Vs:

method = a.boundWork; 
method() // a. TADA MAGIC! 

Lưu ý rằng boundWork sẽ luôn được thực hiện trong ngữ cảnh của cá thể nó thuộc về, bất kể bạn chuyển cho số this với call hoặc apply. Trong ActionScript, hành vi này chính xác là lý do tại sao các phương thức lớp được ràng buộc với cá thể của chúng. Vì vậy, không có vấn đề mà chúng được sử dụng, họ vẫn chỉ vào trường hợp họ đến từ (mà làm cho mô hình sự kiện ActionScript một chút "lành mạnh"). Một khi bạn hiểu điều này, sau đó một công việc xung quanh sẽ trở nên rõ ràng.

Đối với những nơi bạn muốn thực hiện một số phép thuật, tránh các phương pháp cứng dựa trên ActionScript 3 có lợi cho các hàm mẫu thử nghiệm.

Ví dụ, hãy xem xét các mã ActionScript sau:

package 
{ 
    import flash.display.Sprite;  
    public class FunctionApplyTest extends Sprite 
    { 
     public function FunctionApplyTest() 
     { 
      var objA:MyObj = new MyObj("A"); 
      var objB:MyObj = new MyObj("B"); 

      objA.sayName(); 
      objB.sayName(); 

      objA.sayName.apply(objB, []); // a 
      objA.sayName.call(objB); // a 

      objA.pSayName.call(objB) // b <--- 
     } 
    } 
} 

internal dynamic class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(_name); 
    } 

    prototype.pSayName = function():void { 
     trace(this._name); 
    }; 
} 

Chú ý sự khác biệt giữa khai sayNamepSayName. sayName sẽ luôn bị ràng buộc với trường hợp được tạo. pSayName là một chức năng có sẵn cho các phiên bản MyObj nhưng không bị ràng buộc với một phiên bản cụ thể của nó.

Tài liệu cho callapply về mặt kỹ thuật chính xác, miễn là bạn đang nói về nguyên mẫu functions và không phải lớp methods, mà tôi không nghĩ nó đề cập đến chút nào.

+0

Cảm ơn bạn rất nhiều vì đã giải thích điều này, nó đã rất khai sáng! Tôi nghĩ rằng nó có lẽ không phải là trường hợp khai báo phương pháp là cú pháp đường cho ví dụ mã đầu tiên của bạn, bởi vì nếu đó là sự thật thì ClassType.prototype sẽ có các thuộc tính trên nó cho mỗi phương thức không liên kết. Với tôi, có vẻ như đó sẽ là tốt nhất của cả hai thế giới, phần nào tương tự như cơ chế của Python, nơi objA.sayName() là cú pháp đường cho MyObj.sayName (objA). –

1

Wow này là rất đáng ngạc nhiên Oo

Tested nó đứng về phía tôi như tốt và cố gắng để vượt qua trong các thông số như tốt và trong mọi trường hợp, thisArg trôi qua dường như không được sử dụng ở tất cả (có vẻ rõ ràng như một lỗi cho tôi).

Tôi đã phải sử dụng một cái gì đó tương tự nhưng có thêm hạn chế cần truy cập phương pháp mà không tạo một thể hiện của đối tượng (có thể bằng các ngôn ngữ khác nhưng không phải trong AS3> <). Vì vậy, tôi đã kết thúc việc tạo ra các hàm tĩnh và thông qua "thisArg" của riêng tôi.

Vì vậy, làm cho chức năng tĩnh thay vào đó là một cách giải quyết có thể:

static public function SayName(thisArg : MyObj) : void 
{ 
    trace(thisArg._name); 
} 

Not the greatest vì có thể bạn sẽ kết thúc tăng gấp đôi mã như thế này>. <

Ngoài ra, nếu các phương pháp là công khai, bạn có thể lưu tên của chức năng thay vì chức năng và truy cập vào nó là phương pháp bằng cách làm một cái gì đó như:

var funcName : String = "sayName"; 
objB[funcName].apply(null, []); 
objB[funcName].call(null); 

Tuy nhiên, đây là hạn chế tùy thuộc vào phạm vi của bạn phương pháp (phương pháp công cộng có thể được sử dụng như thế này từ khắp mọi nơi, phương pháp nội bộ trong cùng một gói như lớp học của bạn và phương pháp riêng từ bên trong lớp chỉ). Vì vậy, nó là hạn chế hơn so với việc sử dụng thể hiện chức năng thực tế của phương pháp của bạn mà có thể được sử dụng từ bất cứ nơi nào.

Điều này có vẻ như một lỗi khá khó chịu. Tôi hy vọng người khác có giải pháp tốt hơn cho vấn đề này.

1

Bạn đã thử thực sự sử dụng tham chiếu this một cách rõ ràng, tức là:

internal class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(this._name); 
    } 
} 

Nó chỉ có thể là khi từ khóa this được bỏ qua, ví dụ ban đầu được sử dụng để tìm kiếm các lĩnh vực/biến, trong khi những gì thisArg thực sự là tái gắn từ khóa this. Nếu đó là trường hợp nó phức tạp nhất, nhưng nó có thể là giá trị một thử.

+0

+1 'thisArg' không tái hiện liên kết 'this'. Tôi đã tìm thấy tài liệu 'Array' để cung cấp một số [ví dụ tương tự] (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#filter%28%29) của tài liệu này hành vi. – NoobsArePeople2

+0

Có, tôi cũng đã thử sử dụng từ khóa 'này' một cách rõ ràng và không may tìm thấy cùng một hành vi. Tài liệu cho Array.filter được liên kết ở trên rõ ràng nói tham số 'thisArg' phải là null nếu hàm gọi lại là một phương thức, do đó có vẻ như trình triển khai bộ lọc cũng chạy vào vấn đề này. –