Bercakap tentang kata kunci dengan dalam js, tanggapan pertama ramai rakan mungkin bahawa fungsi kata kunci dengan adalah untuk menukar skop, dan perkara yang paling penting ialah penggunaan kata kunci dengan tidak disyorkan. Selepas mendengar kata kunci dengan tidak disyorkan, ramai di antara kita akan mengabaikan kata kunci dengan, memikirkan bahawa kita boleh mengabaikannya dan menggunakannya sahaja. Tetapi kadangkala, apabila kita melihat beberapa soalan kod atau temuduga, akan timbul soalan berkaitan dengan kata kunci Terdapat banyak perangkap yang anda tidak pernah terdedah, jadi masih perlu bercakap tentang kata kunci dengan.
1. Arahan asas
Kata kunci with diterangkan dalam pengaturcaraan lanjutan js seperti ini: Fungsi pernyataan with adalah untuk menetapkan skop kod kepada skop tertentu Sintaks asas adalah seperti berikut:
with (expression) statement;
Tujuan menggunakan kata kunci dengan adalah untuk memudahkan kerja menulis dan mengakses objek yang sama beberapa kali, seperti contoh berikut:
var qs = location.search.substring(1); var hostName = location.hostname; var url = location.href;
Barisan kod ini mengakses sifat dalam objek lokasi Jika anda menggunakan kata kunci dengan, kod tersebut boleh dipermudahkan seperti berikut:
with (location){ var qs = search.substring(1); var hostName = hostname; var url = href; }
Dalam kod ini, pernyataan dengan digunakan untuk mengaitkan objek lokasi Ini bermakna dalam blok kod dengan, setiap pembolehubah pertama kali dianggap pembolehubah tempatan Jika pembolehubah tempatan mempunyai nama yang sama dengan sifat lokasi object, , maka pembolehubah tempatan ini akan menunjuk kepada atribut objek lokasi.
Nota: Pernyataan dengan tidak boleh digunakan dalam mod ketat.
2. Kelemahan dengan kata kunci
Dalam penerangan asas sebelum ini, kita dapat melihat bahawa salah satu fungsi dengan adalah untuk memudahkan kod. Tetapi mengapa ia tidak disyorkan? Mari kita bincangkan tentang kekurangan dengan:
1. Isu prestasi
2. Semantik tidak jelas dan sukar untuk nyahpepijat
3. Isu prestasi
Mula-mula mari kita bincangkan tentang isu prestasi menggunakan kata kunci dengan, mula-mula mari kita lihat dua keping kod:
Sekeping kod pertama tidak menggunakan kata kunci dengan:
function func() { console.time("func"); var obj = { a: [1, 2, 3] }; for (var i = 0; i < 100000; i++) { var v = obj.a[0]; } console.timeEnd("func");//0.847ms } func();
Kod kedua menggunakan kata kunci dengan:
function funcWith() { console.time("funcWith"); var obj = { a: [1, 2, 3] }; var obj2 = { x: 2 }; with (obj2) { console.log(x); for (var i = 0; i < 100000; i++) { var v = obj.a[0]; } } console.timeEnd("funcWith");//84.808ms } funcWith();
Selepas menggunakan kata kunci dengan, prestasi kod dikurangkan dengan banyaknya. Pernyataan dengan dalam sekeping kod kedua bertindak pada objek obj2, dan kemudian objek obj diakses dalam blok dengan. Terdapat pandangan bahawa selepas menggunakan kata kunci dengan, apabila mengakses pembolehubah dalam blok dengan, ia akan terlebih dahulu mencari sama ada terdapat atribut bernama obj pada obj2, kemudian teruskan ke carian seterusnya dalam prestasi. Tetapi adakah ini benar-benar sebab mengapa prestasi program sebenarnya merosot?
Mari ubah suai kod kedua seperti berikut:
function funcWith() { console.time("funcWith"); var obj = { a: [1, 2, 3] }; with (obj) { for (var i = 0; i < 100000; i++) { var v = a[0]; } } console.timeEnd("funcWith");//88.260ms } funcWith();
Kod ini menggunakan pernyataan with pada objek obj, dan kemudian secara langsung menggunakan a untuk mengakses atribut obj Menurut sudut pandangan yang dinyatakan sebelum ini, apabila mengakses atribut, atribut boleh ditemui pada obj in sekali sahaja. Tetapi mengapa prestasi kod masih dikurangkan?
Sebab sebenar ialah: selepas menggunakan kata kunci dengan, enjin JS tidak boleh mengoptimumkan kod ini.
Enjin JS mempunyai fasa kompilasi sebelum kod dilaksanakan Apabila kata kunci dengan tidak digunakan, enjin JS mengetahui bahawa a ialah atribut pada obj, dan ia boleh menganalisis kod secara statik untuk mempertingkatkan penghuraian pengecam, dengan itu mengoptimumkan. kod. Oleh itu Kecekapan pelaksanaan kod dipertingkatkan. Selepas menggunakan kata kunci dengan, enjin js tidak dapat mengetahui sama ada pembolehubah adalah pembolehubah tempatan atau atribut obj Oleh itu, selepas enjin js menemui kata kunci dengan, ia akan berhenti mengoptimumkan kod ini, jadi kecekapan pelaksanaan dikurangkan. .
Satu lagi kesan penggunaan kata kunci dengan pada prestasi ialah alat pemampatan js, yang tidak boleh memampatkan kod ini, yang juga merupakan faktor yang mempengaruhi prestasi.
4. Semantik tidak jelas dan sukar untuk dinyahpepijat
Seperti yang dinyatakan sebelum ini, sebagai tambahan kepada isu prestasi, ia juga mempunyai kelemahan semantik yang tidak jelas dan kesukaran dalam penyahpepijatan, yang menjadikan kod sukar dibaca dan boleh menyebabkan potensi pepijat.
function foo(obj) { with (obj) { a = 2; } } var o1 = { a: 3 }; var o2 = { b: 3 }; foo(o1); console.log(o1.a); // 2 foo(o2); console.log( o2.a ); // undefined console.log( a ); // 2
Kod ini mudah difahami Dalam fungsi foo, kata kunci dengan digunakan untuk mengakses objek obj yang diluluskan, dan kemudian mengubah suai atribut a. Apabila objek o1 dilalui, kerana objek o1 mempunyai atribut a, tidak ada masalah. Apabila objek o2 dihantar masuk, apabila atribut diubah suai, kerana objek o2 tidak mempunyai atribut, atribut yang diubah suai menjadi pembolehubah global. Ini mewujudkan potensi pepijat.
5. Analisis Lanjutan
Setelah berkata begitu banyak sebelum ini, saya percaya semua orang telah memahami mengapa tidak disyorkan untuk menggunakan kata kunci dengan dan kemungkinan masalah. Mari kita lihat beberapa situasi yang lebih kompleks, lihat kod berikut:
var obj = { x: 10, foo: function () { with (this) { var x = 20; var y = 30; console.log(y);//30 } } }; obj.foo(); console.log(obj.x);//20 console.log(obj.y);//undefined
在这段代码中,分别输出30,20,undefined的。涉及的知识点也比较多:with关键字,this关键字,变量提升等等,我们来一一解释一下。
1、this关键字
关于this关键字的文章google上面相当多,这里不再赘述,我们只需记住一点:this关键字始终指向调用函数的对象。在这里,foo函数中,this指向的就是obj对象。因此在with(this)语句块里面,可以直接通过x变量来访问obj的x属性。
2、变量提升
js中的变量提升也是一个经常遇到的问题,我们可以简单理解成在js中,变量声明会被提升到函数的顶部,尽管有的时候,它是在后面声明的。
所以上面的代码可以解析为:
var obj = { x: 10, foo: function () { var x;//声明局部变量x var y;//声明局部变量y with (obj) { x = 20;//访问变量x,在obj上找到x,则修改为20 y = 30;//访问变量y,在bojg上找不到y,则进一步查找,找到局部变量y,修改为30 console.log(y);//30//直接输出局部变量y, } } }; obj.foo(); console.log(obj.x);//20,obj.x已被修改为20 console.log(obj.y);//undefined,obj不存在y属性,则为undefined
上面的注释中,解释了代码的执行过程,相信大家已经理解了为什么会出处30,20,undefined的原因。
有兴趣的同学可以看看下面这段代码:
({ x: 10, foo: function () { function bar() { console.log(x); console.log(y); console.log(this.x); } with (this) { var x = 20; var y = 30; bar.call(this); } } }).foo();
这段代码会输出什么?为什么呢?
总结
本文总结了with语句的特点和弊端,总的来说,强烈不推荐使用with关键字。其实在日常编码中,我们只需要知道不去使用with就可以了,但是有的时候我们可能会遇到一些关于with的奇奇怪怪的问题,想要找出真正的原因,就要深入理解with关键字,这有助于我们去深入学习JS这门语言,同时也是学习JS的一个乐趣。