Sebagai bagian dari panduan P1XT , saya membaca seri YDKJS (lagi). Kali ini saya mencatat pemikiran dan catatan saya, untuk membantu saya belajar dan mungkin orang lain juga akan membacanya. Jika saya membuat kesalahan atau salah tafsir, mohon koreksi saya!

Minggu pagi ini kita berangkat dengan "Buku 4"! Berbeda dengan bahasa seperti C, JavaScript tidak diketik dengan kuat/statis. Sebaliknya dokumentasi ECMA mengatakan (secara kasar), tipe tersebut mempengaruhi bagaimana objek digunakan dan bagaimana nilai dimanipulasi. Pemaksaan di JS berarti Anda dapat mengambil angka, 42, dan membuat string hanya dengan menulis 42 + "me", dan Anda akan mendapatkan "42me". Perbedaan besar dengan bahasa C yang saya gunakan di CS50. Ada tujuh tipe bawaan di JS, dengan tambahan symbol di ES6. Fungsi berada di bawah objek, karena mereka adalah “objek yang dapat dipanggil”. Fakta menariknya adalah jika Anda menjalankan typeof null, itu sebenarnya memberi Anda “object”. Ingat di JS, variabel itu sendiri tidak memiliki tipe, tetapi nilainya memiliki tipe. Ada beberapa perbedaan dalam operator typeof ketika menemukan variabel yang tidak terdefinisi atau tidak dideklarasikan.

var a;
a; // undefined
b; // ReferenceError: b is not defined
typeof a; // "undefined"
typeof b; // "undefined"

Ini bisa membingungkan jika Anda tidak memperhatikan saat men-debug kode. Kita dapat menggunakan ini untuk keuntungan kita, untuk menghindari menjalankan fungsi pada variabel yang tidak dideklarasikan dengan menyertakan if (typeof DEBUG !== “undefined”){} memblokir fungsi apa pun. Kita bisa melakukan sebaliknya, memeriksa apakah suatu variabel belum didefinisikan, sebelum kemudian mendefinisikannya. Ide-ide ini dapat diperluas ke modul ketika memeriksa apakah suatu fitur ada, jika demikian kita dapat menggunakan fitur tersebut atau mendefinisikannya sendiri.

Bab 1 cepat dan kotor, tetapi ketika saya memuat Bab 2 tentang Nilai saya melihat bilah gulir saya mengecil, masih jauh di depan! Kita akan membahas arrays, numbers, dan strings, tiga tipe bawaan yang umum. Pertama, array, yang tidak berukuran sebelumnya (seperti C), dan dapat menampung tipe data apa pun sebagai nilainya. Array juga dapat memiliki properti bernama, yang tidak mempengaruhi length. Hindari membiarkan "kosong" dalam array dengan sesuatu seperti:

var a = [ ];
a[0] = 1;
// no `a[1]` slot set here
a[2] = [ 3 ];
a[1]; // undefined
a.length; // 3

strings tidak dapat diubah di JS, tetapi dalam hal lain berperilaku seperti arrays. Beberapa konsep yang dia diskusikan juga dibahas di bagian algoritma freecodecamp, jadi saya sudah cukup familiar. Hanya ada satu jenis number, tidak perlu khawatir tentang int/float/double dll. Outputnya akan default ke representasi sederhana sehingga 42.300 akan keluar sebagai 42.3. Jika number sangat besar/kecil maka akan ditampilkan sebagai eksponensial. Untuk nilai desimal, ada beberapa masalah dengan presisi floating-point di mana 0.1+0.2===0.3 menghasilkan false. Ini bisa menjadi solusi menggunakan Number.EPSILON. Ada bilangan bulat aman min/maks berdasarkan penyimpanan 64-bit, dan jika diperlukan angka yang lebih besar, Anda harus mengonversinya menjadi string. Ada fungsi isInteger berguna yang diperkenalkan di ES6.

