Rumah  >  Artikel  >  hujung hadapan web  >  Ikuti saya untuk mempelajari skop javascript dan kemahiran chain_javascript skop

Ikuti saya untuk mempelajari skop javascript dan kemahiran chain_javascript skop

WBOY
WBOYasal
2016-05-16 15:31:14883semak imbas

Skop ialah salah satu konsep terpenting dalam JavaScript Jika anda ingin mempelajari JavaScript dengan baik, anda perlu memahami prinsip kerja skop dan rantaian skop JavaScript. Artikel hari ini menyediakan pengenalan ringkas kepada rantaian skop dan skop JavaScript, dengan harapan dapat membantu semua orang mempelajari JavaScript dengan lebih baik.
1. Skop JavaScript

Sebarang bahasa pengaturcaraan mempunyai konsep skop Ringkasnya, skop ialah julat pembolehubah dan fungsi yang boleh diakses, iaitu, skop mengawal keterlihatan dan kitaran hayat pembolehubah dan fungsi. Dalam JavaScript, terdapat dua jenis skop pembolehubah: skop global dan skop tempatan.

1. Skop Global

Objek yang boleh diakses di mana-mana dalam kod mempunyai skop global Secara umumnya, situasi berikut mempunyai skop global:

(1) Fungsi paling luar dan pembolehubah yang ditakrifkan di luar fungsi paling luar mempunyai skop global, contohnya:

var authorName="小平果";
function doSomething(){
 var blogName="你不知道的JavaScript";
 function innerSay(){
 alert(blogName);
 }
 innerSay();
}
alert(authorName); //小平果
alert(blogName); //脚本错误
doSomething(); //你不知道的JavaScript
innerSay() //脚本错误

(2) Semua pembolehubah yang tidak ditentukan dan diperuntukkan secara langsung diisytiharkan secara automatik mempunyai skop global, contohnya:

function doSomething(){
 var authorName="小平果";
 blogName="你不知道的JavaScript";
 alert(authorName);
}
doSomething(); //小平果
alert(blogName); //你不知道的JavaScript
alert(authorName); //脚本错误

BlogName berubah mempunyai skop global, manakala authorName tidak boleh diakses di luar fungsi.

(3) Semua sifat objek tetingkap mempunyai skop global

Secara amnya, sifat terbina dalam objek tetingkap mempunyai skop global, seperti window.name, window.location, window.top, dsb.

 2. Skop Tempatan 
Bertentangan dengan skop global, skop tempatan secara amnya hanya boleh diakses dalam serpihan tetap kod, paling biasa dalam fungsi, jadi di sesetengah tempat anda juga akan melihat orang merujuk skop ini sebagai skop fungsi, seperti kedua-dua blogName berikut dan fungsi innerSay dalam kod hanya mempunyai skop tempatan.

