Rumah >hujung hadapan web >tutorial js >Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS
Artikel ini membawa anda pengetahuan yang berkaitan tentang javascript Ia terutamanya memperkenalkan isu berkaitan tentang cara enjin js melaksanakan kod js Apabila enjin js melaksanakan kod js, ia juga akan bermula dari atas ke bawah. Analisis leksikal, analisis sintaks, analisis semantik dan pemprosesan lain dilakukan di bawah, dan AST dijana selepas analisis kod selesai.
Cadangan berkaitan: Tutorial javascript
Kita mungkin sering mendengar "persekitaran pelaksanaan", "skop", "prototaip" (rantai )", "konteks pelaksanaan", dsb., apakah yang mereka gambarkan?
Kami tahu bahawa js ialah bahasa yang ditaip lemah dan jenis pembolehubah ditentukan pada masa jalan. Apabila enjin js melaksanakan kod js, ia juga akan melaksanakan analisis leksikal, analisis tatabahasa, analisis semantik dan proses lain dari atas ke bawah, dan selepas penghuraian kod selesai Jana AST (Pokok Sintaks Abstrak), dan akhirnya menjana kod mesin yang CPU boleh laksanakan berdasarkan AST dan laksanakannya.
Selain itu, enjin JS juga akan melakukan pemprosesan lain apabila melaksanakan kod Contohnya, terdapat dua peringkat dalam V8:
Ini memperkenalkan dua konsep: "konteks pelaksanaan" dan "rantai skop".
Daripada perkara di atas kita boleh tahu: apabila kod js melaksanakan sekeping kod boleh laku, konteks pelaksanaan yang sepadan akan dibuat.
Pertama sekali, terdapat konsep yang sepadan dengan kod boleh laku dalam js: "persekitaran pelaksanaan" - persekitaran global, persekitaran fungsi dan eval
.
Kedua, untuk setiap konteks pelaksanaan, terdapat tiga sifat penting:
Mari kita lihat dua keping kod:
var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS="global Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS";function checkPemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS(){ var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS="local Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS"; function f(){ return Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS; } return f();}checkPemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS();
var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS="global Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS";function checkPemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS(){ var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS="local Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS"; function f(){ return Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS; } return f;}checkPemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS()();
Apakah yang akan mereka cetak?
Kenapa? Jawapannya ialah susunan konteks pelaksanaan mereka berbeza!
Apakah itu "timbunan konteks pelaksanaan"?
Apabila melaksanakan kod boleh laku, persediaan akan dibuat lebih awal "kerja penyediaan" di sini secara profesional dipanggil "konteks pelaksanaan". Tetapi dengan peningkatan dalam kod boleh laku seperti fungsi, bagaimana untuk menguruskan banyak konteks pelaksanaan? Jadi enjin JS mencipta konsep timbunan konteks pelaksanaan.
Kita boleh menggunakan tatasusunan sepenuhnya untuk mensimulasikan kelakuannya (sentiasa terdapat konteks pelaksanaan global globalContext di bahagian bawah tindanan)
Kami mentakrifkan EStack, pertama
EStack=[globalContext];
dan kemudian simulasikannya Sekeping kod pertama:
EStack.push(<checkpemahaman mendalam tentang cara enjin javascript melaksanakan kod js> functionContext);EStack.push(<f> functionContext);EStack.pop();EStack.pop();</f></checkpemahaman>
Sekeping kod kedua adalah seperti ini:
EStack.push(<checkpemahaman mendalam tentang cara enjin javascript melaksanakan kod js> functionContext);EStack.pop();EStack.push(<f> functionContext);EStack.pop();</f></checkpemahaman>
Sebabnya ialah anda mungkin perlu mengkaji konsep "penutupan" dahulu!
Dengan cara ini, bagaimana untuk mencapai "penjimatan data jangka panjang" dalam "pemodularan bahagian hadapan"?
Caching? Tidak. Penutupan!
Pertama sekali, skop merujuk kepada kawasan dalam program di mana pembolehubah ditakrifkan. Skop menentukan cara untuk mencari pembolehubah, yang menentukan hak akses kod yang sedang melaksanakan kepada pembolehubah.
Terdapat dua jenis skop: skop statik dan skop dinamik.
Skop statik yang digunakan oleh JS juga dipanggil "skop leksikal". Skop fungsi ditentukan apabila fungsi ditakrifkan.
Daripada perkara di atas, pembolehubah dalam skop leksikal akan mempunyai skop tertentu semasa proses penyusunan. Skop ini ialah "konteks pelaksanaan semasa". Selepas ES5 kami menggunakan "persekitaran leksikal" dan bukannya skop untuk menerangkan konteks pelaksanaan. Persekitaran leksikal terdiri daripada dua ahli:
Mari kita lihat contoh:
var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS=1;function foo(){ console.log(Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS);}function bar(){ var Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS=2; foo();}bar();
Melihat kembali definisi di atas, apakah yang perlu dicetak?
Mari kita menganalisis proses pelaksanaan:
Jalankan fungsi foo(), mula-mula lihat di dalam fungsi foo untuk melihat sama ada terdapat nilai pembolehubah setempat. Jika tidak, akan mencari kod pada lapisan atas berdasarkan kedudukan apabila ia ditakrifkan, iaitu nilai=1 Jadi hasilnya akan dicetak sebagai 1.
Sudah tentu ia tidak begitu mudah dan boleh diringkaskan anda boleh menganalisisnya dari perspektif konteks pelaksanaan.
上面我们说了词法环境(作用域)的两个组成。再结合执行上下文,我们不难发现:通过外部词法环境的引用,作用域可以顺着栈层层拓展,建立起从当前环境向外延伸的一条链式结构。
再来看一个例子:
function foo(){ console.dir(bar); var a=1; function bar(){ a=2; }}console.dir(foo);foo();
由静态作用域,全局函数foo创建了一个自身对象的 [[Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS]]
属性
foo[[Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS]]=[globalContext];
而当我们执行foo()时,也会先后进入foo函数的定义期和执行期。在foo函数的定义期时,函数bar的 [[Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS]]
将会包含全局内置Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS和foo的内置Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS
bar[[Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS]]=[fooContext,globalContext];
这证明了这一点:“JS会通过外部词法环境引用来创建变量对象的一个作用域链,从而保证对执行环境有权访问的变量和函数的有序访问。”
让我们再回头看看执行上下文中的那道题,在前面我们说了它们有什么不同,这里说下为什么它们相同地打印了“local Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS”:还是那句话“JS采用的是词法作用域,函数的作用域取决于函数创建的位置” —— JS函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS一定是指局部变量,不管何时何地执行 f() ,这种绑定在执行 f() 时依然有效。
当某个变量无法在自身词法环境记录中找到时,可以根据外部词法环境引用向外层进行寻找,直到最外层的词法环境中外部词法环境引用为null
。
与此相似的是“对象中基于原型链的查找”:
__proto__
为null)为止它们的区别也显而易见:原型链是通过 prototype 属性建立对象继承的链接;而作用域链是指内部函数能访问到外部函数的闭包。不管直接还是间接,所有函数的作用域链最终都链接到全局上下文。
相关推荐:javascript学习教程
Atas ialah kandungan terperinci Pemahaman mendalam tentang cara enjin JavaScript melaksanakan kod JS. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!