Nilai khusus mencakup null dan undefined, dan penting untuk memahami perbedaan di antara keduanya. Hati-hati juga bisa saja membuat identifier dengan nama undefined yang jelas bisa menimbulkan kekacauan. Ada nomor khusus seperti NaN dan Infinity. Jika Anda menambahkan ke jumlah maksimum, Anda akan mendapatkan Infinity! JS juga memiliki 0 dan -0, yang memiliki perilaku khusus dan aplikasi khusus. Ada juga beberapa permasalahan yang muncul dalam penggunaan nilai-nilai khusus ini dalam ketidaksetaraan, dan solusi yang diperlukan.

Meskipun tidak ada pointer di JS (Hore!), beberapa variabel menyimpan nilai dan beberapa menyimpan referensi. Jika ditetapkan sebagai angka, itu akan menjadi nilai, jika ditetapkan sebagai array, itu adalah referensi. Hal ini dapat menimbulkan kebingungan. Objek (termasuk array dan fungsi) diteruskan berdasarkan referensi, dan primitif berdasarkan nilai.

var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

Bab berikutnya membahas Native, yang merupakan fungsi huruf kapital seperti String(), Symbol(), Date(), Boolean() dll. Anda dapat menggunakan beberapa di antaranya untuk membuat primitif yang dibungkus dalam kotak objek melalui new String("xtz"), namun ini bukan penggunaan umum dan sebenarnya dapat memperlambat kinerja. Jika Anda memiliki pembungkus objek, Anda bisa mengeluarkan primitifnya melalui obj.valueOf(). Secara umum, menggunakan Native sebagai konstruktor adalah ide yang buruk, karena hal ini menimbulkan beberapa perilaku aneh dalam kondisi tertentu. Namun jika Anda menginginkan Date Anda harus menggunakan new Date().

Lanjut ke Bab 4tentang pemaksaan, yang tampaknya menjadi topik perdebatan hangat di JS. Hal ini telah dibahas sebelumnya pada buku pertama, membahas pemaksaan secara implisit dan eksplisit.

var a = 42;
var b = a + "";	     // implicit coercion
var c = String( a ); // explicit coercion

Kemudian buku ini membahas secara mendalam tentang bagaimana pemaksaan terjadi di dalam JS, dengan melihat fungsi toString, toNumber, toPrimitive, toBoolean. Saat mengonversi ke boolean, beberapa nilai memaksa menjadi salah: undefined, null , NaN, 0, -0, false, “”. Dalam membahas pemaksaan eksplisit, kita mempelajari beberapa teknik. Kita dapat memaksa string menjadi nomor menggunakan operator unary:

var a = “42”; 
var b = +a;
b; // 42

Menggunakan ini bukanlah cara yang disukai untuk memaksakan suatu angka karena dapat membingungkan dalam kode. Ini sering digunakan untuk memaksakan tanggal ke nomor (seperti stempel waktu) misalnya. var timestamp = +new Date(); . Tilde ~ adalah operator NOT bitwise, bila digunakan pada nomor x ia mengembalikan -(x+1). Hal ini dapat dimanfaatkan dengan cara yang menarik seperti menemukan substring. Karena ~-1berevaluasi menjadi 0, itu salah.

var a = "Hello World";
~a.indexOf( "lo" );			// -4   <-- truthy!
if (~a.indexOf( "lo" )) {	// true
	// found it!
}
~a.indexOf( "ol" );			// 0    <-- falsy!
!~a.indexOf( "ol" );		// true
if (!~a.indexOf( "ol" )) {	// true
	// not found!
}

