`new function ()` dengan huruf kecil “f” di JavaScript

106

Rekan saya telah menggunakan "fungsi baru ()" dengan huruf kecil "f" untuk mendefinisikan objek baru di JavaScript. Tampaknya berfungsi dengan baik di semua browser utama dan juga tampaknya cukup efektif dalam menyembunyikan variabel pribadi. Berikut contohnya:

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

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

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

Begitu "ini" digunakan, ini menjadi milik umum someObj. Jadi someObj.foo, someObj.get_inner () dan someObj.set_inner () semuanya tersedia untuk umum. Selain itu, set_inner () dan get_inner () adalah metode istimewa, sehingga mereka memiliki akses ke "dalam" melalui penutupan.

Namun, saya belum melihat referensi apa pun untuk teknik ini di mana pun. Bahkan JSLint milik Douglas Crockford mengeluhkannya:

  • konstruksi aneh. Hapus 'baru'

Kami menggunakan teknik ini dalam produksi dan tampaknya berhasil dengan baik, tetapi saya agak khawatir karena tidak didokumentasikan di mana pun. Adakah yang tahu jika ini adalah teknik yang valid?

Johnny Oshika
sumber
6
Saya lebih suka konstruksi Anda daripada IIFE ('Fungsi Segera Diminta'). 1: Anda tidak memerlukan objek 'instance' eksplisit, itulah tepatnya 'ini' di JavaScript. 2: Anda tidak perlu mengembalikan apa pun, yang artinya, Anda tidak perlu mengingatnya. Bahkan penulis jawaban yang diterima lupa mengembalikan objek instance pada awalnya! Orang biasanya lebih suka menggunakan IIFE jika mereka membenci yang baru & ini, dengan alasan yang bagus - Jika Anda memiliki fungsi yang menangani peristiwa DOM, thisakan merujuk ke elemen yang memicu peristiwa tersebut, bukan objek Anda, tetapi Anda bisa saja melakukannya var instance = this.
Lee Kowalkowski
1
Mengapa penting untuk pertanyaan menentukan "huruf kecil f"?
ClearCloud8
7
Karena di Javascript juga terdapat fungsi 'Fungsi' (dengan huruf besar F), yang berbeda: Fungsi adalah fungsi konstruktor yang dapat membuat objek fungsi baru, sedangkan fungsi adalah kata kunci.
Stijn de Witt
@Bergi Saya membaca link Anda. Saya tidak melihat alasan untuk mendiskreditkan pola ini. Itu valid. Itu mudah. Jadi apa yang salah. JSLint mengeluh tentang semuanya BTW :)
Stijn de Witt

Jawaban:

64

Saya telah melihat teknik itu sebelumnya, itu valid, Anda menggunakan ekspresi fungsi seolah-olah itu adalah Fungsi Pembuat .

Tetapi IMHO, Anda dapat mencapai hal yang sama dengan ekspresi fungsi pemanggilan otomatis, saya tidak benar-benar melihat gunanya menggunakan newoperator dengan cara itu:

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;
})();

Tujuan dari newoperator adalah untuk membuat instance objek baru, menyiapkan [[Prototype]]properti internal, Anda dapat melihat bagaimana ini dibuat oleh[Construct] properti internal.

Kode di atas akan menghasilkan hasil yang setara.

CMS
sumber
1
Spesifikasi ECMAScript 262 di Bagian 13 menjelaskan ini sedikit lebih formal. Sesuatu seperti function foo () {}mengembalikan hasil dari membuat Functionobjek [mungkin dengan Fungsi baru ()]. Ini gula sintaks.
Clinton Pierce
3
Saya pikir Anda kehilangan return instance;pada akhirnya. Jika tidak, someObjhanya akan undefined. :-)
Matthew Crumley
1
Bolehkah saya menyarankan bahwa jika Anda peduli dengan modularitas dan penyembunyian informasi, Anda menyerah begitu saja dan mulai menggunakan sesuatu seperti require.js? Anda sudah setengah jalan, mengapa berhenti di sini? Asynchronous Module Definition (yang diimplementasikan oleh require.js) mendukung usecase ini dan memberi Anda seluruh perangkat untuk menangani pelingkupan, namespacing, dan manajemen ketergantungan.
Stijn de Witt
Perhatikan bahwa tanda kurung yang mengelilingi deklarasi fungsi tidak diperlukan karena pernyataan tersebut sudah menjadi ekspresi karena adanya=
Explosion Pills
@StijndeWitt setengah jalan berarti Anda perlu melakukan dua kali pekerjaan untuk menggunakan require.js tetapi mungkin hanya ini yang Anda butuhkan dalam kasus sederhana.
xr280xr
15

Kode Anda sama dengan konstruksi yang tidak terlalu aneh

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

    ...
};
var someObj = new Foo;
kennytm
sumber
9
Ia tidak hanya serupa, ia melakukan hal yang persis sama ... dengan satu-satunya pengecualian bahwa mereka tidak akan dapat menggunakan kembali Foo untuk membuat objek lain.
kikito
3
Versi OP dapat digunakan kembali melalui someObj.constructor baru . Di sini konstruktor ditambahkan ke namespace secara eksplisit; gaya yang tepat tergantung pada tujuan dari fungsi tersebut. Juga, gaya ini - meskipun tentunya standar - memungkinkan seseorang mengisi namespace global jika mereka lupa yang baru sebelum Foo .
J Bryan Harga
@kikito apa maksud Anda ini tidak mengizinkan penggunaan ulang Foo untuk membuat objek lain? var newObj = new Foo () harus membuat instance baru.
Bill Yang
1
@BillYang Itu 5 tahun yang lalu. Tidak ada ide. Saya belum pernah menyentuh javascript sejak itu.
kikito
12

Untuk memperjelas beberapa aspek dan membuat JSLint Douglas Crockford tidak mengeluh tentang kode Anda, berikut adalah beberapa contoh instantiation:

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

Dalam contoh 3. ekspresi dalam (...) sebagai nilai adalah fungsi / konstruktor. Ini terlihat seperti ini: new (function () {...}) (). Jadi jika kita menghilangkan tanda kurung akhir seperti pada contoh 2, ekspresi tersebut masih merupakan panggilan konstruktor yang valid dan terlihat seperti contoh 4.

JSLint Douglas Crockford "berpikir" Anda ingin menetapkan fungsi ke someObj, bukan instance-nya. Dan bagaimanapun itu hanya peringatan, bukan kesalahan.

DUzun
sumber