function doSomething(){
 var blogName="你不知道的JavaScript";
 function innerSay(){
 alert(blogName);
 }
 innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误

2. Rantaian Skop

Dalam JavaScript, fungsi juga objek Malah, semua dalam JavaScript adalah objek. Objek fungsi, seperti objek lain, mempunyai sifat yang boleh diakses melalui kod dan satu set sifat dalaman yang hanya boleh diakses oleh enjin JavaScript. Salah satu sifat dalaman ialah [[Skop]], ditakrifkan oleh edisi ketiga standard ECMA-262 ini mengandungi koleksi objek dalam skop di mana fungsi itu dicipta , yang menentukan Data mana yang boleh diakses oleh fungsi tersebut.

Apabila fungsi dicipta, rantai skopnya diisi dengan objek data yang boleh diakses dalam skop di mana fungsi itu dicipta. Contohnya, takrifkan fungsi berikut:

function add(num1,num2) {
 var sum = num1 + num2;
 return sum;
}

Apabila fungsi tambah dicipta, rantai skopnya akan diisi dengan objek global, yang mengandungi semua pembolehubah global, seperti yang ditunjukkan dalam rajah di bawah (nota: gambar hanya menggambarkan sebahagian daripada semua pembolehubah):

Skop penambahan fungsi akan digunakan semasa pelaksanaan. Sebagai contoh, laksanakan kod berikut:

var total = add(5,10);

  执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

  这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:

  在函数执行过程中,没遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。

三、作用域链和代码优化

  从作用域链的结构可以看出,在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。如上图所示,因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。一个好的经验法则是:如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。例如下面的代码:

function changeColor(){
 document.getElementById("btnChange").onclick=function(){
 document.getElementById("targetCanvas").style.backgroundColor="red";
 };
}

  这个函数引用了两次全局变量document,查找该变量必须遍历整个作用域链,直到最后在全局对象中才能找到。这段代码可以重写如下:

function changeColor(){
 var doc=document;
 doc.getElementById("btnChange").onclick=function(){
 doc.getElementById("targetCanvas").style.backgroundColor="red";
 };
}

  这段代码比较简单,重写后不会显示出巨大的性能提升,但是如果程序中有大量的全局变量被从反复访问,那么重写后的代码性能会有显著改善。

四、改变作用域链

  函数每次执行时对应的运行期上下文都是独一无二的,所以多次调用同一个函数就会导致创建多个运行期上下文,当函数执行完毕,执行上下文会被销毁。每一个运行期上下文都和一个作用域链关联。一般情况下,在运行期上下文运行的过程中,其作用域链只会被 with 语句和 catch 语句影响。

  with语句是对象的快捷应用方式,用来避免书写重复代码。例如:

function initUI(){
 with(document){
 var bd=body,
 links=getElementsByTagName("a"),
 i=0,
 len=links.length;
 while(i < len){
 update(links[i++]);
 }
 getElementById("btnInit").onclick=function(){
 doSomething();
 };
 }
}

  这里使用width语句来避免多次书写document,看上去更高效,实际上产生了性能问题。

  当代码运行到with语句时,运行期上下文的作用域链临时被改变了。一个新的可变对象被创建,它包含了参数指定的对象的所有属性。这个对象将被推入作用域链的头部,这意味着函数的所有局部变量现在处于第二个作用域链对象中,因此访问代价更高了。如下图所示:

  因此在程序中应避免使用with语句,在这个例子中,只要简单的把document存储在一个局部变量中就可以提升性能。

  另外一个会改变作用域链的是try-catch语句中的catch语句。当try代码块中发生错误时,执行过程会跳转到catch语句,然后把异常对象推入一个可变对象并置于作用域的头部。在catch代码块内部,函数的所有局部变量将会被放在第二个作用域链对象中。示例代码:

try{
 doSomething();
}catch(ex){
 alert(ex.message); //作用域链在此处改变
}

  请注意,一旦catch语句执行完毕,作用域链机会返回到之前的状态。try-catch语句在代码调试和异常处理中非常有用,因此不建议完全避免。你可以通过优化代码来减少catch语句对性能的影响。一个很好的模式是将错误委托给一个函数处理,例如:

try{
 doSomething();
}catch(ex){
 handleError(ex); //委托给处理器方法
}

  

Dalam kod yang dioptimumkan, kaedah handleError ialah satu-satunya kod yang dilaksanakan dalam klausa tangkapan. Fungsi ini menerima objek pengecualian sebagai parameter, supaya anda boleh mengendalikan ralat dengan lebih fleksibel dan seragam. Memandangkan hanya satu pernyataan dilaksanakan dan tiada pembolehubah tempatan diakses, perubahan sementara dalam rantaian skop tidak akan menjejaskan prestasi kod.

Di atas adalah keseluruhan kandungan artikel ini, saya berharap melalui artikel ini semua orang akan mempunyai pemahaman yang lebih baik tentang skop dan rantaian skop JavaScript, dan kita boleh membuat kemajuan bersama.

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn