Mengapa JavaScript diperlukan mode ketat?

Mode ketat adalah bagian penting dari JavaScript modern. Mode ini yang memungkinkan pengembang untuk menggunakan lebih terbatas daripada sintaksis standar.

Semantik mode ketat berbeda dari mode non-ketat tradisional, yang kadang-kadang disebut "mode ceroboh". Dalam mode ini, aturan sintaks bahasa tidak begitu ketat, dan ketika beberapa kesalahan terjadi, sistem tidak memberi tahu pengguna tentang mereka. Yaitu, kesalahan dapat diabaikan, dan kode di mana mereka dibuat dapat dieksekusi lebih lanjut. Ini dapat menyebabkan hasil eksekusi kode yang tidak terduga.



Mode ketat memperkenalkan beberapa perubahan pada semantik JavaScript. Ini mencegah sistem dari menutup mata terhadap kesalahan dengan melemparkan pengecualian yang sesuai. Ini menyebabkan eksekusi program terhenti.

Mode ketat, di samping itu, membantu dalam menulis program di mana tidak ada kekurangan yang mencegah mesin JS dari mengoptimalkan kode. Lebih lanjut, dalam mode ini dilarang menggunakan elemen sintaks yang mungkin mendapatkan makna khusus dalam versi bahasa yang akan datang.

Fitur menggunakan mode ketat


Mode ketat dapat diterapkan ke fungsi individual atau ke seluruh skrip. Itu tidak bisa diterapkan hanya pada instruksi individual atau pada blok kode yang dilampirkan dalam kurung kurawal. Untuk menggunakan mode ketat di tingkat keseluruhan skrip, di bagian paling awal file, sebelum perintah lain, Anda harus "use strict" atau 'use strict' konstruksi 'use strict' .

Jika proyek memiliki beberapa skrip yang tidak menggunakan mode ketat, dan lain-lain yang menggunakan mode ini, maka mungkin saja skrip ini digabungkan.

Ini akan mengarah pada fakta bahwa kode yang tidak dimaksudkan untuk dieksekusi dalam mode ketat akan berada dalam keadaan seperti itu ketika sistem mencoba untuk mengeksekusinya dalam mode ketat. Kebalikannya juga dimungkinkan - kode yang ditulis untuk mode ketat akan jatuh ke mode non-ketat. Karena itu, yang terbaik adalah tidak mencampur skrip "ketat" dan "tidak ketat".

Seperti yang telah disebutkan, mode ketat dapat diterapkan ke fungsi individual. Untuk melakukan ini - konstruksi "use strict" atau 'use strict' harus ditempatkan di bagian atas tubuh fungsi, sebelum perintah lainnya. Mode ketat dengan pendekatan ini berlaku untuk semua yang ditempatkan di tubuh fungsi, termasuk fungsi bersarang.

