`new function ()` với chữ thường “f” trong JavaScript


106

Đồng nghiệp của tôi đã sử dụng "new function ()" với "f" viết thường để xác định các đối tượng mới trong JavaScript. Nó dường như hoạt động tốt trong tất cả các trình duyệt chính và nó cũng có vẻ khá hiệu quả trong việc ẩn các biến riêng tư. Đây là một ví dụ:

    var someObj = new function () {
        var inner = 'some value';
        this.foo = 'blah';

        this.get_inner = function () {
            return inner;
        };

        this.set_inner = function (s) {
            inner = s;
        };
    };

Ngay sau khi "this" được sử dụng, nó sẽ trở thành tài sản công cộng của someObj. Vì vậy, someObj.foo, someObj.get_inner () và someObj.set_inner () đều có sẵn công khai. Ngoài ra, set_inner () và get_inner () là các phương thức đặc quyền, vì vậy chúng có quyền truy cập vào "bên trong" thông qua các bao đóng.

Tuy nhiên, tôi không thấy bất kỳ tài liệu tham khảo nào về kỹ thuật này ở bất kỳ đâu. Ngay cả JSLint của Douglas Crockford cũng phàn nàn về điều đó:

  • xây dựng kỳ lạ. Xóa 'mới'

Chúng tôi đang sử dụng kỹ thuật này trong sản xuất và nó có vẻ đang hoạt động tốt, nhưng tôi hơi lo lắng về nó vì nó không được ghi lại ở bất cứ đâu. Có ai biết nếu đây là một kỹ thuật hợp lệ?


6
Tôi thích cấu trúc của bạn hơn IIFE ('Hàm được gọi ngay lập tức'). 1: Bạn không cần một đối tượng 'instance' rõ ràng, đó chính xác là 'this' trong JavaScript. 2: Bạn không cần trả lại bất cứ thứ gì, có nghĩa là, bạn không cần phải nhớ. Ngay cả tác giả của câu trả lời được chấp nhận cũng quên trả lại đối tượng thể hiện ban đầu! Mọi người thường thích sử dụng IIFE hơn nếu họ ghét cái mới & cái này, có lý do chính đáng - Nếu bạn có một hàm xử lý sự kiện DOM, thissẽ tham chiếu đến phần tử đã kích hoạt sự kiện, không phải đối tượng của bạn, nhưng bạn có thể có var instance = this.
Lee Kowalkowski

1
Tại sao câu hỏi chỉ định "chữ thường f" lại quan trọng?
ClearCloud8

7
Bởi vì trong Javascript cũng tồn tại hàm 'Function' (với chữ F viết hoa), điều này khác hẳn: Hàm là một hàm khởi tạo có thể tạo các đối tượng hàm mới, trong khi hàm là một từ khóa.
Stijn de Witt,


@Bergi Tôi đã đọc các liên kết của bạn. Tôi thấy không có lý do gì để làm mất uy tín của mô hình này. Nó hợp lệ. Nó đơn giản. Vì vậy những gì là sai. JSLint phàn nàn về mọi thứ BTW :)
Stijn de Witt

Câu trả lời:


64

Tôi đã thấy kỹ thuật đó trước đây, nó hợp lệ, bạn đang sử dụng một biểu thức hàm như thể nó là một Hàm tạo .

Nhưng IMHO, bạn có thể đạt được điều tương tự với biểu thức hàm tự động gọi, tôi thực sự không thấy điểm của việc sử dụng newtoán tử theo cách đó:

var someObj = (function () {
    var instance = {},
        inner = 'some value';

    instance.foo = 'blah';

    instance.get_inner = function () {
        return inner;
    };

    instance.set_inner = function (s) {
        inner = s;
    };

    return instance;
})();

Mục đích của newtoán tử là tạo các thể hiện đối tượng mới, thiết lập thuộc tính [[Prototype]]bên trong, bạn có thể xem cách này được thực hiện bởi thuộc tính [Construct]bên trong.

Đoạn mã trên sẽ tạo ra một kết quả tương đương.


1
Đặc tả ECMAScript 262 trong Phần 13 giải thích điều này chính thức hơn một chút. Một cái gì đó như function foo () {}trả về kết quả của việc tạo một Functionđối tượng [có lẽ là với Hàm mới ()]. Đó là đường cú pháp.
Clinton Pierce

3
Tôi nghĩ rằng bạn đang thiếu một return instance;ở cuối. Nếu không, someObjsẽ chỉ là undefined. :-)
Matthew Crumley

1
Tôi có thể gợi ý rằng nếu bạn quan tâm đến tính mô-đun và ẩn thông tin, bạn chỉ cần từ bỏ điều này và bắt đầu sử dụng một cái gì đó như Requi.js? Bạn đã đi được nửa chặng đường, tại sao lại dừng ở đây? Định nghĩa Mô-đun không đồng bộ (là những gì thực hiện request.js) hỗ trợ usecase này và cung cấp cho bạn toàn bộ bộ công cụ để xử lý phạm vi, không gian tên và quản lý phụ thuộc.
Stijn de Witt,

Lưu ý rằng các dấu ngoặc xung quanh khai báo hàm là không cần thiết kể từ khi tuyên bố đã là một biểu hiện do sự hiện diện của=
Thuốc nổ

@StijndeWitt đến nửa chặng đường có nghĩa là bạn sẽ cần thực hiện gấp đôi công việc để sử dụng request.js nhưng đây có thể là tất cả những gì bạn cần trong những trường hợp đơn giản.
xr280xr

15

Mã của bạn giống với cấu trúc ít kỳ lạ hơn

function Foo () {
    var inner = 'some value';
    this.foo = 'blah';

    ...
};
var someObj = new Foo;

9
Nó không chỉ tương tự, mà nó còn hoạt động giống hệt nhau ... với ngoại lệ duy nhất là họ sẽ không thể sử dụng lại Foo để tạo một đối tượng khác.
kikito

3
Phiên bản của OP có thể được sử dụng lại thông qua someObj.constructor mới . Ở đây hàm tạo được thêm vào không gian tên một cách rõ ràng; phong cách phù hợp phụ thuộc vào mục đích dự định của chức năng. Ngoài ra, phong cách này - mặc dù chắc chắn là tiêu chuẩn - cho phép ai đó điền vào không gian tên toàn cầu nếu họ quên mới trước Foo .
J Bryan Giá

@kikito ý bạn là gì, điều này không cho phép sử dụng lại Foo để tạo đối tượng khác? var newObj = new Foo () sẽ tạo một phiên bản mới.
Bill Yang

1
@BillYang Đó là 5 năm trước. Không ý kiến. Tôi đã không đụng đến javascript kể từ đó.
kikito

12

Để làm rõ một số khía cạnh và khiến JSLint của Douglas Crockford không phàn nàn về mã của bạn, đây là một số ví dụ về khởi tạo:

1. o = new Object(); // normal call of a constructor

2. o = new Object;   // accepted call of a constructor

3. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
})(); // normal call of a constructor

4. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
}); // accepted call of a constructor

Trong ví dụ 3. biểu thức trong (...) as value là một hàm / hàm tạo. Nó trông giống như sau: new (function () {...}) (). Vì vậy, nếu chúng ta bỏ qua các dấu ngoặc kết thúc như trong ví dụ 2, biểu thức vẫn là một lệnh gọi hàm tạo hợp lệ và trông giống như ví dụ 4.

JSLint của Douglas Crockford "nghĩ rằng" bạn muốn gán hàm cho someObj, không phải trường hợp của nó. Và suy cho cùng đó chỉ là một cảnh báo, không phải là một lỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.