Diambil dari MDN
String literal (dilambangkan dengan tanda kutip ganda atau tunggal) dan string yang dikembalikan dari panggilan String dalam konteks non-konstruktor (yaitu, tanpa menggunakan kata kunci baru) adalah string primitif. JavaScript secara otomatis mengonversi objek primitif menjadi String, sehingga memungkinkan untuk menggunakan metode objek String untuk string primitif. Dalam konteks di mana metode akan dipanggil pada string primitif atau terjadi pencarian properti, JavaScript akan secara otomatis menggabungkan string primitif dan memanggil metode atau melakukan pencarian properti.
Jadi, saya pikir (secara logis) operasi (panggilan metode) pada primitif string harus lebih lambat daripada operasi pada Objek string karena string primitif apa pun diubah ke Objek string (kerja ekstra) sebelum method
diterapkan pada string.
Namun dalam kasus uji ini , hasilnya justru sebaliknya. The blok kode-1 berjalan lebih cepat dari kode blok-2 , kedua blok kode yang diberikan di bawah:
blok kode-1:
var s = '0123456789';
for (var i = 0; i < s.length; i++) {
s.charAt(i);
}
blok kode-2:
var s = new String('0123456789');
for (var i = 0; i < s.length; i++) {
s.charAt(i);
}
Hasil bervariasi di browser tetapi blok kode-1 selalu lebih cepat. Adakah yang bisa menjelaskan ini, mengapa kode blok-1 lebih cepat daripada kode blok-2 .
sumber
new String
memperkenalkan lapisan transparan lain dari pembungkus Objek .typeof new String(); //"object"
'0123456789'.charAt(i)
?code block-1
lebih cepat?Jawaban:
JavaScript memiliki dua kategori tipe utama, primitif dan objek.
Pola petik tunggal / petik ganda identik dalam hal fungsionalitas. Selain itu, perilaku yang coba Anda namai disebut auto-boxing. Jadi yang sebenarnya terjadi adalah primitif diubah menjadi tipe pembungkusnya ketika metode jenis pembungkus dipanggil. Sederhanakan:
Merupakan tipe data primitif. Ini tidak memiliki metode, tidak lebih dari sebuah penunjuk ke referensi memori data mentah, yang menjelaskan kecepatan akses acak yang jauh lebih cepat.
Jadi apa yang terjadi jika Anda melakukannya
s.charAt(i)
misalnya?Karena
s
bukan merupakan contoh dariString
, JavaScript akan auto-boxs
, yang memilikitypeof string
jenis pembungkusnyaString
, dengantypeof object
atau lebih tepatnyas.valueOf(s).prototype.toString.call = [object String]
.Perilaku auto-boxing
s
bolak-balik ke jenis pembungkusnya sesuai kebutuhan, tetapi operasi standar sangat cepat karena Anda berurusan dengan tipe data yang lebih sederhana. Bagaimanapun auto-boxing danObject.prototype.valueOf
memiliki efek berbeda.Jika Anda ingin memaksa auto-boxing atau mentransmisikan primitif ke jenis pembungkusnya, Anda dapat menggunakan
Object.prototype.valueOf
, tetapi perilakunya berbeda. Berdasarkan berbagai macam skenario pengujian, auto-boxing hanya menerapkan metode yang 'diperlukan', tanpa mengubah sifat primitif variabel. Itulah mengapa Anda mendapatkan kecepatan yang lebih baik.sumber
Ini agak tergantung pada implementasi, tetapi saya akan mengambil bidikan. Saya akan mencontohkan dengan V8 tetapi saya berasumsi mesin lain menggunakan pendekatan serupa.
String primitif diurai menjadi
v8::String
objek. Karenanya, metode dapat dipanggil langsung seperti yang disebutkan oleh jfriend00 .Sebuah objek String, di sisi lain, diurai menjadi
v8::StringObject
yang meluasObject
dan, selain menjadi objek penuh, berfungsi sebagai pembungkus untukv8::String
.Sekarang hanya logis, panggilan untuk
new String('').method()
memiliki unbox iniv8::StringObject
'sv8::String
sebelum mengeksekusi metode, karena itu lebih lambat.Dalam banyak bahasa lain, nilai primitif tidak memiliki metode.
Cara MDN menempatkannya tampaknya menjadi cara paling sederhana untuk menjelaskan cara kerja auto-boxing primitif (seperti juga disebutkan dalam jawaban flav ), yaitu, bagaimana nilai primitif-y JavaScript dapat memanggil metode.
Namun, mesin pintar tidak akan mengonversi string primitive-y menjadi objek String setiap kali Anda perlu memanggil metode. Ini juga secara informatif disebutkan dalam spesifikasi ES5 Beranotasi. berkenaan dengan menyelesaikan properti (dan "metode" ¹) dari nilai primitif:
Pada level yang sangat rendah, String paling sering diimplementasikan sebagai nilai skalar yang tidak dapat diubah. Contoh struktur pembungkus:
Semakin jauh Anda dari primitif, semakin lama waktu yang dibutuhkan untuk mencapainya. Dalam praktiknya,
String
primitif jauh lebih sering daripadaStringObject
s, oleh karena itu tidak mengherankan bagi mesin untuk menambahkan metode ke Kelas objek 'yang sesuai (ditafsirkan)' primitif String alih-alih mengonversi bolak-balik antaraString
danStringObject
seperti yang disarankan oleh penjelasan MDN.¹ Dalam JavaScript, "metode" hanyalah konvensi penamaan untuk properti yang menetapkan nilai fungsi tipe.
sumber
=]
Sekarang saya bertanya-tanya apakah penjelasan MDN ada di sana hanya karena tampaknya itu cara termudah untuk memahami auto-boxing atau apakah ada referensi ke sana dalam spesifikasi ES .. Membaca seluruh spesifikasi saat ini untuk memeriksa, akan ingat untuk perbarui jawabannya jika saya pernah menemukan referensi.Dalam kasus string literal, kami tidak dapat menetapkan properti
Sedangkan dalam kasus Objek String kita dapat menetapkan properti
sumber
String
objek juga. Terima kasih!String Literal:
Literal string tidak dapat diubah, yang berarti, setelah dibuat, statusnya tidak dapat diubah, yang juga membuatnya aman untuk thread.
a==b
Hasilnya akan menjadi 'true' kedua string merujuk objek yang sama.Objek String:
Di sini, dua objek berbeda dibuat, dan mereka memiliki referensi berbeda:
a==b
hasilnya akan salah, karena memiliki referensi yang berbeda.sumber
a
&b
mencoba untuk menetapkana[0] = 'X'
itu akan dieksekusi berhasil tetapi akan tidak bekerja seperti yang Anda harapkanJika Anda menggunakan
new
, Anda secara eksplisit menyatakan bahwa Anda ingin membuat sebuah instance dari sebuah Object . Oleh karena itu,new String
menghasilkan sebuah Objek yang membungkus primitif String , yang berarti tindakan apa pun di atasnya melibatkan lapisan kerja tambahan.Karena memiliki tipe yang berbeda, penerjemah JavaScript Anda juga dapat mengoptimalkannya secara berbeda, seperti yang disebutkan dalam komentar .
sumber
Saat Anda menyatakan:
Anda membuat string primitif. String primitif itu memiliki metode yang memungkinkan Anda memanggil metode di atasnya tanpa mengonversi primitif ke objek kelas pertama. Jadi anggapan Anda bahwa ini akan lebih lambat karena string harus diubah menjadi objek tidak benar. Itu tidak harus diubah menjadi sebuah objek. Primitif itu sendiri dapat memanggil metode.
Mengonversinya menjadi objek full-blown (yang memungkinkan Anda menambahkan properti baru padanya) adalah langkah tambahan dan tidak membuat string bergerak lebih cepat (sebenarnya pengujian Anda menunjukkan bahwa hal itu membuatnya lebih lambat).
sumber
String.prototype
?var s = '0123456789';
adalah nilai primitif, bagaimana nilai ini memiliki metode, saya bingung!Saya dapat melihat bahwa pertanyaan ini telah diselesaikan sejak lama, ada perbedaan halus lainnya antara string literal dan objek string, karena tampaknya tidak ada yang menyentuhnya, saya pikir saya hanya akan menulisnya untuk kelengkapan.
Pada dasarnya perbedaan lain antara keduanya adalah saat menggunakan eval. eval ('1 + 1') memberikan 2, sedangkan eval (new String ('1 + 1')) memberikan '1 + 1', jadi jika blok kode tertentu dapat dieksekusi baik 'normal' atau dengan eval, itu bisa mengarah pada hasil yang aneh
sumber
new String("")
mengembalikan objek, dan mengevaluasi hanya mengevaluasi string, dan mengembalikan segala sesuatu yang lain apa adanyaKeberadaan objek tidak ada hubungannya dengan perilaku sebenarnya dari String di mesin ECMAScript / JavaScript karena cakupan root hanya akan berisi objek fungsi untuk ini. Jadi fungsi charAt (int) dalam kasus string literal akan dicari dan dijalankan.
Dengan objek nyata Anda menambahkan satu lapisan lagi di mana metode charAt (int) juga dicari pada objek itu sendiri sebelum perilaku standar dijalankan (sama seperti di atas). Rupanya ada banyak sekali pekerjaan yang dilakukan dalam kasus ini.
BTW Saya tidak berpikir bahwa primitif sebenarnya diubah menjadi Objek tetapi mesin skrip hanya akan menandai variabel ini sebagai tipe string dan oleh karena itu dapat menemukan semua fungsi yang disediakan untuk itu sehingga sepertinya Anda memanggil objek. Jangan lupa ini adalah runtime skrip yang bekerja pada prinsip yang berbeda dari runtime OO.
sumber
Perbedaan terbesar antara string primitif dan objek string adalah objek harus mengikuti aturan ini untuk
==
operator :Jadi, sementara string primitif memiliki kemudahan
==
yang membandingkan nilai, Anda kurang beruntung ketika harus membuat jenis objek tetap lainnya (termasuk objek string) berperilaku seperti tipe nilai.(Orang lain telah mencatat bahwa objek string secara teknis dapat berubah karena Anda dapat menambahkan properti padanya. Tetapi tidak jelas untuk apa itu berguna; nilai string itu sendiri tidak dapat berubah.)
sumber
Kode tersebut dioptimalkan sebelum dijalankan oleh mesin javascript. Secara umum, tolok ukur mikro dapat menyesatkan karena compiler dan interpreter mengatur ulang, memodifikasi, menghapus, dan melakukan trik lain pada bagian kode Anda untuk membuatnya berjalan lebih cepat. Dengan kata lain, kode tertulis memberi tahu apa tujuan tetapi compiler dan / atau runtime akan memutuskan bagaimana mencapai tujuan itu.
Blok 1 lebih cepat terutama karena: var s = '0123456789'; selalu lebih cepat dari var s = new String ('0123456789'); karena overhead pembuatan objek.
Bagian loop bukanlah yang menyebabkan perlambatan karena chartAt () bisa dibuat sebaris oleh interpreter. Coba lepaskan loop dan ulangi tes, Anda akan melihat rasio kecepatan akan sama seperti jika loop tidak dilepas. Dengan kata lain, untuk pengujian ini, blok loop pada waktu eksekusi memiliki kode bytecode / mesin yang persis sama.
Untuk jenis tolok ukur mikro ini, melihat bytecode atau kode mesin akan memberikan gambaran yang lebih jelas.
sumber
Dalam Javascript, tipe data primitif seperti string adalah blok penyusun non-komposit. Ini berarti bahwa mereka hanyalah nilai, tidak lebih:
let a = "string value";
Secara default tidak ada metode bawaan seperti toUpperCase, toLowerCase dll ...Tetapi, jika Anda mencoba menulis:
Ini tidak akan menimbulkan kesalahan apa pun, melainkan akan berfungsi sebagaimana mestinya.
Apa yang terjadi ? Nah, ketika Anda mencoba mengakses properti string
a
Javascript memaksa string ke objek yangnew String(a);
dikenal sebagai objek pembungkus .Proses ini terkait dengan konsep yang disebut konstruktor fungsi di Javascript, di mana fungsi digunakan untuk membuat objek baru.
Ketika Anda mengetik di
new String('String value');
sini String adalah konstruktor fungsi, yang mengambil argumen dan membuat objek kosong di dalam ruang lingkup fungsi, objek kosong ini ditugaskan ke ini dan dalam kasus ini, String memasok semua fungsi bawaan yang diketahui yang kami sebutkan sebelumnya. dan segera setelah operasi selesai, misalnya melakukan operasi huruf besar, objek pembungkus akan dibuang.Untuk membuktikannya, mari lakukan ini:
Di sini keluaran tidak akan ditentukan. Kenapa? Dalam hal ini Javascript membuat objek String pembungkus, menyetel properti addNewProperty baru dan membuang objek pembungkus segera. inilah mengapa Anda menjadi tidak terdefinisi. Kode semu akan terlihat seperti ini:
sumber
kita bisa mendefinisikan String dengan 3 cara
// juga kita bisa membuat menggunakan 4. var d = a + '';
Periksa jenis string yang dibuat menggunakan operator typeof
ketika Anda membandingkan a dan b var
a==b ( // yes)
ketika Anda membandingkan objek String
sumber