sách gpt4 ăn đã đi

Giới thiệu về JavaScript ③-Function (2) Nguyên tắc {Chuyên sâu} Bối cảnh thực thi

In lại Tác giả: Tôi là chú chim nhỏ Thời gian cập nhật: 2022-12-02 14:31:19 28 4
mua khóa gpt4 giày nike

hình ảnh.png

00. Việc đóng JS và phạm vi từ vựng có gây đau đầu không?

Tôi đang rất đau đầu với các phần đóng, ngữ cảnh, hàm lồng nhau của JavaScript và điều này. Ngôn ngữ này được thiết kế để tạo cảm giác khó hiểu, vì vậy tôi sẽ cố gắng hiểu và tóm tắt nó trước.

  • Tại sao lại có chuyện đóng cửa? Việc đóng cửa bao bọc những gì?
  • phạm vi từ vựng là gì?
  • Chức năng được thực hiện như thế nào?

hình ảnh


01. Bối cảnh thực thi

tên mô tả
Nó là gì? bối cảnh thực thi (bối cảnh thực hiện) JavaScript Một khái niệm trừu tượng về môi trường trong đó mã được phân tích cú pháp và thực thi. mọi chức năng thực hiện Mỗi lần, nó tạo bối cảnh thực thi riêng, lưu thông tin cần thiết khi hàm được chạy và chạy hàm thông qua ngữ cảnh của chính nó.
Nó dùng để làm gì? Tất nhiên, đó là để tự mình chạy chức năng và nhận ra giá trị của chính nó.
Có những loại nào? ① Bối cảnh toàn cầu : Bối cảnh thực thi cơ bản nhất của môi trường toàn cầu, tất cả mã không nằm trong bất kỳ chức năng nào đều nằm trong đó.
Đối tượng chung trong trình duyệt là cửa sổ , trong phạm vi toàn cầu của chúng tôi Các biến được khai báo và khai báo ngầm sẽ trở thành các biến thuộc tính toàn cục Global. cái này định hướng cửa sổ
Một số đối tượng toàn cục hoặc hàm toàn cục sẽ được khởi tạo, chẳng hạn như trong mã bàn điều khiển không xác định làNaN
② Bối cảnh chức năng : Mỗi hàm có bối cảnh riêng, được tạo khi hàm được gọi. Bối cảnh toàn cục có thể được coi là bối cảnh hàm gốc cấp cao nhất.
đánh giá() gọi bối cảnh nội bộ đánh giá Mã sẽ được biên dịch để tạo bối cảnh thực thi riêng, không được sử dụng phổ biến và không được khuyến khích. Dựa trên tính năng này, một số framework sẽ sử dụng đánh giá() Để triển khai Sandbox sandbox.
Thông tin nào được lưu? Khởi tạo các biến ngữ cảnh, hàm và thông tin khác
🔸 Giá trị này cái này Tham chiếu đối tượng môi trường
🔸 Môi trường nội bộ (Cục bộ) : Tất cả các biến, hàm và tham số (đối số) cục bộ của hàm.
🔸 chuỗi phạm vi : Thông tin theo ngữ cảnh bổ sung với phạm vi truy cập.
Ai sẽ sử dụng nó? bối cảnh thực thi phụ thuộc vào ngăn xếp lệnh gọi hàm Để thống nhất quản lý lưu trữ và lập kế hoạch.
vòng đời Tạo (đẩy) => thực hiện => Phá hủy (pop) , được tạo khi hàm được gọi và bị hủy sau khi thực thi xong.

hình ảnh


02. Ngăn xếp lệnh gọi hàm dùng để làm gì?

Ngăn xếp lệnh gọi hàm là hàng đợi cấu trúc ngăn xếp (cuối cùng vào, ra trước) quản lý các lệnh gọi hàm hoặc ngăn xếp thực thi, lưu trữ tất cả bối cảnh thực thi của chương trình hiện tại (các hàm đang được thực thi). Tất nhiên, thứ đầu tiên được đẩy lên ngăn xếp là bối cảnh chung được tạo khi chương trình được khởi tạo. Nó là thành viên VIP và sẽ ở cuối ngăn xếp cho đến khi chương trình thoát ra.

