2011-07-19 5 views
37

Có lẽ là phần được hiểu ít nhất của JavaScript, đứng bên cạnh chuỗi nguyên mẫu.Toán tử mới hoạt động như thế nào trong JavaScript?

Vì vậy, câu hỏi là: làm thế nào ...

new dataObj(args); 

... thực sự tạo ra một đối tượng, và xác định của nó chuỗi nguyên mẫu/nhà thầu/etc?

Tốt nhất là hiển thị thay thế, để hiểu đầy đủ từ khóa này.

+2

Sắp xếp các liên quan: http://stackoverflow.com/question/1646698/what-is-the-new-keyword-in-javascript – Ivan

Trả lời

45

Nhà điều hành new sử dụng phương pháp nội [[Construct]], và về cơ bản nào sau đây:

  • Khởi một đối tượng có nguồn gốc mới
  • Thiết lập nội bộ [[Prototype]] của đối tượng này, trỏ đến thuộc tính Function prototype.
    • Nếu thuộc tính prototype của hàm không phải là đối tượng (một giá trị nguyên thủy, như số, chuỗi, Boolean, Không xác định hoặc Null), Object.prototype được sử dụng thay thế.
  • Sau khi tạo đối tượng, nó gọi hàm, cung cấp đối tượng làm giá trị this.
  • Nếu giá trị trả về của hàm được gọi, là một nguyên thủy, đối tượng được tạo bên trong được trả về.
  • Nếu không, nếu đối tượng được trả về, đối tượng được tạo bên trong sẽ bị mất.

An thực hiện tương đương với những gì các nhà điều hành new không, có thể được thể hiện như thế này (giả định rằng ECMAScript 5 Object.create phương pháp có sẵn):

function NEW(f) { 
    var obj, ret, proto; 

    // Check if `f.prototype` is an object, not a primitive 
    proto = Object(f.prototype) === f.prototype ? f.prototype : Object.prototype; 

    // Create an object that inherits from `proto` 
    obj = Object.create(proto); 

    // Apply the function setting `obj` as the `this` value 
    ret = f.apply(obj, Array.prototype.slice.call(arguments, 1)); 

    if (Object(ret) === ret) { // the result is an object? 
    return ret; 
    } 
    return obj; 
} 

// Example usage: 
function Foo (arg) { 
    this.prop = arg; 
} 
Foo.prototype.inherited = 'baz'; 

var obj = NEW(Foo, 'bar'); 
obj.prop;   // 'bar' 
obj.inherited;  // 'baz' 
obj instanceof Foo // true 
+0

Liệu có an toàn khi thay thế Object.create (proto) bằng> var newObj = {}; newObj.prototype = proto; ? – PicoCreator

+4

@ pico.creator: Không, thuộc tính 'prototype' chỉ có ý nghĩa đối với các đối tượng Function, khi được sử dụng như các hàm tạo và sử dụng một hàm tạo trong ví dụ của tôi là' new', sẽ cần sử dụng toán tử 'new'. .. Cách duy nhất khác xung quanh sẽ là sử dụng thuộc tính '__proto__', nhưng nó không chuẩn và nó không được dùng nữa. Xem [câu trả lời này] (http://stackoverflow.com/questions/2111288/#2111353) trong đó tôi giải thích sự khác biệt giữa thuộc tính 'prototype' của các đối tượng hàm và thuộc tính * internal *' [[Prototype]] ' tất cả các đối tượng đã hình thành chuỗi nguyên mẫu. – CMS

+0

Việc sử dụng kép của thuật ngữ chắc chắn là khó hiểu. Tuy nhiên câu trả lời đã bỏ qua thiết lập của hàm tạo đối tượng; Nguyên nhân từ các thí nghiệm của tôi, có vẻ như hàm xây dựng được nhân bản, áp dụng và được thêm vào kết quả .constructor. – PicoCreator

8

Khái niệm new C(arg1, arg2):

Giả sử C là một hàm JavaScript (nếu không bạn nhận được một lỗi):

  1. Tạo một đối tượng rỗng mới (không có tài sản)
  2. Thiết lập nguyên mẫu của các mới đối tượng với giá trị của thuộc tính "prototype" của C.
    • Lưu ý: Giá trị mặc định của prototype cho một chức năng là một đối tượng (tự động tạo ra khi hàm được công bố) với nguyên mẫu của nó thiết lập để Object.prototypeconstructor tài sản chỉ trở lại chức năng C.
    • Lưu ý: Thuật ngữ có thể gây nhầm lẫn. Thuộc tính có tên là "nguyên mẫu" là không phải là giống như nguyên mẫu của đối tượng. Chỉ các hàm có thuộc tính có tên là "nguyên mẫu", nhưng tất cả các đối tượng đều có một mẫu thử nghiệm.
  3. Gọi hàm C với 'this' được đặt thành đối tượng mới và với đối số được cung cấp.
  4. Nếu gọi hàm C trả về một đối tượng, đối tượng này là kết quả của biểu thức. Nếu không, đối tượng mới được tạo là kết quả của biểu thức.

Phương án thay thế cho new trong ECMAScript 5 sẽ sử dụng phương pháp được dựng sẵn Object.createObject.

new C(arg1, arg2) sẽ tương đương với:

var obj = Object.createObject(C.prototype); 
C.apply(obj, [arg1, arg2]); 

Chuẩn JavaScript không cho phép bạn thiết lập một cách rõ ràng nguyên mẫu của một đối tượng, vì vậy Object.createObject không thể được thực hiện bằng ngôn ngữ riêng của mình. Một số triển khai cho phép nó thông qua thuộc tính không chuẩn __proto__. Trong trường hợp đó, new C thể được mô phỏng như thế này:

var obj = {}; 
obj.__proto__ = C.prototype; 
C.apply(obj, [arg1, arg2]); 
+1

Lưu ý ở điểm # 2: Giá trị mặc định của thuộc tính 'prototype' của bất kỳ hàm do người dùng định nghĩa nào, là một đối tượng chứa' hàm tạo' thuộc tính tham chiếu trở lại chính hàm đó và nó kế thừa từ 'Object.prototype'. Đối tượng này được khởi tạo khi [đối tượng hàm được tạo] (http://es5.github.com/#x13.2). Về 'Object.create', nó có thể được * một phần * mô phỏng trên ES3, thiết lập thuộc tính' [[Prototype]] 'có thể được thực hiện thông qua một hàm tạo tạm thời, nhưng có, nó không thể mô phỏng hoàn toàn, [xem thêm] (http://stackoverflow.com/questions/3830800#3844768). Chúc mừng. – CMS