Sebagian besar sisa bab ini memberikan panduan praktis dengan contoh-contoh nyata mengenai pemaksaan yang eksplisit dan implisit antara berbagai jenis pemaksaan. Ini akan menjadi referensi yang baik di masa mendatang jika saya menemukan sintaks atau logika yang tidak biasa di alam liar. Kemudian masuk ke perbedaan antara persamaan ketat dan longgar. Kesetaraan yang longgar memungkinkan terjadinya pemaksaan, sedangkan yang tegas tidak. Tidak ada perbedaan performa di antara keduanya, gunakan == jika Anda ingin mengizinkan pemaksaan dan === jika tidak. Saat membandingkan string dan angka, string tersebut selalu dipaksa menjadi angka. Saat membandingkan bool dan angka, bool selalu (secara implisit) dipaksa menjadi angka (jadi 0 atau 1). Hal ini tidak mudah untuk diingat, jadi lebih baik secara eksplisit atau implisit memaksa nomor tersebut menjadi bool terlebih dahulu, sebelum memeriksa. Menariknya, ketika membandingkan null dengan undefined, keduanya tidak dapat dibedakan (yaitu null == undefined bernilai true. Ada juga beberapa kasus tepi yang menarik/tidak biasa dengan operator pemaksaan dan perbandingan, yang harus dihindari oleh pengembang yang baik. Kasus yang harus dihindari umumnya melibatkan salah satu atau keduanya sebagai nilai-nilai "false-y". Ini adalah tabel menyenangkan yang dia kutip untuk diingat, saya akan mempostingnya di sini untuk referensi saya di masa mendatang juga:

Beberapa poin lagi dan kita selesai dengan bab ini. Saat mengevaluasi ekspresi seperti 42 || “abc"Anda akan mendapatkan nilai kembalian yang dalam hal ini adalah 42. Berikut aturannya:

Untuk operator ||, jika pengujiannya adalah true, ekspresi || akan menghasilkan nilai operan pertama (a atau c). Jika pengujiannya adalah false, ekspresi || menghasilkan nilai operan kedua (b).

Sebaliknya, untuk operator &&, jika pengujiannya adalah true, ekspresi && menghasilkan nilai operan kedua (b). Jika pengujiannya adalah false, ekspresi && menghasilkan nilai operan pertama (a atau c).

Dua benda dikatakan sama jika mengacu pada benda yang sama. Saat menggunakan perbandingan relasional < atau <=, pemaksaan juga bisa terjadi. Saat membandingkan dua string, keduanya dilihat secara leksikografis sehingga "043" < "42" akan bernilai true. Ini adalah bab yang panjang dengan banyak informasi, referensi yang bagus.

Mari masuk ke Tata BahasaJavaScript, yaitu cara kerja sintaksis. Kami memiliki pernyataan, yang dapat terdiri dari satu atau lebih ekspresi secara bersamaan. Semua pernyataan memiliki nilai penyelesaian, yang saya lihat di Konsol Pengembang setelah menekan enter, biasanya undefined. Selain yang kita lihat di Konsol Pengembang, ekspresi dapat memiliki efek samping yang tidak terlihat.

function foo() {
	a = a + 1;
}
var a = 1;
foo();		// result: `undefined`, side effect: changed `a`

Kurung kurawal {} digunakan dalam JavaScript untuk menunjukkan object literal atau Blok. Ada diskusi panjang tentang prioritas operator && || terutama jika menggunakan lebih dari satu dalam sebuah pernyataan. Dalam pernyataan seperti true || false && false;, && dievaluasi sebelum || jadi hasilnya benar. Selain itu, || lebih preseden dibandingkan operator ternary ? :, yang masih memerlukan waktu bagi saya untuk memahami kapan digunakan. Operator biner dan/atau bersifat asosiatif kanan, sedangkan operator ternary bersifat asosiatif kiri, hal ini menentukan cara argumen “dikelompokkan” namun tidak menentukan cara evaluasinya.

JavaScript memiliki mesin yang menambahkan titik koma secara otomatis jika Anda lupa memasukkannya. Saya cukup bersalah karena menghilangkan titik koma dalam kode saya, karena saya pertama kali mempelajari python dan mempelajari beberapa kebiasaan buruk. Salah satu risiko ASI adalah ia salah mengasumsikan di mana Anda menginginkan titik koma.

Ada struktur dalam JavaScript untuk try...catch...finally. Blok finally akan selalu berjalan, meskipun try/catch memiliki pernyataan return.

function foo() {
	try {
		return 42;
	}
	finally {
		console.log( "Hello" );
	}
	console.log( "never runs" );
}
console.log( foo() );
// Hello
// 42

Cukup banyak untuk buku ini. Seperti biasa dengan YDKJS, ada lebih banyak informasi daripada yang bisa saya rangkum. Saya harap saya memahami intinya, dan saya pasti akan menyimpan buku-buku ini sebagai referensi di masa depan.