2.1. Quá trình thực hiện chức năng

Quá trình gọi ngữ cảnh thực thi hàm (cũng là vòng đời của hàm):

  • Tạo-Đẩy : Tạo bối cảnh thực thi và đẩy nó lên ngăn xếp để giành quyền kiểm soát.
  • Thực hiện - làm việc : Thực thi code của hàm, gán giá trị cho biến và tìm biến. Nếu có lệnh gọi hàm nội bộ, luồng hàm sẽ được lặp lại theo cách đệ quy.
  • phá hủy pop : Khi quá trình thực thi hàm hoàn tất và thoát ra khỏi ngăn xếp, bối cảnh thực thi được giải phóng và các biến của nó cũng được giải phóng, tất cả bị hủy và điều khiển quay trở lại bối cảnh thực thi trước đó.

hình ảnh

                        
                          hàm first() { second(); //Sử dụng second() } hàm second() { } first();

                        
                      

Quá trình thực thi đoạn mã trên được thể hiện trong hình bên dưới:

  1. Khi chương trình khởi tạo và chạy, điều đầu tiên được tạo ra là bối cảnh chung. Toàn cầu , nhập ngăn xếp thực thi.
  2. gọi Đầu tiên() chức năng, bối cảnh của nó được tạo và đẩy lên ngăn xếp.
  3. Đầu tiên() Hàm này được gọi nội bộ thứ hai() chức năng, tạo thứ hai() Lệnh sau được đẩy vào ngăn xếp và được thực thi.
  4. thứ hai() Việc thực thi hàm hoàn tất và thoát ra khỏi ngăn xếp, điều khiển quay về Đầu tiên() bối cảnh chức năng.
  5. Đầu tiên() Việc thực thi hàm được hoàn thành và thoát khỏi ngăn xếp, đồng thời điều khiển quay trở lại bối cảnh chung.

c71b3089775edcdcd2043eba90a70572_u=544850019,275206126&fm=253&app=138&f=PNG&fmt=tự động&q=75_w=1280&h=228.webp

Một ví dụ khác về ngăn xếp lệnh gọi hàm:

                        
                          var a = 1; cho b = 1; hàm FA(x) { hàm FB(y) { hàm FC(z) { console.log(a + b + x + y + z); } FC(3); } FB(2); } FA(1); //8

                        
                      

Ngăn xếp lệnh gọi hàm của hàm trên khi thực thi FC() như dưới đây (Gỡ lỗi điểm dừng của trình duyệt Edge):

hình ảnh.png

✅ Khi thực thi mã hàm FC, phạm vi của nó giữ lại tất cả các biến phạm vi sẽ được sử dụng, từ chính nó trở lên đối tượng toàn cục. Đây là cách các bao đóng xuất phát! .

  • var a = 1; :Các biến được khai báo bằng var sẽ được sử dụng làm đối tượng toàn cục cửa sổ biến.
  • cho b = 1; : Các biến được khai báo trong môi trường toàn cục có thể được truy cập bởi bất kỳ hàm nào. Nếu được đặt trong môi trường tập lệnh toàn cục, chúng có thể được coi là một phần của môi trường toàn cầu.

✅ Trong call stack có FC, FB, FA vì là hàm lồng nhau nên FB và FA chưa kết thúc nên vẫn còn trong stack.

hình ảnh.png

2.2. Tràn ngăn xếp

Dung lượng ngăn xếp lệnh gọi hàm bị hạn chế! --Hàm đệ quy.

Hàm đệ quy là một quá trình gọi nhiều lớp + tự lồng. Do đó, khi một hàm đệ quy được thực thi, nó sẽ được đẩy lên ngăn xếp mà không bật ra ngoài. Quá nhiều vòng lặp sẽ vượt quá giới hạn dung lượng của ngăn xếp, gây ra lỗi. Ví dụ: trong ví dụ sau, một phép đệ quy bổ sung đơn giản sẽ dẫn đến lỗi (InternalError: too much recursion) nếu nó được đệ quy 1500 lần trong trình duyệt Firefox, dung lượng ngăn xếp cuộc gọi sẽ vượt quá 11000 lần ( Đã vượt quá kích thước ngăn xếp cuộc gọi tối đa).

❓Giải quyết thế nào?

  • tránh đệ quy : Đóng gói logic xử lý và chuyển nó thành một vòng lặp để xử lý. Hoặc sử dụng thiết lập thời gian chờ(hàm,0) Gửi đến hàng đợi nhiệm vụ để thực hiện riêng biệt.
  • thực hiện phân chia : Chia mã hợp lý thành nhiều hàm đệ quy.
                        
                          function add(x) { if (x <= 0) return 0; return x + add(x - 1); //Tính tổng đệ quy} add(1000); //Firefox: 1000 vẫn ổn, 1500 sẽ báo lỗi InternalError : quá nhiều đệ quy add(10000);//Edge: 10000 có thể được thực thi, nhưng 11000 sẽ báo lỗi Đã vượt quá kích thước ngăn xếp cuộc gọi tối đa

                        
                      

» Ngăn xếp cuộc gọi Firefox:

hình ảnh.png


03. Phạm vi từ vựng là gì?

Phạm vi là một tập hợp các quy tắc quy định phạm vi (quyền hạn) của các biến và sử dụng quy tắc này để tìm các biến. Bao gồm phạm vi tĩnh và phạm vi động, JavaScript chủ yếu là phạm vi tĩnh (phạm vi từ vựng).

  • phạm vi tĩnh (đó là phạm vi từ vựng ): JavaScript tạo phạm vi dựa trên phạm vi từ vựng và xác định phạm vi và mối quan hệ phạm vi (chuỗi phạm vi) của các biến dựa trên phân tích từ vựng của mã. Môi trường từ vựng là thứ tự chúng ta viết mã nên nó là tĩnh, nghĩa là phạm vi của các hàm và biến được xác định khi chúng được khai báo và sẽ không thay đổi trong giai đoạn chạy.
  • phạm vi động : Được xác định dựa trên mối quan hệ gọi động và chuỗi phạm vi của nó dựa trên ngăn xếp lệnh gọi trong thời gian chạy. Ví dụ cái này , nói chung bối cảnh được xác định dựa trên cuộc gọi. Vì vậy cái này Giá trị có thể được tìm thấy trên ngăn xếp cuộc gọi. cái này chỉ vào một Đối tượng tham chiếu , không phải bản thân hàm cũng như phạm vi từ vựng của nó.

hình ảnh

Do đó, chức năng chính của phạm vi từ vựng là chỉ định quyền truy cập của các biến và xác định cách tìm biến. Các quy tắc cơ bản là:

  • Quyết định vị trí mã : Vị trí khai báo một biến (bao gồm cả hàm) sẽ xác định phạm vi, bất kể nó được gọi ở đâu.
  • Có quyền của phụ huynh : Một hàm (hoặc khối) có thể truy cập dữ liệu bên ngoài nó. Nếu được lồng nhiều cấp, nó có quyền phạm vi của cấp độ gốc theo cách đệ quy, tùy thuộc vào môi trường toàn cầu.
  • phạm vi chức năng : Chỉ các chức năng mới có thể giới hạn phạm vi và các chức năng cấp trên hoặc bên ngoài không thể truy cập được.
  • Sử dụng cùng tên ở gần đây : Nếu có biến có cùng tên với biến cấp trên thì biến gần nhất sẽ được sử dụng.
  • Tìm kiếm lên trên theo từng lớp : Quy tắc tìm kiếm các biến là bắt đầu từ bên trong, sau đó đi lên từng bước cho đến khi không tìm thấy môi trường chung. không xác định

Phạm vi từ vựng ở đây là phạm vi biến JS được đề cập ở trên. Việc đóng giữ lại các biến của phạm vi ngữ cảnh để đạt được phạm vi từ vựng.

❓Phạm vi từ vựng được triển khai như thế nào? --Chuỗi phạm vi, đóng cửa.

Hàm cha FA() được lấy ra khỏi ngăn xếp và bị hủy sau khi thực thi (trường hợp điển hình là hàm trả về FB() có thể được thực thi ở bất kỳ đâu. Vậy hàm bên trong FB() tìm biến x của hàm cha ở đâu. khi nào nó được thực thi?

  • ✅ Phạm vi chức năng nội bộ: Đầu tiên Mỗi chức năng thực hiện Sẽ tạo phạm vi riêng (bối cảnh thực thi) và khi tìm kiếm biến, tìm kiếm phạm vi cục bộ sẽ được ưu tiên.
  • ✅ Đóng cửa : Phạm vi chức năng bên ngoài (từ vựng vượt trội) của tham chiếu tạo thành một bao đóng, sử dụng một Đóng cửa _(Đóng /ˈkləʊʒə(r)/ đóng)_Lưu đối tượng, nhiều (tham chiếu bên ngoài) được lưu vào ngữ cảnh hàm theo từng bước [[Phạm vi]] (Phạm vi /skoʊp/ phạm vi) được thiết lập, hình thành chuỗi phạm vi
  • ✅ Chuỗi phạm vi Mức thấp nhất là tham chiếu đến đối tượng toàn cục, đối tượng này luôn ở đó, cho dù bạn có muốn hay không.
  • ✅Tìm kiếm biến đổi Chỉ cần thực hiện trên chuỗi phạm vi này: bối cảnh riêng ( Môi trường từ vựng, môi trường biến đổi) => Tìm kiếm chuỗi phạm vi từng bước => phạm vi toàn cầu => không xác định

hình ảnh

                        
                          hàm FA(x) { hàm FB(y) { x+=y; console.log(x); } console.dir(FB); //Trở về hàm FB()} let fb = FA(1) ; // Quá trình thực thi hàm FA hoàn tất, fb(2) được đưa ra khỏi ngăn xếp và bị hủy; //3 // Hàm fb() được trả về giữ lại biến phạm vi FA() gốc của nó x fb(2); //x trong bao đóng: Tôi lại lớn hơn fb(2); //7 // Hàm đóng tương tự được gọi lặp đi lặp lại và các biến nội bộ được thay đổi

                        
                      

hình ảnh.png

Hiểu đơn giản về việc đóng là tham chiếu trỏ đến phạm vi cha được lưu trữ trong môi trường hiện tại. Nếu hàm con lồng nhau không tham chiếu bất kỳ biến nào trong hàm cha thì sẽ không có bao đóng nào được tạo ra. Tuy nhiên, các đối tượng chung luôn tồn tại trên chuỗi phạm vi [[Phạm vi]] của chúng.

Ví dụ:

                        
                          var a = 1; cho b = 2; hàm FunA(x) { cho x1 = 1; var x2 = 2; hàm FunB(y) { console.log(a + b + x + x1 + x2 + y); } FunB(2); console.dir(FunB) } FunA(1); //9 console.dir(FunA)

                        
                      

Trong ví dụ về mã ở trên, hàm FunA() lồng hàm FunB() Như được hiển thị bên dưới, có ba đối tượng trong bộ sưu tập [[Scope]] của hàm FunB():

hình ảnh.png

  • Kết thúc (FunA) vuiA() Việc đóng một hàm, chứa các tham số của nó x , biến riêng x1 x2
  • Kịch bản :Phạm vi tập lệnh Phạm vi tập lệnh (có thể được coi là một phần của phạm vi toàn cầu), lưu trữ các tập lệnh có thể truy cập được trong môi trường tập lệnh tập lệnh toàn cầu. cho phép hằng số Biến là các biến trong phạm vi toàn cục. của chúng tôi biến Một Được thăng cấp lên đối tượng toàn cầu cửa sổ "thuộc tính".
  • Toàn cầu : Đối tượng phạm vi toàn cầu, là cửa sổ, chứa của chúng tôi Các biến được khai báo và các biến không được khai báo.

Nếu hàm FunB() được khai báo bên ngoài và chỉ được gọi trong FunA() thì chuỗi phạm vi sẽ khác.


04. Bối cảnh thực thi được tạo ra như thế nào?

Trong quá trình tạo ngữ cảnh thực thi, phạm vi từ vựng tương ứng sẽ được tạo, bao gồm môi trường từ vựng và môi trường biến.

  • Tạo môi trường từ vựng (Môi trường từ vựng):
    • hồ sơ môi trường Môi trườngRecord : Ghi lại các thông tin như khai báo biến, hàm và chỉ lưu trữ các khai báo hàm và cho/const các biến được khai báo.
    • tham chiếu bên ngoài bên ngoài : Tham chiếu đến môi trường từ vựng có phạm vi (cao hơn), ít nhất bao gồm cả bối cảnh chung.
  • Tạo môi trường biến (VariableEnvironment): Về cơ bản nó là một môi trường từ vựng, nhưng nó chỉ lưu trữ của chúng tôi Các biến được khai báo tương tự như môi trường từ vựng.
                        
                          ExecutionContext = { ThisBinding = , LexicalEnvironment = { ... }, VariableEnvironment = { ... }, }

                        
                      

❗Tìm kiếm biến: Khi tìm kiếm biến, trước tiên chúng ta tìm kiếm từ môi trường từ vựng, sau đó mới đến môi trường biến. Nghĩa là, các biến const và let được tìm kiếm đầu tiên, tiếp theo là các biến var.

hình ảnh

Tóm lại từ nhiều góc độ, việc tạo bối cảnh thực thi chủ yếu giải quyết ba khía cạnh sau:

① Xác định giá trị của this (This Binding):

  • trong bối cảnh toàn cầu cái này định hướng cửa sổ
  • bối cảnh thực thi hàm , nếu nó được gọi với một tham chiếu đối tượng, thì cái này Giá trị của được đặt cho đối tượng này, nếu không cái này Giá trị được đặt thành một đối tượng chung hoặc không xác định (ở chế độ nghiêm ngặt)
  • gọi (thisArg)、 áp dụng (thisArg)、 ràng buộc (thisArg) sẽ được chỉ định trực tiếp Giá trị này giá trị.

② Môi trường bên trong: Bao gồm môi trường từ vựng và môi trường biến đổi, là các biến, hàm và các thông tin khác bên trong hàm, cũng như thông tin đối số tham số.

③ Chuỗi phạm vi (tham chiếu bên ngoài): Phạm vi từ vựng bên ngoài được lưu trữ trong bộ sưu tập [[Phạm vi]] của hàm để tìm biến phạm vi cấp cao hơn.


05. ❓Kết luận là gì?

  • ❓ Các biến càng gần nhau thì càng tốt: Tốt nhất là bản địa hóa chúng và cố gắng tránh làm cho liên kết tìm kiếm biến quá dài. Việc chuyển đổi phạm vi theo từng lớp để tìm chúng cũng rất mệt mỏi.
  • ❓ Ưu tiên hằng số , thứ hai cho phép , cố gắng không sử dụng nó (kiên quyết) của chúng tôi
  • ❓ Lưu ý về độ dài của ngăn xếp lệnh gọi hàm, chẳng hạn như đệ quy.
  • ❓ Sau khi sử dụng chức năng đóng, hãy mở nó ra bằng tay. vui vẻ = null; , hãy thu gom rác càng sớm càng tốt.
  • ❓Cố gắng tránh trở thành biến môi trường toàn cục, đặc biệt là một số biến toàn cục luôn ở đó và sẽ không được thu gom rác.
    • Bao gồm tuyên bố môi trường toàn cầu cho phép hằng số của chúng tôi
    • Hãy nhớ không sử dụng các biến không được khai báo chuỗi='' , sẽ trở thành một biến toàn cục bất kể nó ở đâu.

Tránh xa JavaScript, tránh xa front-end... Tôi tưởng mình đã học được nó, nhưng thực tế có thể tôi vẫn chưa bắt đầu.

hình ảnh.png


10. Quản lý bộ nhớ GC

Vòng đời của các biến loại giá trị phụ thuộc vào hàm và được giải phóng sau khi hàm được thực thi. Quản lý bộ nhớ Garbage Collection (Garbage Collection) chủ yếu nhắm vào các đối tượng tham chiếu. Khi phát hiện đối tượng đó sẽ không còn được sử dụng nữa, bộ nhớ của nó sẽ được giải phóng. GC chạy tự động và không cần can thiệp hoặc có thể thực hiện.

Chìa khóa để GC tái chế một vật thể là đảm bảo rằng nó thực sự là đồ thải và nó không được sử dụng ở bất cứ đâu. Phương pháp chính được sử dụng là làm sạch dấu vết.

  • làm sạch thẻ (mark-and-sweep): đánh dấu tất cả các Đối tượng có thể tiếp cận gốc và tất cả các đối tượng được tham chiếu của nó), phần còn lại là thứ không ai muốn và có thể bị xóa.
  • Đếm tham chiếu : Theo số lần biến được tham chiếu, chiến lược này không còn được sử dụng vì chiến lược thu gom rác quá rác và đã bị bỏ rơi.

❓Khả năng tiếp cận là gì?

  • rễ : Các biến trực tiếp nhất của môi trường thực thi hiện tại (cửa sổ), bao gồm các biến cục bộ và tham số của hàm hiện đang được thực thi;
  • khả năng tiếp cận (Khả năng tiếp cận): Nếu một giá trị (đối tượng) có thể được truy cập trong một chuỗi từ gốc thì nó có thể truy cập được, điều đó có nghĩa là đối tượng dữ liệu vẫn có giá trị.

hình ảnh

Trong hình trên, biến cục bộ obj1 trong hàm FuncA có đối tượng giá trị {P} được lưu trữ trong vùng nhớ. Tại thời điểm này, đối tượng giá trị {P} được tham chiếu bởi biến gốc obj1 và có thể truy cập được.

  • Nếu hàm hoàn thành việc thực thi, hàm sẽ bị hủy và tham chiếu biến obj1 Cũng đi cùng cô ấy. đối tượng giá trị {P} Nếu nó không được tham chiếu, nó sẽ không thể truy cập được.
  • Nếu việc thực thi được hiển thị trong hàm obj1=null; đối tượng có cùng giá trị {P} Nếu nó không được tham chiếu, nó không thể truy cập được.

hình ảnh.png

GC định kỳ thực hiện hai bước thu gom rác:

① Giai đoạn đánh dấu: Tìm các đối tượng có thể tiếp cận và đánh dấu chúng. Thuật toán thực tế sẽ tinh tế hơn.

  • Trình thu gom rác tìm thấy tất cả các gốc và "đánh dấu" (ghi nhớ) chúng.
  • Tiếp tục di chuyển ngang và "đánh dấu" các đối tượng được tham chiếu bởi gốc.
  • ...tiếp tục duyệt cho đến khi tất cả các đối tượng có thể tiếp cận được tìm thấy và đánh dấu.

② Giai đoạn dọn dẹp: Những đồ vật không được đánh dấu sẽ bị dọn sạch và xóa.

⚠️ Biến toàn cục sẽ không bị xóa: Các biến toàn cục thuộc về cửa sổ là gốc và sẽ không bao giờ bị xóa nếu có nền! .


©️ Tuyên bố về bản quyền: Mọi quyền được bảo lưu @安木西. Nội dung bài viết này chỉ mang tính chất học hỏi. Vui lòng ghi rõ nguồn khi tái bản! Địa chỉ chỉnh sửa gốc - Yuque.

Cuối cùng, bài viết này về Giới thiệu về JavaScript ③-Function (2) Nguyên tắc {Chuyên sâu} Bối cảnh thực thi sẽ kết thúc ở đây. vui lòng Tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .

28 4 0
tôi là một con chim nhỏ
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress