2012-02-16 47 views
10

tôi tìm thấy một cái gì đó rất kỳ quặc hôm nay: Nếu bạn tạo đối tượng với một hàm constructor và new từ khóa, nhưng return một chức năng từ các nhà xây dựng, nó hoạt động như vậy:Sử dụng 'trở lại' khi tạo đối tượng với 'mới'

  1. Đối tượng mới được tạo thay vào đó là hàm.
  2. Đó chức năng mới có thể được gọi như bình thường, tuy nhiên ...
  3. Nếu bạn duy trì một tham chiếu đến this trong hàm constructor, tài liệu tham khảo this một đối tượng được tạo ra một cách chính xác từ các nhà xây dựng. Đó là những gì bạn dự kiến ​​sẽ được trả lại từ new.

Dưới đây là một ví dụ:

function Constructor() { 
    var self = this; 

    this.name = 'instance'; 
    return function() { 
    return self; 
    } 
} 

Vì vậy, nếu bạn khởi tạo nó như thế này: var instance = new Constructor() Sau đây sẽ cho kết quả:

typeof instance //returns "function" 
typeof instance() //returns "object" 
instance()   //returns { name: 'instance' } 

Vì vậy, tôi đoán tôi có ba câu hỏi sau:

  1. Điều này có hợp pháp không? k trình duyệt chéo? Nó thực sự tuyệt vời và tôi nghĩ nó có thể được sử dụng theo nhiều cách, nhưng hành vi này có đáng tin cậy không?
  2. Điều gì xảy ra trong nền gây ra hành vi này?
  3. (có thể được trả lời bởi 2, nhưng ...) Là đối tượng mới (đối tượng được tham chiếu với 'this') bên trong phiên bản mới, sao cho tất cả đều được khép kín và được dọn sạch bởi bộ thu gom rác?
+0

Thật sai khi trả lại bất kỳ thứ gì từ một hàm tạo, cuối cùng tôi nghe thấy. –

Trả lời

7
  1. Vâng, trong khi một constructor mặc định trả về đối tượng mới được xây dựng (được tham chiếu bởi this), bạn có thể ghi đè lên rằng trở lại giá trị miễn là bạn trả về một đối tượng. Bởi vì một hàm là một đối tượng, bạn có thể trả về nó như bạn đang ở trong ví dụ của bạn. Đối tượng mới được tạo là không phải là một hàm, mà hàm trả về của bạn tham chiếu đối tượng mới được tạo trong phạm vi biến của nó.

  2. Xem # 1

  3. Điều này là do một chức năng tạo ra một đóng cửa, vì vậy nó tiếp tục tham khảo các self biến, trong đó xảy ra để tham khảo các đối tượng thực tế đang được xây dựng. Vì vậy, tôi sẽ không hoàn toàn nói rằng nó "bên trong" bất cứ điều gì, mà đúng hơn là chỉ là một phần của phạm vi biến của hàm.

Điều cần hiểu là chức năng của bạn không khác bất kỳ chức năng nào khác. Cũng giống như nếu bạn đã trả lại một Array, bạn chỉ cần có một Array thông thường, có thể tham khảo đối tượng mới.

function Constructor() { 

    this.name = 'instance'; 
    return [ this ]; // Instead return an Array that references the new object 
} 
+0

Tôi hiểu rồi! Vì vậy, biến "dụ" trong ví dụ của tôi là một * đóng *, không phải là một hàm bình thường? Và đóng cửa đó chứa cả hàm trả về và đối tượng instantiated, có thể được truy cập bằng "this"? –

+2

@KevinMcTigue: Vâng, tất cả các chức năng đều đóng. Nó chỉ đơn giản là một phần của việc thực thi nội bộ các hàm trong JavaScript. Điều gì làm cho một hàm đóng cửa là nó có một tham chiếu vĩnh viễn đến phạm vi biến ban đầu mà nó được tạo ra. Vì vậy, bạn chỉ cần trả về một hàm cũ đơn giản, hoạt động đúng như bất kỳ hàm nào khác, ở chỗ nó không mất đi phạm vi biến * (bao gồm biến 'self', tham chiếu đối tượng mới của bạn) *. –

2

Vâng, đó là một câu hỏi thực sự tốt và, như bạn có thể đã đoán, không dễ dàng trả lời.

Để đặt nó rất đơn giản:
1) Có và Có; đây là một trong những tính năng tuyệt vời mà bạn không tìm thấy trong các ngôn ngữ lập trình "truyền thống".
2) xin vui lòng đọc về việc đóng cửa (liên kết bên dưới)
3) Có (xin đọc thêm)

Bạn nên đọc thêm về Javascript đóng cửa: http://jibbering.com/faq/notes/closures/
http://www.javascriptkit.com/javatutors/closures.shtml (ở đây bạn có một số ví dụ làm việc tốt)

và, đặc biệt hơn, mô hình thừa kế ký sinh trùng:
http://blog.higher-order.net/2008/02/21/javascript-parasitic-inheritance-power-constructors-and-instanceof/

tôi hy vọng điều này sẽ giúp

+0

Cảm ơn các liên kết. Cái thứ hai rất thú vị. Tôi đã học được một thuật ngữ mới hôm nay: Power Constructor –

1

đây là những gì bạn gọi một closure

những gì nó làm là tạo ra một môi trường đang khép kín (thường được gọi là một đối tượng)

typeof instance //returns "function" - since it's not "fired" or called. just returns the function declaration (correct me if i'm wrong) 
typeof instance() //returns "object" - it returns an object since you called it 
instance()   //returns an object also - you called it, but you didn't store it 

một ví dụ về một đối tượng được xây dựng sử dụng đóng cửa:

function Constructor() { 
    var privateProperty = 'private'; 
    var privateMethod = function(){ 
     alert('called from public method'); 
    }; 

    //return only what's to be seen in public 
    return { 
     publicProperty: 'im public', 
     publicMethod: function(){ 
      alert('called from public method'); 
     } 
     getter: privateMethod //assign to call the private method 
    } 
} 

var myObj = Constructor(); 
var pubProp = myObj.publicProperty; // pubProp = 'im public' 
myObj.publicMethod()    //alert: 'called from public method'; 
myObj.getter()      //alert: 'called from public method'; 

//cannot access since "private": 
myObj.privateProperty 
myObj.privateMethod 
+1

_ "những gì nó làm là tạo ra một môi trường mã khép kín (thường được gọi là một đối tượng)" _ - Thường được gọi là "đóng cửa". Nó không phải là một "đối tượng", ít nhất là không có nghĩa là một đối tượng JS. Ngoài ra, nếu hàm của bạn trả về một đối tượng một cách rõ ràng thì không phải là cách hay để gọi nó bằng 'new' vì đó là gây hiểu lầm - nếu sử dụng' new' bạn mong đợi kết quả là một thể hiện của 'Constructor'. – nnnnnn

+0

Theo trang MDN trên bao đóng: * "Một đóng là một loại đối tượng đặc biệt kết hợp hai thứ: một hàm và môi trường mà chức năng đó đã được tạo ra." * –

+1

@nnnnnn tôi chỉ giải thích một cách đơn giản. mặc dù nó không phải là không an toàn, nó phổ biến sử dụng nó để mô phỏng một đối tượng (có tài sản riêng và công cộng). đối với 'mới' .. tôi không biết về điều đó. – Joseph

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