Sebagai contoh:

 const strictFunction = ()=>{  'use strict';  const nestedFunction = ()=>{    //        } } 

Dalam modul JavaScript yang muncul dalam standar ES2015, mode ketat diaktifkan secara default. Karena itu, ketika bekerja dengan mereka, Anda tidak perlu memasukkannya secara eksplisit.

Perubahan yang diperkenalkan ke kode JS dengan mode ketat


Mode ketat memengaruhi sintaksis kode dan cara kode berperilaku selama eksekusi program. Kesalahan dalam kode dikonversi menjadi pengecualian. Fakta bahwa dalam mode diam diam-diam crash dalam mode ketat menyebabkan pesan kesalahan. Ini mirip dengan bagaimana sistem merespons kesalahan sintaks dalam mode lax. Dalam mode ketat, bekerja dengan variabel disederhanakan, penggunaan fungsi eval dan objek arguments diatur dengan ketat, dan bekerja dengan konstruksi yang dapat diimplementasikan dalam versi bahasa yang akan datang disederhanakan.

โ– Konversi kesalahan diam menjadi pengecualian


Kesalahan diam dikonversi dalam mode ketat ke pengecualian. Dalam mode longgar, sistem tidak secara eksplisit merespons kesalahan tersebut. Dalam mode ketat, keberadaan kesalahan seperti itu menyebabkan kode tidak dapat dioperasikan.

Jadi, berkat ini, sulit untuk membuat kesalahan dengan secara tidak sengaja mendeklarasikan variabel global, karena variabel dan konstanta dalam mode ketat tidak dapat dideklarasikan tanpa menggunakan arahan var , let atau const . Akibatnya, membuat variabel tanpa arahan ini akan menyebabkan program tidak dapat dioperasikan. Misalnya, mencoba untuk mengeksekusi kode berikut akan memunculkan exception ReferenceError :

 'use strict'; badVariable = 1; 

Kode tersebut tidak dapat dijalankan dalam mode ketat, karena jika mode ketat dimatikan, itu akan membuat variabel global badVariable . Mode ketat melindungi programmer dari membuat variabel global secara tidak sengaja.

Upaya untuk mengeksekusi kode apa pun yang, dalam mode normal, tidak berfungsi, sekarang melempar pengecualian. Kesalahan dianggap sebagai konstruksi sintaksis yang salah yang diabaikan begitu saja dalam mode longgar.

Jadi, misalnya, dalam mode ketat, Anda tidak bisa melakukan operasi penetapan nilai pada entitas read-only seperti arguments , NaN atau eval .

Dalam mode ketat, pengecualian, misalnya, akan dilemparkan dalam kasus berikut:

  • upaya untuk menetapkan nilai ke properti hanya-baca, seperti beberapa jenis properti global yang dapat ditulis ulang;
  • upaya untuk menulis nilai ke properti yang hanya memiliki pengambil;
  • Upaya untuk menulis sesuatu ke properti objek yang tidak dapat diperluas.

Berikut adalah contoh konstruksi sintaks yang mengarah ke pengecualian mode ketat:

 'use strict'; let undefined = 5; let Infinity = 5; let obj = {}; Object.defineProperty(obj, 'foo', { value: 1, writable: false }); obj.foo = 1 let obj2 = { get foo() { return 17; } }; obj2.foo = 2 let fixedObj = {}; Object.preventExtensions(fixedObj); fixed.bar= 1; 

Mencoba menjalankan fragmen kode tersebut dalam mode ketat akan menghasilkan pengecualian TypeError . Misalnya, undefined dan Infinity adalah entitas global yang nilainya tidak dapat ditimpa, dan properti foo objek obj tidak mendukung penulisan ulang. Properti foo dari obj2 hanya memiliki pengambil. Objek fixedObj dibuat non-extensible menggunakan metode Object.preventExtensions .

Upaya menghapus TypeError terhapuskan juga akan menghasilkan TypeError :

 'use strict'; delete Array.prototype 

Mode ketat melarang menetapkan properti dengan nama yang sama ke objek. Akibatnya, upaya untuk mengeksekusi kode berikut akan menghasilkan kesalahan sintaksis:

 'use strict'; let o = { a: 1, a: 2 }; 

Mode ketat membutuhkan nama parameter fungsi menjadi unik. Dalam mode non-ketat, jika, misalnya, dua parameter fungsi memiliki nama yang sama one , maka, ketika melewati fungsi argumen, nilai parameter akan menjadi apa yang termasuk dalam argumen yang dinyatakan terakhir.

Dalam mode ketat, parameter fungsi dengan nama yang sama dilarang. Akibatnya, upaya untuk mengeksekusi kode berikut akan menghasilkan kesalahan sintaksis:

 'use strict'; const multiply = (x, x, y) => x*x*y; 

Dalam mode ketat, Anda tidak dapat menggunakan notasi oktal angka, mendahului angka dengan nol. Ini tidak ada dalam spesifikasi, tetapi fitur ini didukung oleh browser.

Keadaan ini membingungkan pengembang, memaksa mereka untuk percaya bahwa angka 0 sebelumnya diabaikan, tanpa banyak akal. Dalam mode ketat, mencoba menggunakan angka di awal yang 0 akan menghasilkan kesalahan sintaks.

Mode ketat juga melarang penggunaan konstruksi yang menghambat optimasi. Penerjemah, sebelum melakukan optimasi kode, perlu tahu bahwa variabel disimpan tepat di mana, menurut penerjemah, itu disimpan. Dalam mode ketat, hal-hal yang mengganggu optimasi dilarang.

Salah satu contoh larangan semacam itu menyangkut pernyataan with . Jika Anda menggunakan instruksi ini, ini mencegah penerjemah JS dari menemukan variabel atau properti mana yang kami maksudkan, karena ada kemungkinan bahwa entitas dengan nama yang sama ada di luar dan di dalam blok pernyataan with .

Misalkan ada kode seperti ini:

 let x = 1; with (obj) {  x; } 

Penerjemah tidak akan dapat mengetahui apakah variabel x terletak di dalam blok with mengacu pada variabel eksternal x , atau ke properti obj.x dari objek obj .

Akibatnya, tidak jelas persis di mana nilai x akan berada di memori. Untuk menghilangkan ambiguitas seperti itu, dalam mode ketat penggunaan pernyataan with dilarang. Mari kita lihat apa yang terjadi jika Anda mencoba menjalankan kode berikut dalam mode ketat:

 'use strict'; let x = 1; with (obj) {  x; } 

Hasil dari upaya ini akan menjadi kesalahan sintaksis.

Bahkan dalam mode ketat, dilarang untuk mendeklarasikan variabel dalam kode yang diteruskan ke metode eval .

Misalnya, dalam mode normal, perintah form eval('let x') akan menghasilkan deklarasi variabel x . Hal ini memungkinkan pemrogram untuk menyembunyikan deklarasi variabel dalam string, yang dapat menyebabkan menimpa definisi variabel yang sama di luar eval .

Untuk mencegah hal ini, dalam mode ketat dilarang untuk mendeklarasikan variabel dalam kode yang diteruskan sebagai string ke metode eval .

Mode ketat juga melarang penghapusan variabel reguler. Akibatnya, mencoba mengeksekusi kode berikut akan menghasilkan kesalahan sintaksis:

 'use strict'; let x; delete x; 

โ– Melarang konstruksi sintaks yang salah


Dalam mode ketat, penggunaan yang salah dari arguments dan arguments dilarang. Ini adalah larangan semua jenis manipulasi dengan mereka. Sebagai contoh, ini adalah sesuatu seperti memberikan nilai baru kepada mereka, menggunakan nama mereka sebagai nama variabel, fungsi, parameter fungsi.

Berikut adalah contoh penyalahgunaan eval dan arguments :

 'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = { set p(arguments) { } }; let eval; try { } catch (arguments) { } try { } catch (eval) { } function x(eval) { } function arguments() { } let y = function eval() { }; let eval = ()=>{ }; let f = new Function('arguments', "'use strict'; return 1;"); 

Dalam mode ketat, Anda tidak bisa membuat alias untuk objek arguments dan menetapkan nilai arguments baru melalui alias ini.

Dalam mode normal, jika parameter pertama dari fungsi adalah a , maka pengaturan nilai a dalam kode fungsi juga mengarah ke perubahan nilai dalam arguments[0] . Dalam mode ketat, arguments akan selalu berisi daftar argumen yang dengannya fungsi dipanggil.

Misalkan Anda memiliki kode berikut:

 const fn = function(a) {  'use strict';  a = 2;  return [a, arguments[0]]; } console.log(fn(1)) 

Konsol akan mendapatkan [2,1] . Ini karena menulis nilai 2 ke a tidak menulis nilai 2 ke arguments[0] .

PtOptimasi kinerja


Dalam mode ketat, properti arguments.callee tidak didukung. Dalam mode normal, ia mengembalikan nama fungsi induk dari fungsi yang properti callee dari objek arguments kita periksa.

Dukungan untuk properti ini mengganggu optimisasi, seperti fungsi inlining, karena menggunakan arguments.callee membutuhkan ketersediaan referensi ke fungsi yang tidak tertanam ketika mengakses properti ini. Dalam mode ketat, menggunakan arguments.callee memunculkan exception TypeError .

Dalam mode ketat, this ini tidak harus selalu menjadi objek. Dalam keadaan normal, jika fungsi ini terikat, menggunakan call , apply atau bind , untuk sesuatu yang bukan objek, ke nilai tipe primitif seperti undefined , null , number atau boolean , nilai seperti itu harus menjadi objek.

Jika konteks this berubah menjadi sesuatu yang bukan objek, objek global akan menggantikannya. Misalnya, window . Ini berarti bahwa jika Anda memanggil fungsi dengan mengatur this ke nilai yang bukan objek, bukan nilai ini, referensi ke objek global akan jatuh ke this .

Pertimbangkan sebuah contoh:

 'use strict'; function fn() {  return this; } console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true); 

Semua perintah console.log akan menghasilkan true , karena dalam mode ketat nilai this dalam fungsi tidak secara otomatis diganti oleh referensi ke objek global jika this disetel ke nilai yang bukan objek.

โ– Perubahan terkait keamanan


Dalam mode ketat, Anda tidak dapat membuat properti fungsi caller dan arguments publik. Faktanya adalah caller , misalnya, dapat memberikan akses ke fungsi yang disebut fungsi yang properti caller sedang kita akses.

Objek arguments menyimpan argumen yang dilewatkan ke fungsi ketika dipanggil. Misalnya, jika kita memiliki fungsi fn , ini berarti bahwa melalui fn.caller Anda dapat mengakses fungsi yang disebut fungsi, dan menggunakan fn.arguments Anda dapat melihat argumen yang dilewatkan ke fn ketika dipanggil.

Fitur-fitur ini berpotensi menimbulkan risiko keamanan. Akibatnya, akses ke properti ini dilarang dalam mode ketat.

 function secretFunction() {  'use strict';  secretFunction.caller;  secretFunction.arguments; } function restrictedRunner() {  return secretFunction(); } restrictedRunner(); 

Pada contoh sebelumnya, kita tidak bisa, dalam mode ketat, mengakses secretFunction.caller dan secretFunction.arguments . Faktanya adalah bahwa properti ini dapat digunakan untuk mendapatkan setumpuk panggilan fungsi. Jika Anda mencoba menjalankan kode ini, pengecualian TypeError akan TypeError .

Dalam mode ketat, pengidentifikasi yang dapat digunakan dalam versi JavaScript yang akan datang tidak dapat digunakan untuk memberi nama variabel atau properti objek. Sebagai contoh, kita berbicara tentang pengidentifikasi berikut: implements , interface , let , package , private , protected , public , static dan yield .

Dalam ES2015 dan dalam versi standar selanjutnya, pengidentifikasi ini menjadi kata-kata yang dicadangkan. Dan mereka tidak dapat digunakan untuk memberi nama variabel atau properti dalam mode ketat.

Ringkasan


Mode ketat adalah standar yang telah ada selama bertahun-tahun. Ia menikmati dukungan browser yang sangat luas. Masalah dengan kode mode ketat hanya dapat terjadi di browser lama, seperti Internet Explorer.

Browser modern seharusnya tidak mengalami kesulitan dengan mode JavaScript yang ketat. Akibatnya, kita dapat mengatakan bahwa mode ini harus digunakan untuk mencegah kesalahan "diam" dan untuk meningkatkan keamanan aplikasi. Kesalahan diam dikonversi menjadi pengecualian yang menghambat pelaksanaan program, dan dalam hal meningkatkan keamanan, misalnya, mekanisme mode ketat yang membatasi eval dan mencegah akses ke tumpukan panggilan fungsi dapat dicatat. Selain itu, penggunaan mode ketat memfasilitasi optimalisasi kode mesin JS dan memaksa programmer untuk hati-hati menangani kata-kata yang disimpan yang mungkin digunakan dalam versi JavaScript yang akan datang.

Pembaca yang budiman! Apakah Anda menggunakan mode ketat saat menulis kode JS untuk proyek Anda?


Source: https://habr.com/ru/post/id477284/


All Articles