Apakah ada cara untuk mendapatkan sesuatu seperti berikut ini berfungsi di JavaScript?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
Dalam bentuk saat ini, kode ini jelas melempar kesalahan referensi karena this
tidak merujuk foo
. Tetapi apakah ada cara untuk memiliki nilai dalam properti literal objek tergantung pada properti lain yang dinyatakan sebelumnya?
javascript
object-literal
kpozin
sumber
sumber
foo.a
ataufoo.b
diubah maka nilaifoo.c
sinkronisasi juga akan berubah. Ini mungkin atau mungkin tidak apa yang diperlukan.this
mengikat ke objek bersarang terdalam. Misalnya:... x: { get c () { /*this is x, not foo*/ } } ...
foo
beeing dinyatakan sebagai variabel danc
hanya akan dievaluasi pada saat itu dipanggil, menggunakanfoo
di dalamc
akan bekerja, sebagai lawanthis
(hati-hati meskipun)Anda dapat melakukan sesuatu seperti:
Ini akan menjadi semacam inisialisasi satu kali objek.
Perhatikan bahwa Anda benar-benar menetapkan nilai kembali dari
init()
kefoo
, karena itu Anda harusreturn this
.sumber
delete this.init
sebelumreturn this
sehinggafoo
tidak terpolusiinit()
panggilan itu langsung ditambahkan literal untuk mempertahankannya menjadi ekspresi tunggal. Tetapi tentu saja Anda dapat memanggil fungsi secara terpisah yang Anda inginkan.Jawaban yang jelas dan sederhana tidak ada, jadi untuk kelengkapan:
Tidak. Semua solusi di sini menundanya sampai setelah objek dibuat (dengan berbagai cara) dan kemudian menetapkan properti ketiga. Cara paling sederhana adalah dengan melakukan ini:
Semua yang lain hanyalah cara tidak langsung untuk melakukan hal yang sama. (Felix's sangat pintar, tetapi membutuhkan membuat dan menghancurkan fungsi sementara, menambah kompleksitas; dan baik meninggalkan properti tambahan pada objek atau [jika Anda
delete
properti itu] berdampak pada kinerja akses properti selanjutnya pada objek itu.)Jika Anda membutuhkan semuanya dalam satu ekspresi, Anda dapat melakukannya tanpa properti sementara:
Atau tentu saja, jika Anda perlu melakukan ini lebih dari sekali:
maka di mana Anda perlu menggunakannya:
sumber
this
hanya tersedia untuk metode objek tersebut, dan tidak ada jenis properti lainnya. Ada ide di mana saya bisa menemukan itu? Terima kasih!delete
10% lebih cepat dan tokek:delete
hanya 1% lebih lambat.Cukup instantiate fungsi anonim:
sumber
new Point(x, y)
kecuali bahwa fungsi tersebut tidak dinamai untuk digunakan kembali.var foo = function() { this.…; return this; }.call({});
yang secara sintaksis tidak jauh berbeda tetapi secara waras waras.new
kata kunci.Sekarang di ES6 Anda dapat membuat properti cache malas. Pada penggunaan pertama properti mengevaluasi sekali untuk menjadi properti statis normal. Hasil: Kedua kalinya overhead fungsi matematika dilewati.
Keajaiban ada di pengambil.
Pada pengambil panah
this
mengambil lingkup leksikal sekitarnya .sumber
Object.defineProperty(foo, 'c', {get:function() {...}})
untuk mendefinisikannya. Ini mudah dilakukan dengan cara yang tidak mencolok di pabrik seperti ini. Tentu saja jika Anda dapat menggunakanget
gula itu lebih mudah dibaca tetapi kemampuannya sudah ada.Beberapa penutupan harus berurusan dengan ini;
Semua variabel yang dideklarasikan di dalamnya
foo
adalah milik pribadifoo
, seperti yang Anda harapkan dengan deklarasi fungsi apa pun dan karena semuanya ada dalam ruang lingkup, semuanya memiliki akses satu sama lain tanpa perlu merujuk kethis
, sama seperti yang Anda harapkan dengan suatu fungsi. Perbedaannya adalah bahwa fungsi ini mengembalikan objek yang memperlihatkan variabel pribadi dan menetapkan objek itufoo
. Pada akhirnya, Anda mengembalikan hanya antarmuka yang ingin Anda tampilkan sebagai objek denganreturn {}
pernyataan.Fungsi ini kemudian dieksekusi di akhir dengan
()
yang menyebabkan seluruh objek foo dievaluasi, semua variabel dalam instantiated dan objek kembali ditambahkan sebagai propertifoo()
.sumber
Anda bisa melakukannya seperti ini
Metode itu telah terbukti bermanfaat bagi saya ketika saya harus merujuk ke objek yang awalnya dideklarasikan fungsi. Berikut ini adalah contoh minimal bagaimana saya menggunakannya:
Dengan mendefinisikan diri sebagai objek yang berisi fungsi cetak Anda mengizinkan fungsi untuk merujuk ke objek itu. Ini berarti Anda tidak perlu 'mengikat' fungsi cetak ke objek jika Anda harus meneruskannya di tempat lain.
Jika Anda mau, gunakan
this
seperti yang diilustrasikan di bawah iniKemudian kode berikut akan mencatat 0, 1, 2 dan kemudian memberikan kesalahan
Dengan menggunakan metode mandiri Anda menjamin bahwa pencetakan akan selalu mengembalikan objek yang sama terlepas dari konteks di mana fungsi dijalankan. Kode di atas akan berjalan dengan baik dan log 0, 1, 2 dan 3 saat menggunakan versi self
createMyObject()
.sumber
Untuk penyelesaiannya, di ES6 kami memiliki kelas (didukung pada saat penulisan ini hanya oleh browser terbaru, tetapi tersedia dalam Babel, TypeScript dan transpiler lainnya)
sumber
Anda dapat melakukannya menggunakan pola modul. Seperti:
Dengan pola ini Anda dapat instantiate beberapa objek foo sesuai dengan kebutuhan Anda.
http://jsfiddle.net/jPNxY/1/
sumber
}();
, itu akan mengeksekusi sendiri dan mengembalikan objek, bukan fungsi. Juga,foo.c
adalah suatu fungsi, jadi menulis kepadanya itu berfungsi dan doa berikutnyafooObject.c()
akan gagal. Mungkin biola ini lebih dekat dengan apa yang Anda tuju (itu juga singleton, tidak dirancang untuk dipakai instantiated).Ada beberapa cara untuk mencapai ini; inilah yang akan saya gunakan:
sumber
hanya demi pemikiran - letakkan properti objek di luar garis waktu:
ada jawaban yang lebih baik di atas juga . Ini adalah bagaimana saya mengubah kode contoh yang Anda tanyakan.
MEMPERBARUI:
sumber
var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }
jadi sekarang Anda bisa melakukanfoo.c
alih - alihfoo.c()
:) (Jangan ragu untuk menempelkannya ke dalam jawaban Anda sehingga pemformatan lebih baik!)Menciptakan fungsi baru pada objek Anda secara literal dan menggunakan konstruktor tampaknya merupakan perubahan radikal dari masalah awal, dan itu tidak perlu.
Anda tidak bisa merujuk properti saudara selama inisialisasi objek literal.
Solusi paling sederhana untuk properti yang dihitung mengikuti (tanpa tumpukan, tanpa fungsi, tanpa konstruktor):
sumber
Jawaban lain yang diposting di sini lebih baik tetapi inilah alternatifnya:
init()
atau kode apa pun di luar objek literalFungsi anonim yang dijalankan sendiri dan penyimpanan jendela
Pesanan dijamin (
bar
sebelumbaz
).Tentu
window
saja itu mencemari , tetapi saya tidak bisa membayangkan seseorang menulis naskah yangwindow.temp
harus gigih. MungkintempMyApp
jika Anda paranoid.Ini juga jelek tapi kadang berguna. Contohnya adalah ketika Anda menggunakan API dengan kondisi inisialisasi yang kaku dan tidak merasa ingin refactoring sehingga pelingkupannya benar.
Dan itu kering, tentu saja.
sumber
Kunci dari semua ini adalah RUANG LINGKUP .
Anda perlu merangkum "parent" (objek induk) dari properti yang ingin Anda tetapkan sebagai objek instantiated sendiri, dan kemudian Anda bisa membuat referensi ke properti saudara menggunakan kata kunci
this
Sangat, sangat penting untuk diingat bahwa jika Anda merujuk
this
tanpa terlebih dahulu melakukannya, makathis
akan merujuk pada lingkup luar ... yang akan menjadiwindow
objek.sumber
jika objek Anda ditulis sebagai fungsi yang mengembalikan objek, DAN Anda menggunakan ES6 objek-atribut 'metode', maka itu mungkin:
sumber
Saya menggunakan kode berikut sebagai alternatif, dan berfungsi. Dan variabel dapat berupa array juga. (@ Fausto R.)
sumber
Inilah cara ES6 yang rapi:
Saya menggunakannya untuk melakukan sesuatu seperti ini:
sumber
Bagaimana dengan solusi ini ini akan bekerja dengan objek bersarang dengan array juga
sumber
Melempar opsi karena saya tidak melihat skenario persis ini tertutup. Jika Anda tidak ingin
c
memperbarui kapana
ataub
memperbarui, maka ES6 IIFE berfungsi dengan baik.Untuk kebutuhan saya, saya memiliki objek yang berhubungan dengan array yang akhirnya akan digunakan dalam satu lingkaran, jadi saya hanya ingin menghitung beberapa pengaturan umum sekali, jadi inilah yang saya miliki:
Karena saya perlu mengatur properti untuk
indexOfSelectedTier
dan saya perlu menggunakan nilai itu ketika mengaturhasUpperTierSelection
properti, saya menghitung nilai itu terlebih dahulu dan meneruskannya sebagai param ke IIFEsumber
Pendekatan lain adalah dengan mendeklarasikan objek terlebih dahulu sebelum menetapkan properti ke dalamnya:
Dengan itu, Anda bisa menggunakan nama variabel objek untuk mengakses nilai yang sudah ditetapkan.
Terbaik untuk
config.js
file.sumber
foo
yang dideklarasikan yang menunjuk ke objek yang dimaksud.Ini hampir identik dengan jawaban @ slicedtoad, tetapi tidak menggunakan fungsi.
sumber
Di sini kami menggunakan ekspresi kelas untuk mendapatkan antarmuka literal objek bersarang yang kami inginkan. Ini adalah hal terbaik IMHO berikutnya untuk dapat mereferensikan properti suatu objek selama pembuatan.
Hal utama yang perlu diperhatikan adalah saat menggunakan solusi ini, Anda memiliki antarmuka yang sama persis seperti yang Anda miliki dari objek literal. Dan sintaksnya cukup dekat dengan objek literal itu sendiri (vs menggunakan fungsi, dll).
Bandingkan yang berikut ini
Solusi yang saya usulkan
Solusi jika objek literal sudah mencukupi
Contoh lain
Di sini di kelas ini, Anda dapat menggabungkan beberapa jalur relatif di antara mereka sendiri, yang tidak mungkin dengan objek literal.
sumber
Jika Anda ingin menggunakan JS asli, jawaban lain memberikan solusi yang baik.
Tetapi jika Anda bersedia menulis objek referensi diri seperti:
Saya menulis perpustakaan npm bernama self-referenced-object yang mendukung sintaks itu dan mengembalikan objek asli.
sumber
b
nilai properti harus:${this.a + this.a}
. Kedua, tetapi yang kurang penting, Anda ingin mengembalikan nomor, bukan string dengan menggunakan sesuatu sepertiparseInt
. Terakhir dan PALING penting, ketika saya mencoba contoh ini tidak berfungsi, untuk alasan yang sama OP bertanya. Pengembalianthis
tidak terdefinisi saat menggunakan objek deklarasi sendiri. @ alex-e-leon