2009-12-30 66 views
83

Các trường hợp chính xác mà câu lệnh trả về trong Javascript có thể trả lại giá trị khác hơn this khi một hàm tạo được gọi bằng cách sử dụng từ khóa new là gì?Giá trị nào mà một hàm khởi tạo có thể trả về để tránh trả lại giá trị này?

Ví dụ:

function Foo() { 
    return something; 
} 

var foo = new Foo(); 

Nếu tôi không nhầm, nếu something là một tổ chức phi chức năng nguyên thủy, this sẽ được trả lại. Nếu không, something sẽ được trả lại. Điều này có đúng không?

IOW, giá trị nào có thể something mất làm (new Foo() instanceof Foo) === false?

+0

liên quan: [? Những gì được trở về từ một nhà xây dựng] (http://stackoverflow.com/q/3350215/1048572) – Bergi

Trả lời

150

Tình trạng chính xác được mô tả trên [[Construct]] tài sản nội bộ, được sử dụng bởi các nhà điều hành new:

Từ 3 ECMA-262. Phiên bản Quy cách:

13.2.2[[Construct]]

Khi [[Construct]] tài sản cho một đối tượng FunctionF là gọi, các bước sau đây được thực hiện:

  1. Tạo một đối tượng ECMAScript bản địa mới.
  2. Đặt thuộc tính [[Class]] của Result(1) đến "Object".
  3. Nhận giá trị của thuộc tính mẫu thử của F.
  4. Nếu Result(3) là một đối tượng, hãy đặt thuộc tính [[Prototype]] của Result(1) thành Result(3).
  5. Nếu Result(3) không phải là một đối tượng, thiết lập các [[Prototype]] tài sản của Result(1) đến đối tượng Object nguyên mẫu ban đầu như được mô tả trong 15.2.3.1.
  6. Gọi [[Call]] tài sản của F, cung cấp Result(1) như giá trị this và cung cấp danh sách đối số truyền vào [[Construct]] như các giá trị tham số .
  7. Nếu Type (Result(6))Object sau đó trả lại Result(6).
  8. Trả lại Result(1).

Nhìn vào bước 7 và 8, các đối tượng mới sẽ được trả lại chỉ khi loại của Result(6) (giá trị trả về từ F constructor chức năng) là không một Object.

+5

+1 sử dụng tham khảo tuyệt vời –

+12

Lưu ý bổ sung: typeof (null) là "đối tượng", tuy nhiên trả về null không * kích hoạt bước 7 để xảy ra –

+3

@BT: Kiểm tra cài đặt node.js của tôi, có vẻ như "Loại' (x) 'là' Đối tượng' "trong thông số như được trích dẫn ở trên có nghĩa là' 'instanceof Object' là' true' ", * not *" 'typeof (x) === 'object'' là' true' ". Ví dụ, 'null instanceof Object' đánh giá sai (và thực sự bạn không thể trả về' null' từ một hàm tạo), và 'new String (" asdf ") instanceof Object' đánh giá là true (và thực sự bạn có thể trả về một String từ hàm tạo ...) –

-1

Khi bạn đang sử dụng từ khóa new, một đối tượng được tạo. Sau đó, hàm được gọi để khởi tạo đối tượng.

Không có chức năng nào có thể làm để ngăn chặn đối tượng đang được tạo, vì điều đó được thực hiện trước khi hàm được gọi.

+2

Tôi không tham gia về điều đó. Tôi biết bạn có thể làm những gì tôi yêu cầu (tôi đã thử nó), nhưng tôi không biết các trường hợp dứt khoát mà nó xảy ra. Trong ví dụ của tôi, nó có thể kết thúc với '(foo instanceof Foo) === false'. –

+1

@trin - câu trả lời ngắn gọn không có – JonH

+0

Tại sao lại là downvote? Nếu bạn không giải thích những gì bạn nghĩ là sai, nó không thể cải thiện câu trả lời. – Guffa

2

Tôi không thể tìm thấy bất kỳ tài liệu nào về vấn đề này, nhưng tôi nghĩ bạn đã chính xác. Ví dụ: bạn có thể trả lại new Number(5) từ một hàm tạo, nhưng không phải là chữ số 5 (được bỏ qua và thay vào đó, this sẽ được trả về).

+0

Nhân tiện: điều này xảy ra vì 'Số mới (5)' (hoặc thậm chí chỉ là 'Số (5)', vì nó được dự định làm việc giống nhau nếu được gọi là hàm) tạo một đối tượng * số *, ví dụ điều này có nghĩa là trong khi ''' == false',' !! new String ('') == true'. –

+0

Hai năm sau và sẵn sàng trả lời để sửa lời nhận xét của tôi, nó hoạt động: 'hàm One() {return new Number (1)}' nhưng điều này không: 'function One() {return Number (1)}' –

0

Lưu ý phụ, giá trị trả lại hoặc this chỉ là một phần của phương trình.

Ví dụ, hãy xem xét điều này:

function Two() { return new Number(2); } 
var two = new Two; 
two + 2; // 4 
two.valueOf = function() { return 3; } 
two + 2; // 5 
two.valueOf = function() { return '2'; } 
two + 2; // '22' 

Như bạn thấy, .valueOf() được nội được sử dụng và có thể khai thác để cho vui và lợi nhuận. Bạn thậm chí có thể tạo ra phản ứng phụ, ví dụ:

function AutoIncrementingNumber(start) { 
    var n = new Number, val = start || 0; 
    n.valueOf = function() { return val++; }; 
    return n; 
} 
var auto = new AutoIncrementingNumber(42); 
auto + 1; // 43 
auto + 1; // 44 
auto + 1; // 45 

tôi có thể tưởng tượng này phải có một số loại ứng dụng thực tế. Và nó không phải là một cách rõ ràng Number hoặc, nếu bạn thêm .valueOf cho bất kỳ đối tượng nó có thể cư xử như một số:

({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638 

Bạn có thể khai thác này để làm cho một đối tượng mà luôn luôn trả về một GUID mới, ví dụ.

2

ví dụ bê tông http://jsbin.com/zivivucahi/1/edit?html,js,console,output

/* 
ECMA 262 v 5 
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 
"4.3.2 
primitive value 
member of one of the types Undefined, Null, Boolean, Number, Symbol, or String as defined in clause 6" 
*/ 

var Person = function(x){ 
    return x; 

}; 


console.log(Person.constructor); 
console.log(Person.prototype.constructor); 
console.log(typeof(Person)); 
console.log(typeof(Person.prototype)); 

function log(x){ 
    console.log(x instanceof Person); 
    console.log(typeof x); 
    console.log(typeof x.prototype); 
} 

log(new Person(undefined)); 
log(new Person(null)); 
log(new Person(true)); 
log(new Person(2)); 
log(new Person("")); 

//returns a function not an object 
log(new Person(function(){})); 


//implementation? 
//log(new Person(Symbol('%'))); 
Các vấn đề liên quan