Văn hay trong hiện tại, chữ tốt ở tương lai

Bạn chưa biết rõ về JavaScript đâu (You don't know JS yet) | Chương 2.4

Khám phá bản chất JavaScript từ lịch sử tên gọi, chuẩn ECMAScript và tính đa mô thức. Xóa bỏ lầm tưởng, xây nền tảng vững chắc cho nhà phát triển website.

49 phút đọc.

0 lượt xem.

Mở đầu

Đến thời điểm hiện tại của lộ trình học tập, bạn chắc hẳn đã thiết lập được một nền tảng nhận thức tương đối vững chắc về cơ chế lồng ghép của các không gian phạm vi, trải dài từ không gian phạm vi toàn cục trên cùng trút xuống tận những tầng sâu nhất bên dưới – một hệ thống mạng lưới kiến trúc mà giới khoa học máy tính chính thức gọi tên là chuỗi phạm vi của một chương trình điện toán. Tuy nhiên, việc chỉ đơn thuần nắm bắt được nguồn gốc xuất xứ của một biến số từ một không gian phạm vi cụ thể nào đó mới chỉ phác họa được một nửa của bức tranh sự thật toàn cảnh. Một loạt các câu hỏi mang tính chất nền tảng và hóc búa bắt đầu được đặt ra: nếu như một câu lệnh khai báo biến số vật lý xuất hiện ở một vị trí tít sâu bên dưới, vượt qua khỏi câu lệnh đầu tiên của một không gian phạm vi, thì bất kỳ một nỗ lực tham chiếu nào nhắm vào cái định danh đó trước khi hệ thống kịp chạy đến dòng khai báo sẽ phản ứng và hành xử ra sao trong thực tế? Hay những hệ lụy hệ thống nào sẽ bị kích nổ nếu như bạn cố tình thách thức các quy tắc bằng cách cố gắng khai báo đi khai báo lại cùng một biến số đến tận hai lần hoặc nhiều hơn bên trong cùng một giới hạn không gian phạm vi chật hẹp? Đặc trưng kiến trúc của mô hình phạm vi từ vựng bên trong hệ sinh thái ngôn ngữ JavaScript thực sự vô cùng phong phú và ẩn chứa đầy rẫy những sắc thái vi tế, đặc biệt là khi chúng ta tiến hành giải phẫu cách thức và thời điểm chính xác mà các biến số được hệ thống khai sinh, thành hình và chính thức được cấp phép để toàn bộ chương trình có thể tự do truy xuất và sử dụng.

Cơ chế khởi tạo và khả năng truy cập biến số

Việc thấu hiểu thời điểm một biến số thực sự tồn tại trong bộ nhớ không chỉ đơn giản là việc đọc mã từ trên xuống dưới. Ngôn ngữ này sở hữu những quy tắc ngầm định độc đáo chi phối vòng đời của các định danh ngay từ giai đoạn biên dịch.

Hiện tượng kéo lên và sự ưu tiên của khai báo hàm

Tại thời khắc chính xác nào trên dòng thời gian thực thi thì một biến số mới thực sự trở nên sẵn sàng để được mang ra sử dụng bên trong chính cái không gian phạm vi ôm lấy nó? Đa số các kỹ sư lập trình, dựa trên trực giác và kinh nghiệm từ các ngôn ngữ khác, có thể sẽ ngay lập tức đưa ra một câu trả lời tưởng chừng như vô cùng hiển nhiên và hợp logic: đó chắc chắn phải là thời điểm sau khi cái biến số đó đã được hệ thống xử lý qua câu lệnh khai báo hoặc khởi tạo thành công. Thế nhưng, trong hệ sinh thái của ngôn ngữ JavaScript, chân lý đó lại không hoàn toàn chính xác tuyệt đối. Hãy thử đưa vào tầm ngắm một đoạn mã mẫu vô cùng phổ biến, nơi mà một lời gọi hàm được thực thi để in ra một lời chào, nhưng bản thân cái phần định nghĩa chi tiết của cái hàm đó lại nằm chễm chệ ở tận những dòng lệnh cuối cùng phía dưới. Đoạn mã này vẫn vận hành một cách trơn tru, hoàn hảo mà không hề vấp phải bất kỳ một sự cố sụp đổ nào. Bạn có thể đã từng tận mắt chứng kiến, hoặc thậm chí là đã tự tay mình gõ ra những đoạn mã có cấu trúc đảo ngược tương tự như vậy trong quá khứ. Thế nhưng, đã bao giờ bạn thực sự dừng lại để nghiêm túc tự chất vấn bản thân về việc làm thế quái nào, hay bởi một thế lực ma thuật nào, mà toàn bộ cơ chế này lại có thể hoạt động trơn tru đến vậy chưa? Nói một cách cụ thể và đi sâu vào bản chất kỹ thuật hơn, tại sao hệ thống lại cho phép bạn có thể ngang nhiên truy cập vào cái định danh tên hàm ngay từ dòng lệnh đầu tiên (để thọc tay vào lấy sợi dây tham chiếu hàm và tiến hành thực thi nó), bất chấp một sự thật rành rành về mặt không gian vật lý là cái câu lệnh khai báo hàm đó hoàn toàn không hề tồn tại cho đến tận dòng thứ tư của chương trình?

Để có thể giải mã được hiện tượng tưởng chừng như phi logic này, chúng ta bắt buộc phải khơi gợi lại những kiến thức nền tảng đã được thiết lập vững chắc từ Chương 1, nơi đã chỉ ra một chân lý kiến trúc rằng toàn bộ mọi định danh biến số đều đã được hệ thống đăng ký hộ khẩu thường trú vào đúng các không gian phạm vi tương ứng của chúng ngay trong suốt quá trình biên dịch tĩnh. Vượt xa hơn thế, một nguyên lý mang tính chất rường cột là mỗi một định danh đều được hệ thống chính thức khai sinh và khởi tạo ngay tại cái vạch xuất phát đầu tiên của cái không gian phạm vi mà nó trực thuộc, và hành động khai sinh này diễn ra lặp đi lặp lại mỗi khi hệ thống bước chân vào cái không gian phạm vi đó. Cái thuật ngữ hàn lâm được giới chuyên môn sử dụng phổ biến nhất để miêu tả cho việc một biến số sở hữu khả năng hiển thị và có thể truy cập được ngay từ điểm khởi đầu của không gian phạm vi bao bọc nó, mặc cho sự thật là câu lệnh khai báo vật lý của nó có thể bị vùi lấp ở tận dưới đáy của đoạn mã, được gọi là hiện tượng kéo lên.. Tuy nhiên, việc chỉ đơn thuần vứt ra cái thuật ngữ kéo lên. vẫn hoàn toàn không đủ sức nặng để trả lời trọn vẹn cho câu hỏi hóc búa được đặt ra ban đầu. Chúng ta có thể dễ dàng hiểu được lý do tại sao cỗ máy thông dịch lại có thể nhìn thấy sự tồn tại của cái định danh tên hàm ngay từ lúc bắt đầu chạy không gian phạm vi, thế nhưng tại sao chúng ta lại được hệ thống cấp cho cái đặc quyền to lớn là có thể gọi thực thi cái hàm đó từ rất lâu trước khi nó được khai báo chính thức?

Nói một cách khác, bằng một cơ chế kỳ diệu nào mà cái biến số định danh tên hàm đó lại sở hữu sẵn một giá trị dữ liệu (chính là sợi dây tham chiếu trỏ thẳng đến cấu trúc hàm) được gán chặt vào nó, ngay từ cái khoảnh khắc tích tắc đầu tiên khi không gian phạm vi vừa mới bấm nút khởi động? Lời giải đáp cho bài toán này nằm ở một đặc tính kiến trúc vô cùng đặc biệt và độc quyền dành riêng cho các câu lệnh khai báo hàm chính thống, đặc tính này được giới học thuật định danh là hiện tượng kéo lên của hàm.. Khi cái tên định danh của một câu lệnh khai báo hàm được hệ thống đăng ký hộ khẩu ở ngay trên đỉnh của không gian phạm vi mà nó cư trú, nó còn được hệ thống ban phát thêm một ân huệ đặc biệt là tự động khởi tạo luôn giá trị và trỏ thẳng vào cái tham chiếu của hàm vật lý đó. Đó chính là phép màu giải thích vì sao toàn bộ cấu trúc của cái hàm đó lại có thể bị triệu hồi và thực thi ở bất kỳ ngóc ngách nào xuyên suốt toàn bộ không gian phạm vi! Một chi tiết kiến trúc mang tính chất sống còn cần phải được khắc cốt ghi tâm là cả hiện tượng kéo lên của hàm. lẫn biến thể kéo lên của biến số. sử dụng từ khóa kiểu cũ đều chỉ móc nối và gắn chặt các tên định danh của chúng vào cái không gian phạm vi hàm đang bao bọc lấy chúng ở vị trí gần nhất (hoặc, trong trường hợp không có bất kỳ một cái hàm nào bao bọc, chúng sẽ bay thẳng ra và bám vào không gian phạm vi toàn cục), chứ tuyệt đối chúng không bao giờ chịu hạ mình để bám vào các không gian phạm vi cấp khối. Các câu lệnh khai báo sử dụng những từ khóa hiện đại mặc dù vẫn chịu sự chi phối của hiện tượng kéo lên, nhưng chúng lại ưu tiên bám rễ vào các khối mã bao bọc chúng thay vì chỉ trung thành với các không gian phạm vi hàm.

Sự khác biệt giữa khai báo hàm và biểu thức hàm

Một nguyên lý tối quan trọng cần phải được phân định rạch ròi là hiện tượng kéo lên của hàm. chỉ phát huy tác dụng và áp dụng độc quyền đối với các câu lệnh khai báo hàm mang tính chất chính thống (cụ thể hơn là những khai báo hàm xuất hiện chễm chệ ở bên ngoài các khối mã lệnh), và nó tuyệt đối tước bỏ mọi quyền lợi đối với các thao tác gán biểu thức hàm vào một biến số. Hãy cùng nhau mổ xẻ một ví dụ điển hình để thấy rõ sự khác biệt một trời một vực này: khi bạn cố gắng gọi một lời chào thông qua một biến số trước khi gán một biểu thức hàm ẩn danh cho nó, dòng lệnh gọi hàm ở ngay vị trí đầu tiên chắc chắn sẽ kích nổ một lỗi hệ thống làm sập chương trình. Thế nhưng, điểm mấu chốt mang tính chất quyết định mà bạn cần phải cực kỳ tinh ý quan sát ở đây chính là chủng loại của cái lỗi vừa bị ném ra. Hệ thống báo cáo một Lỗi kiểu dữ liệu., một tín hiệu cảnh báo cực kỳ rõ ràng mang hàm ý rằng chúng ta đang cố tình thực hiện một hành động cấm kỵ đối với một giá trị dữ liệu không hề hỗ trợ cho cái thao tác đó. Tùy thuộc vào việc bạn đang chạy đoạn mã trên môi trường JavaScript nào, thông điệp lỗi in ra màn hình có thể sẽ mang một hình hài chung chung kiểu như: Giá trị chưa xác định không phải là một hàm., hoặc ở một số môi trường thân thiện hơn, nó sẽ chỉ đích danh: Định danh lời chào không phải là một hàm..

Hãy dồn toàn bộ sự chú ý của bạn vào một sự thật kiến trúc rằng cái lỗi hệ thống này tuyệt đối không phải là một Lỗi tham chiếu.. Cỗ máy thông dịch JavaScript hoàn toàn không hề than phiền với chúng ta về việc nó bị mù và không thể tìm thấy cái định danh tên là lời chào ở đâu bên trong cái không gian phạm vi này. Trái ngược hoàn toàn, thông điệp mà nó muốn truyền tải là cái định danh tên lời chào đó thực sự đã được hệ thống tìm thấy và công nhận sự tồn tại, nhưng bi kịch thay, tại ngay cái khoảnh khắc tích tắc mà lời gọi hàm diễn ra, cái biến số đó lại không hề chứa đựng bất kỳ một sợi dây tham chiếu hàm nào bên trong bụng của nó. Theo bộ quy tắc thi hành của ngôn ngữ, chỉ có duy nhất các thực thể hàm mới sở hữu đặc quyền được triệu hồi và thực thi, vì vậy mọi nỗ lực mù quáng nhằm triệu hồi một giá trị dữ liệu phi hàm đều sẽ nhận lãnh hậu quả tất yếu là một sự cố lỗi sụp đổ hệ thống. Vậy thì một câu hỏi mang tính chất logic được đặt ra: nếu như không chứa đựng sợi dây tham chiếu hàm, thì rốt cuộc cái biến số lời chào đó đang âm thầm ôm giữ cái giá trị quái quỷ gì bên trong nó tại thời điểm bị gọi?

Câu trả lời nằm ở bản chất cốt lõi của các biến số được khai sinh bởi từ khóa kiểu cũ; bên cạnh việc được hệ thống nhấc bổng và kéo lên đỉnh của không gian phạm vi, chúng còn tự động được hệ thống ưu ái khởi tạo giá trị mặc định là trống rỗng. ngay tại cái vạch xuất phát của không gian phạm vi mà chúng cư ngụ – xin nhắc lại một lần nữa, đó chính là không gian hàm bao bọc gần nhất, hoặc là không gian toàn cục. Một khi quá trình khởi tạo giá trị mặc định này hoàn tất, chúng hoàn toàn sẵn sàng phơi mình ra để được toàn bộ phần còn lại của không gian phạm vi mang ra sử dụng (có thể là để gán một giá trị mới vào, hoặc trích xuất giá trị hiện tại ra, v.v.). Chính vì cơ chế này, ở ngay tại cái dòng lệnh đầu tiên đầy rủi ro kia, biến số lời chào thực sự đã hiện hữu vật lý trong bộ nhớ, nhưng thân xác của nó chỉ là một lớp vỏ rỗng tuếch chứa đựng một giá trị trống rỗng. mặc định. Bánh xe thời gian thực thi phải miệt mài lăn đến tận dòng lệnh thứ tư thì cái biến số lời chào đó mới chính thức được hệ thống nhồi nhét cho cái sợi dây tham chiếu hàm. Bạn bắt buộc phải dành một sự tập trung cao độ để nhận diện và khắc sâu sự phân định rạch ròi ở điểm này. Một câu lệnh khai báo hàm không chỉ được hệ thống kéo lên mà còn được khởi tạo ngay lập tức bằng chính cái giá trị thực thể hàm của nó (hiện tượng này, như đã nhấn mạnh, được gọi là hiện tượng kéo lên của hàm.). Một biến số kiểu cũ cũng được vinh dự kéo lên, nhưng sau đó nó chỉ được hệ thống tự động khởi tạo bằng một giá trị trống rỗng. nhạt nhẽo. Bất kỳ một thao tác gán biểu thức hàm nào diễn ra sau đó vào cái biến số này đều bị đóng băng và hoàn toàn không thể xảy ra cho đến tận khi luồng thực thi chạy thời gian thực đâm sầm vào đúng cái câu lệnh gán vật lý đó. Trong cả hai kịch bản, cái tên định danh đều vươn lên đỉnh cao của không gian, nhưng sự móc nối với tham chiếu hàm sẽ vĩnh viễn không được xử lý tại thời điểm khởi tạo (bắt đầu không gian phạm vi) trừ phi cái định danh đó được sinh ra từ một câu lệnh khai báo hàm chính thống.

Bản chất của việc kéo lên biến số thông thường

Để có thể thấu thị một cách toàn diện hơn, chúng ta hãy cùng nhau chuyển hướng lăng kính sang một ví dụ minh họa khác về hiện tượng kéo lên của biến số.. Hãy tưởng tượng một kịch bản nơi bạn thực hiện một lệnh gán một chuỗi ký tự chào hỏi vào một biến số ngay ở dòng đầu tiên, tiếp theo là in giá trị đó ra màn hình điều khiển, và ngạc nhiên thay, mãi đến tận dòng lệnh thứ năm thì bạn mới thong thả tung ra câu lệnh khai báo biến số đó bằng từ khóa kiểu cũ. Mặc dù xét về mặt trình tự không gian vật lý, cái biến số chào hỏi đó hoàn toàn không hề có tư cách tồn tại cho đến tận khi trình biên dịch đọc đến dòng thứ năm, thế nhưng nó lại phơi bày sự sẵn sàng để tiếp nhận một phép gán giá trị một cách hợp lệ ngay từ thuở sơ khai ở dòng thứ nhất. Bí ẩn đằng sau sự nghịch lý về mặt thời gian này là gì?

Để giải phẫu được hiện tượng này một cách triệt để, chúng ta bắt buộc phải dựa vào hai trụ cột lý thuyết không thể tách rời: thứ nhất là sự thật rằng cái tên định danh đã được hệ thống dùng ma thuật để kéo lên trên cùng; và thứ hai là nó đã được cỗ máy tự động nhồi nhét một giá trị trống rỗng. ngay từ cái đỉnh cao nhất của không gian phạm vi đó. Việc lạm dụng hiện tượng kéo lên của biến số. theo kiểu tréo ngoe như vậy chắc chắn sẽ gây ra một cảm giác gợn cợn, cực kỳ thiếu tự nhiên và phản trực giác đối với những bộ óc đã quen với tư duy tuần tự logic. Và hoàn toàn có thể hiểu được khi đại đa số các kỹ sư tham khảo tài liệu này đều ôm ấp một khao khát cháy bỏng, hoàn toàn chính đáng là muốn né tránh đến mức tối đa việc phải phụ thuộc vào một thủ thuật kiến trúc dễ gây hoang mang như vậy bên trong các dự án phần mềm của họ. Thế nhưng, liệu chúng ta có nên cực đoan đến mức phải tìm mọi cách diệt trừ và né tránh toàn bộ mọi hình thái của hiện tượng kéo lên (bao gồm cả hiện tượng kéo lên của hàm. vô cùng hữu dụng) hay không? Những góc nhìn đa chiều và các luồng tư tưởng tranh luận sâu sắc xoay quanh giá trị thực tiễn của hiện tượng kéo lên này sẽ được chúng ta mổ xẻ và đào sâu chi tiết hơn ở các phần phụ lục, nhằm mang lại một cái nhìn khách quan và toàn diện nhất cho người kiến trúc sư.

Phân tích phép ẩn dụ kéo lên và hành vi tái khai báo

Để hiểu rõ cách thức mã nguồn được chuẩn bị trước khi thực thi, cộng đồng lập trình đã tạo ra nhiều phép ẩn dụ. Tuy nhiên, việc bám chấp vào những ẩn dụ này đôi khi lại dẫn đến những nhận thức sai lầm nghiêm trọng về hành vi tái khai báo.

Giới hạn của phép ẩn dụ kéo lên

Chương hai của bộ tài liệu này đã được lấp đầy bởi một bộ sưu tập phong phú các hình ảnh phép ẩn dụ sinh động (nhằm mục đích minh họa và cụ thể hóa cấu trúc trừu tượng của không gian phạm vi), thế nhưng tại phân đoạn này, chúng ta lại phải tiếp tục đối mặt và vật lộn với một phép ẩn dụ khổng lồ khác: bản thân khái niệm kéo lên. Thay vì nhìn nhận hiện tượng kéo lên như một bước thực thi cơ học vật lý, khô khan mà cỗ máy JavaScript phải oằn mình gánh vác, sẽ là một cách tiếp cận mang lại hiệu quả tư duy vượt trội hơn rất nhiều nếu chúng ta coi hiện tượng kéo lên như một công cụ hình tượng hóa (visualization) nhằm mô tả lại hàng loạt các hành động dàn xếp và chuẩn bị nền móng kiến trúc phức tạp mà cỗ máy JavaScript âm thầm tiến hành để thiết lập cấu trúc cho chương trình từ rất lâu trước khi bất kỳ một tiến trình thực thi nào được phép khởi động.

Một sự diễn giải kinh điển và mang tính phổ quát nhất về ý nghĩa của hiện tượng kéo lên thường được phác họa như một hành động nâng nhấc—mang hình bóng của một lực sĩ đang dùng sức đẩy một khối tạ khổng lồ vút lên cao—nhấc bổng toàn bộ mọi định danh biến số vượt qua trọng lực để vươn lên tận vị trí đỉnh cao nhất của một không gian phạm vi. Lời giải thích được truyền miệng và thường xuyên được khẳng định chắc nịch nhất trong giới lập trình viên là: cỗ máy JavaScript sẽ thực sự, bằng một ma thuật vật lý nào đó, tiến hành viết lại và cấu trúc lại toàn bộ cái chương trình đó trước thời điểm thực thi, khiến cho mặt mũi của cái đoạn mã bị xào xáo lại sao cho phần khai báo nằm gọn gàng ở trên, bỏ lại phần gán giá trị ở dưới. Cái phép ẩn dụ kéo lên này mạnh dạn đưa ra một giả thuyết đầy táo bạo rằng bộ máy JavaScript đã tiến hành một công đoạn tiền xử lý, lướt qua đoạn mã gốc và tự ý sắp xếp lại trật tự của nó một chút, với mục đích tối thượng là gom toàn bộ các câu lệnh khai báo vứt lên trên đầu của các không gian phạm vi tương ứng của chúng, trước khi tiếng cúng còi báo hiệu bắt đầu thời gian chạy vang lên. Đẩy đi xa hơn nữa, phép ẩn dụ này còn mạnh miệng tuyên bố rằng các câu lệnh khai báo hàm, với toàn bộ nguyên vẹn hình hài và nội tạng của chúng, đều được nhấc bổng lên tận đỉnh của mỗi không gian phạm vi.

Cái luật bất thành văn do phép ẩn dụ kéo lên này đẻ ra là: các câu lệnh khai báo hàm sẽ được đặc cách ưu tiên kéo lên trước nhất, và ngay lập tức bám gót theo sau là các biến số thông thường sẽ được kéo lên tập kết ngay bên dưới các hàm. Từ đó, câu chuyện cổ tích về hiện tượng kéo lên gieo rắc một niềm tin ngây thơ rằng chương trình đã bị cỗ máy JavaScript tự động sắp xếp lại thành một trật tự hoàn toàn khác biệt. Phải thừa nhận rằng, cái phép ẩn dụ kéo lên này mang lại một sự tiện lợi và thoải mái vô cùng to lớn cho tư duy. Lợi ích nhãn tiền của nó là cho phép chúng ta có thể gạt phăng đi, nhắm mắt làm ngơ trước toàn bộ quá trình tiền xử lý nhìn-trước-đoán-sau đầy ma thuật và phức tạp tột độ vốn dĩ mang tính chất bắt buộc để hệ thống có thể đào bới, lùng sục ra toàn bộ các câu lệnh khai báo đang nằm ẩn vùi sâu dưới vô vàn các tầng lớp không gian phạm vi lồng ghép, rồi bằng một cách thần kỳ nào đó dịch chuyển (kéo lên) chúng vút lên trên đỉnh; thay vào đó, chúng ta có thể an tâm kê cao gối ngủ và tư duy về cách thức chương trình vận hành y hệt như thể nó đang được cỗ máy JavaScript chạy băng qua trong một lượt quét duy nhất, tuyến tính trôi tuột từ trên xuống dưới. Mô hình thi hành một lượt duy nhất này chắc chắn mang lại một cảm giác thẳng thắn, đơn giản và dễ tiêu hóa hơn gấp vạn lần so với cái lời khẳng định chắc nịch về một quá trình xử lý phức tạp phải chia làm hai giai đoạn tách biệt mà Chương 1 đã trình bày.

Việc sử dụng khái niệm kéo lên như một cơ chế cơ học tưởng tượng nhằm tái cấu trúc lại vị trí các đoạn mã có thể là một sự đơn giản hóa mang tính chất cám dỗ và đầy sức hút, nhưng sự thật phũ phàng là nó hoàn toàn sai lệch và thiếu tính chính xác về mặt kỹ thuật. Cỗ máy JavaScript vĩnh viễn không bao giờ thực hiện bất kỳ một hành động vật lý nào để sắp xếp lại các dòng mã của bạn. Nó không hề sở hữu một con mắt phép thuật nào để có thể nhìn xuyên thấu không gian và dự đoán trước được các khai báo; con đường duy nhất, chính xác và khoa học nhất để có thể săn lùng ra chúng, cũng như vẽ ra toàn bộ các ranh giới không gian phạm vi chằng chịt trong chương trình, là việc bộ máy bắt buộc phải tiến hành phân tích cú pháp toàn bộ tệp mã nguồn từ đầu đến cuối. Và bạn có đoán được quá trình phân tích cú pháp thực chất là gì không? Đó chính là giai đoạn mở màn tiên phong trong cái mô hình xử lý hai giai đoạn! Tuyệt đối không tồn tại bất kỳ một thủ thuật uốn éo tư duy tinh vi nào có thể giúp bạn lẩn tránh hay phủ nhận sự thật kiến trúc sắt đá đó.

Vậy thì, nếu như cái phép ẩn dụ kéo lên này là một sự sai lệch (nói một cách nhẹ nhàng nhất), thì chúng ta nên hành xử ra sao và đặt cái thuật ngữ này vào đâu cho đúng? Tôi bảo lưu quan điểm rằng nó vẫn duy trì được một giá trị sử dụng vô cùng to lớn—minh chứng rõ ràng nhất là ngay cả những chuyên gia đầu sỏ, các thành viên cốt cán của Ủy ban Kỹ thuật 39 vẫn thường xuyên đem nó ra sử dụng trong các cuộc đàm thoại!—thế nhưng tôi kịch liệt phản đối việc chúng ta ảo tưởng và rêu rao rằng nó là một tiến trình tái sắp xếp mã nguồn vật lý có thật. Tôi khẳng định một cách đanh thép rằng thuật ngữ kéo lên nên và phải được dùng độc quyền để chỉ định cho một thao tác trong thời gian biên dịch, đó là việc cỗ máy tự động kiến tạo ra các chỉ thị mã máy chạy trong thời gian thực nhằm mục đích thực thi việc đăng ký nhân khẩu một cách tự động cho một biến số ngay tại cái vạch xuất phát của không gian phạm vi mà nó trực thuộc, và quá trình đăng ký này được lặp đi lặp lại một cách nhẫn nại mỗi khi luồng thực thi đặt chân vào cái không gian phạm vi đó. Đó là một sự dịch chuyển tư duy vô cùng tinh tế, nhỏ bé nhưng lại mang tính chất sống còn và vĩ đại: chúng ta phải đưa hiện tượng kéo lên thoát khỏi cái mác là một hành vi thời gian chạy đầy ma thuật, và trả nó về đúng cái ngai vàng nguyên thủy của nó trong danh sách các tác vụ tĩnh của thời gian biên dịch.

Sự thật về hành vi tái khai báo trong cùng một phạm vi

Bạn đã bao giờ tự đặt ra một giả thuyết về những thảm họa kiến trúc nào sẽ xảy ra nếu như một biến số bị ép buộc phải trải qua quá trình khai báo đến tận hai lần hoặc nhiều hơn, nhưng lại bị nhốt chung trong cùng một giới hạn không gian phạm vi chật hẹp hay chưa? Hãy cùng đưa vào tầm ngắm một đoạn mã nơi biến số tên sinh viên được khai báo và gán giá trị, sau đó in ra màn hình, rồi ngay phía dưới lại tiếp tục xuất hiện một câu lệnh khai báo biến y hệt bằng từ khóa kiểu cũ mà không kèm thao tác gán. Bạn sẽ đặt cược vào kết quả nào sẽ được in ra ở cái thông điệp thứ hai? Một bộ phận không nhỏ các lập trình viên thường có xu hướng tin vào một ảo giác rằng cái câu lệnh khai báo thứ hai kia đã thực sự tiến hành tái khai báo cái biến số đó (và qua đó đã thực hiện một hành vi cài đặt lại hoặc xóa sổ giá trị của nó), do đó họ đặt kỳ vọng một cách ngây thơ rằng giá trị trống rỗng. sẽ được trả về và in ra màn hình.

Thế nhưng, dưới góc độ của bộ đặc tả kiến trúc, liệu có thực sự tồn tại một khái niệm gọi là một biến số bị tái khai báo ngay bên trong một không gian phạm vi duy nhất hay không? Câu trả lời là một tiếng Không vang dội. Nếu bạn phân tích cái chương trình này bằng lăng kính của cái phép ẩn dụ kéo lên ngây thơ kia, thì đoạn mã sẽ bị ảo tưởng là được tái cấu trúc lại phục vụ cho mục đích thực thi bằng cách đưa cả hai câu lệnh khai báo lên trên cùng. Vì bản chất sâu xa của hiện tượng kéo lên xoay quanh việc thực hiện thủ tục đăng ký nhân khẩu cho một biến số ngay tại cái vạch xuất phát của một không gian phạm vi, nên hệ thống sẽ hoàn toàn rảnh rỗi và chẳng có bất cứ một thao tác vật lý nào cần phải được thi hành ở khúc giữa của cái không gian phạm vi đó, nơi mà cái chương trình gốc đã từng đặt một câu lệnh khai báo thứ hai bằng từ khóa kiểu cũ. Cái câu lệnh thứ hai đó, trớ trêu thay, lại hoàn toàn chỉ là một hành vi vô dụng (no-operation), một dòng lệnh vô tri không mang lại bất kỳ một ý nghĩa kiến trúc nào.

Một chi tiết kiến trúc khác mang tầm quan trọng ngang ngửa cần phải được chỉ đích danh là: câu lệnh khai báo biến trần trụi hoàn toàn không mang ý nghĩa tương đương và không được phép đánh đồng với một câu lệnh khai báo biến kèm theo thao tác gán tường minh bằng giá trị trống rỗng., mặc cho đại đa số đều đang lầm tưởng như vậy. Bằng cách thêm vào thao tác gán giá trị trống rỗng. một cách tường minh, chúng ta đã can thiệp vật lý và ép buộc giá trị của biến số phải thay đổi thành trống rỗng., khác biệt hoàn toàn với việc kỳ vọng hệ thống sẽ tự động, ngầm định thực hiện cái thao tác gán đó nếu như chúng ta lười biếng bỏ qua nó. Việc lặp lại một câu lệnh khai báo bằng từ khóa kiểu cũ cho cùng một tên định danh bên trong một ranh giới không gian phạm vi về cơ bản chỉ là một thao tác thừa thãi, tốn công vô ích của lập trình viên. Hãy tiếp tục chiêm ngưỡng một minh họa khác về sự vô nghĩa này, nhưng lần này là với một tên định danh bị giằng xé giữa một câu lệnh khai báo biến và một câu lệnh khai báo hàm mang cùng tên gọi. Lệnh khai báo biến đầu tiên sẽ đứng ra làm thủ tục đăng ký cái định danh đó vào hộ khẩu của không gian phạm vi, và do nó mang dòng máu của từ khóa kiểu cũ, nên hệ thống sẽ tự động nhồi nhét giá trị khởi tạo mặc định là trống rỗng. cho nó. Câu lệnh khai báo hàm theo gót phía sau hoàn toàn không phải tốn sức để đăng ký lại cái định danh đó nữa, thế nhưng, nhờ vào đặc quyền tối thượng của hiện tượng kéo lên của hàm., nó đã ngang nhiên chà đạp và đè bẹp cái giá trị khởi tạo mặc định kia để ép hệ thống phải sử dụng cái tham chiếu hàm thực sự của nó. Cái câu lệnh khai báo biến thứ hai xuất hiện bơ vơ ở đó rốt cuộc cũng chẳng có khả năng tác động hay làm nên trò trống gì, bởi vì cái định danh đó đã an tọa vững vàng ở đó rồi, và hiện tượng kéo lên của hàm. thì đã vĩnh viễn tước đoạt lấy quyền ưu tiên cao nhất cho khâu tự động khởi tạo giá trị.

Cơ chế ngăn chặn tái khai báo của các từ khóa hiện đại

Vậy thì kịch bản hệ thống sẽ xoay chuyển ra sao nếu như chúng ta cố tình nhai lại một câu lệnh khai báo bên trong một không gian phạm vi, nhưng lần này lại sử dụng vũ khí là các từ khóa hiện đại như let hoặc const? Chương trình quái gở này sẽ bị chặn đứng không thương tiếc, vĩnh viễn không bao giờ có cơ hội được chạy thực thi, mà thay vào đó nó sẽ kích nổ một Lỗi cú pháp. ngay tắp lự. Phụ thuộc vào cái môi trường JavaScript cụ thể mà bạn đang trú ngụ, cái thông điệp báo lỗi ném thẳng vào mặt bạn sẽ mang nội dung cảnh báo đại loại như: Tên định danh đã từng được khai báo trước đó. Nói một cách rành mạch và không khoan nhượng, đây chính là một kịch bản nơi mà mọi mưu đồ mờ ám nhằm tái khai báo một biến số đều bị bộ đặc tả ngôn ngữ nghiêm cấm một cách tuyệt đối và rõ ràng! Không chỉ dừng lại ở việc sự hiện diện của hai câu lệnh khai báo sử dụng từ khóa let sẽ châm ngòi cho cái lỗi này. Mức độ nghiêm ngặt còn đi xa đến mức: nếu bất kỳ một câu lệnh khai báo nào trong nhóm có dính dáng đến từ khóa let, thì bất chấp việc cái câu lệnh còn lại có đang sử dụng từ khóa let hay từ khóa kiểu cũ var, thì cái lỗi chí mạng đó vẫn sẽ bị hệ thống kích nổ một cách phũ phàng không phân biệt.

Trong toàn bộ mọi kịch bản lai tạp đó, một Lỗi cú pháp. luôn luôn trực chờ và giáng xuống đầu cái câu lệnh khai báo thứ hai. Kết luận rút ra ở đây là, con đường sống sót duy nhất để bạn có thể thực hiện thành công cái gọi là tái khai báo một biến số là bạn bắt buộc phải đồng bộ và sử dụng duy nhất cái từ khóa cổ lỗ sĩ var cho toàn bộ (hai hoặc hàng tá) các câu lệnh khai báo của cái biến số đó. Nhưng động lực sâu xa nào lại thúc đẩy hội đồng thiết kế phải ban hành lệnh cấm khắc nghiệt này? Nguyên lý dẫn đến sự tồn tại của cái lỗi này về mặt bản chất không thực sự xuất phát từ một ràng buộc kỹ thuật bất khả kháng nào cả, bởi vì lịch sử đã chứng minh hành vi tái khai báo của từ khóa var vẫn luôn được hệ thống dung túng và vận hành trơn tru từ thuở khai sinh lập địa; một cách hiển nhiên, một sự khoan hồng tương tự hoàn toàn có thể được ban phát cho từ khóa let nếu họ muốn.

Nguyên nhân thực sự đằng sau quyết định này lại mang nặng hơi hướng của một cuộc thanh trừng văn hóa, một nỗ lực kỹ nghệ xã hội học nhằm nắn gân cộng đồng lập trình. Việc các lập trình viên có thói quen tái khai báo bừa bãi các biến số luôn bị coi là một cái gai trong mắt bởi một bộ phận lớn giới chuyên gia, bao gồm cả những bộ óc sừng sỏ nhất đang ngồi trong Ủy ban Kỹ thuật 39, vì họ coi đó là một thói quen lập trình tồi tệ, một cái bẫy chết người có khả năng gieo rắc vô số những con rệp máy (bugs) tàn phá chương trình. Chính vì vậy, khi phiên bản đặc tả thứ sáu chính thức vén màn giới thiệu từ khóa let cho toàn thế giới, họ đã đồng lòng thông qua một nghị quyết sắt đá nhằm chặt đứt hoàn toàn hành vi tái khai báo này bằng việc vung ra một cái lỗi hệ thống cứng rắn. Khi Trình biên dịch trong lúc thu thập thông tin tiến hành chất vấn Người quản lý phạm vi về một câu lệnh khai báo, nếu như cái tên định danh đó đã từng được làm thủ tục đăng ký từ trước, và nếu như một trong hai hoặc cả hai cái câu lệnh khai báo đó có dính líu đến từ khóa let, thì một cái lỗi sẽ được ném ra không thương tiếc. Thông điệp răn đe mang tính giáo dục mà hệ thống muốn khắc sâu vào tâm trí của các lập trình viên là: Hãy chấm dứt ngay lập tức cái thói quen dựa dẫm vào những trò tái khai báo cẩu thả và lỏng lẻo đi!.

Vòng đời của hằng số, vòng lặp và Vùng chết tạm thời

Từ khóa hiện đại không chỉ thay đổi cách chúng ta khai báo biến số mà còn áp đặt những vòng đời khắt khe lên chúng, đặc biệt là hằng số và các ranh giới thời gian.

Đặc thù của hằng số và sự khởi tạo bắt buộc

Từ khóa const đóng vai trò như một người gác cổng, mang trong mình một bộ quy tắc ràng buộc mang tính chất khắc nghiệt và độc tài hơn rất nhiều so với người anh em let của nó. Hoàn toàn tương đồng với let, từ khóa const bị tước đoạt mọi quyền lực để có thể được sử dụng lặp lại cho cùng một tên định danh bên trong cùng một ranh giới không gian phạm vi. Tuy nhiên, trái ngược hoàn toàn với let - nơi mà lệnh cấm tái khai báo chủ yếu được áp đặt dựa trên những quan điểm mang tính chất phong cách và định hướng thói quen lập trình - thì đằng sau lệnh cấm của const lại là một lý do kỹ thuật mang tính chất cốt lõi và không thể vượt qua, một lý do đủ sức mạnh để đè bẹp mọi nỗ lực thỏa hiệp.

Bản chất của từ khóa const đặt ra một yêu cầu tiên quyết mang tính sống còn: một biến số hằng bắt buộc phải được truyền vào một giá trị khởi tạo ngay tại khoảnh khắc nó chào đời, vì vậy việc cố tình lơ đễnh hay bỏ sót một thao tác gán đi kèm với câu lệnh khai báo sẽ ngay lập tức bị hệ thống trừng phạt bằng một Lỗi cú pháp.. Sứ mệnh tối thượng của các câu lệnh khai báo const là kiến tạo ra những biến số kiên cố, những pháo đài dữ liệu vĩnh viễn không thể bị tái gán (re-assigned) bằng một giá trị mới. Cái biến số tên sinh viên bị khóa chặt vĩnh viễn, không thể bị tái gán bởi bất kỳ một nỗ lực nào khác đơn giản là vì nó đã được khai sinh và bảo vệ bởi một từ khóa const. Xin hãy lưu ý một cách cẩn trọng đến một chi tiết vô cùng tinh tế ở đây: cái lỗi bị hệ thống ném ra khi bạn ngoan cố cố gắng tái gán một hằng số là một Lỗi kiểu dữ liệu., chứ không hề là một Lỗi cú pháp.. Sự khác biệt vi tế giữa hai chủng loại lỗi này thực chất mang một ý nghĩa kiến trúc cực kỳ quan trọng, nhưng thật đáng buồn là nó lại quá dễ dàng bị các nhà phát triển lướt qua và bỏ lỡ. Những lỗi cú pháp đóng vai trò đại diện cho những khiếm khuyết vật lý, những vết nứt trong cấu trúc của bản thân chương trình, những thứ có sức mạnh tàn phá ngăn chặn chương trình ngay từ lúc chưa kịp bấm nút khởi động luồng thực thi. Ngược lại, những lỗi kiểu dữ liệu lại là hiện thân của những sự cố đứt gãy logic phát sinh trong quá trình chương trình đang miệt mài chạy thực thi.

Một chuỗi suy luận logic không thể bẻ gãy được hình thành: nếu như các biến số được khai báo bởi const đã bị tước đoạt quyền tái gán, và nếu như các khai báo const luôn luôn thèm khát và đòi hỏi bắt buộc phải có các thao tác gán đi kèm, thì chúng ta đã có trong tay một lý do kỹ thuật vô cùng trong sáng và vững chãi để giải thích tại sao const lại bắt buộc phải nghiêm cấm mọi hình thái tái khai báo: bởi vì bất kỳ một mưu đồ tái khai báo bằng const nào về bản chất cũng sẽ ngầm chứa một sự tái gán giá trị cho const, một hành động phản nghịch vĩnh viễn không được hệ thống dung thứ! Đứng trước thực tại là hành vi tái khai báo bằng const bắt buộc phải bị cấm tiệt (dựa trên những nền tảng kỹ thuật vững chắc đó), hội đồng Ủy ban Kỹ thuật 39 về cơ bản đã có một cảm quan sâu sắc rằng, để bảo vệ sự đồng nhất và tính nhất quán cho toàn bộ ngôn ngữ, hành vi tái khai báo bằng let cũng nên chịu chung số phận bị đưa lên đoạn đầu đài. Mặc dù vẫn còn đó những tranh cãi nảy lửa về việc liệu đây có phải là một quyết định tối ưu và hoàn hảo nhất hay không, nhưng ít nhất, chúng ta đã thấu hiểu được những dòng suy nghĩ và lập luận kiến trúc nằm đằng sau cái quyết định mang tính lịch sử đó.

Xử lý khai báo biến số bên trong các cấu trúc vòng lặp

Xuyên suốt những cuộc mổ xẻ vừa qua, một thông điệp kiến trúc đã trở nên trong suốt và hiển nhiên: bản thân hệ sinh thái ngôn ngữ JavaScript thực sự không hề mong muốn, và luôn cố gắng dập tắt mọi ý định của chúng ta trong việc tái khai báo các biến số bên trong ranh giới của cùng một không gian phạm vi. Lời răn đe này có lẽ sẽ mang đến một cảm giác vô cùng thẳng thắn và dễ nuốt, cho đến khi tư duy của bạn bắt đầu va chạm và đánh giá xem liệu nó sẽ mang lại những hệ lụy điên rồ gì đối với việc lặp đi lặp lại một cách cơ học các câu lệnh khai báo bên trong các guồng quay của các vòng lặp. Vậy liệu cái biến giá trị ngẫu nhiên có đang phải chịu đựng quá trình bị tái khai báo một cách liên tục, dồn dập hết lần này đến lần khác bên trong cái chương trình này hay không? Liệu chúng ta có sắp sửa bị một cơn mưa lỗi hệ thống ném thẳng vào mặt hay không? Câu trả lời ngắn gọn là Không.

Toàn bộ hiến pháp quy định về phạm vi (bao gồm cả những điều luật liên quan đến việc tái khai báo đối với những biến số được kiến tạo bởi từ khóa let) đều được hệ thống áp dụng và thực thi một cách biệt lập cho từng cá thể không gian phạm vi.. Để diễn giải một cách dễ hiểu hơn, mỗi khi bánh xe thực thi của hệ thống lăn vào một không gian phạm vi trong thời gian chạy, toàn bộ mọi thiết lập đều được tái khởi động lại từ con số không. Mỗi một chu kỳ quay của vòng lặp sẽ tự động kiến tạo ra một cá thể không gian phạm vi hoàn toàn mới mẻ của riêng nó, và bên trong cái giới hạn của cá thể không gian phạm vi non trẻ đó, cái biến giá trị ngẫu nhiên chỉ phải trải qua duy nhất một lần khai báo duy nhất. Vì vậy, thực chất không hề tồn tại bất kỳ một âm mưu tái khai báo nào ở đây cả, và theo lẽ tự nhiên, sẽ không có một cái lỗi nào bị hệ thống kích nổ. Trước khi chúng ta mở rộng tầm nhìn để xem xét các hình thái vòng lặp phức tạp khác, một giả thuyết được đặt ra là: kịch bản sẽ biến thiên ra sao nếu như cái câu lệnh khai báo bên trong đoạn mã vừa rồi bị biến đổi thành một từ khóa kiểu cũ var? Liệu cái biến đó có đang bị tái khai báo ở đây không, đặc biệt là khi chúng ta đều đã nắm rõ đặc tính dung túng cho việc đó của từ khóa này? Câu trả lời vẫn tiếp tục là Không. Bởi vì từ khóa var hoàn toàn không được hệ thống đối xử như một câu lệnh khai báo kiến tạo ra không gian phạm vi khối, nên nó sẽ ngang nhiên phớt lờ cái khối vòng lặp và bám thẳng vào không gian phạm vi toàn cục hoặc hàm bao bọc bên ngoài. Do đó, trên toàn cục hệ thống chỉ tồn tại duy nhất một cái biến số duy nhất, sống chung trong cùng một không gian phạm vi với cái biến kiểm soát vòng lặp. Không hề có bất kỳ một sự tái khai báo nào diễn ra ở đây cả!

Một chiếc chìa khóa vạn năng để bạn có thể giữ cho cái mớ bòng bong lý thuyết này được rạch ròi và ngăn nắp trong đầu là hãy luôn khắc cốt ghi tâm rằng: các từ khóa khai báo như var, let,const trên thực tế đã bị hệ thống loại bỏ và xóa sổ hoàn toàn khỏi đoạn mã ngay trước thời khắc mà chương trình bắt đầu nổ máy chạy thực thi. Bọn chúng đã được giao phó toàn quyền và bị hệ thống biên dịch xử lý một cách triệt để từ trước đó rất lâu rồi. Nếu bạn có thể rèn luyện cho tâm trí mình khả năng tẩy xóa đi những cái từ khóa khai báo đó bằng trí tưởng tượng, rồi sau đó mới bắt tay vào việc cố gắng xử lý và luân chuyển đoạn mã trong đầu, thì kỹ năng đó sẽ hỗ trợ đắc lực giúp bạn đưa ra được phán đoán chính xác xem liệu các quá trình (tái) khai báo có khả năng xảy ra hay không, và nếu có thì vào lúc nào. Vậy đối với các hình thái vòng lặp truyền thống như for, thì cái biến số đếm i có đang bị tái khai báo hay không? Để trả lời, bạn phải tự vấn xem cái biến i đó đang nằm ở không gian phạm vi nào. Trực giác có thể đánh lừa bạn rằng nó đang nằm ở không gian phạm vi bao bọc bên ngoài, nhưng sự thật là nó nằm chễm chệ ngay trong cái không gian phạm vi của cái thân khối vòng lặp. Tương tự như vậy, đối với các vòng lặp duyệt qua thuộc tính hoặc phần tử, cái biến số được khai báo cũng được hệ thống đối xử như thể nó nằm lọt thỏm bên trong cái thân khối vòng lặp, và do đó nó sẽ được xử lý riêng biệt cho từng chu kỳ lặp. Rõ ràng là không có sự tái khai báo nào hết. Nhưng mọi thứ sẽ bắt đầu trở nên rối rắm và phức tạp hơn gấp bội khi chúng ta kéo từ khóa const vào cuộc chơi của các vòng lặp. Mặc dù const hoạt động vô cùng êm ái và hoàn hảo bên trong các vòng lặp duyệt mảng/đối tượng vì mỗi chu kỳ lặp đều khởi tạo một biến số mới hoàn toàn độc lập, thế nhưng nó lại đứt gánh và sụp đổ thảm hại khi bị nhét vào cái vòng lặp for truyền thống. Nguyên nhân sâu xa làm kích nổ cái lỗi này là gì? Vấn đề cốt lõi không nằm ở chỗ cái biến i được kiến tạo ra một lần trong mỗi chu kỳ lặp, mà nó nằm ở chỗ cái biểu thức tăng trưởng i++ về mặt bản chất cơ học là một hành động tái gán giá trị mới (chứ không phải là tái khai báo), một hành động bị các hằng số cấm tiệt và coi là một sự phỉ báng.

Giải mã Vùng chết tạm thời và quá trình khởi tạo

Đối với những biến số được sinh ra từ các câu lệnh khai báo bằng từ khóa kiểu cũ, cái biến số đó không những được hệ thống nhấc bổng lên tận vị trí cao nhất của không gian phạm vi của nó, mà nó còn nhận được một đặc ân là được hệ thống tự động khởi tạo bằng một giá trị trống rỗng., một cơ chế hoàn hảo để cái biến số đó có thể lập tức được mang ra sử dụng một cách tự do xuyên suốt toàn bộ không gian phạm vi. Thế nhưng, những câu lệnh khai báo sử dụng các từ khóa hiện đại như letconst lại mang một hình hài và số phận hoàn toàn không giống như vậy trên phương diện này. Khi bạn cố gắng chạm vào một biến số let trước khi dòng mã chứa câu lệnh khai báo của nó kịp chạy, kết quả thảm khốc mà đoạn chương trình này gặt hái được là một Lỗi tham chiếu. bị ném thẳng vào mặt bạn ngay tại dòng lệnh đầu tiên. Thông điệp lỗi này là một minh chứng vô cùng đanh thép và chính xác nhằm phơi bày cái gốc rễ của vấn đề: cái biến số tên sinh viên đó thực sự đã tồn tại và chiếm chỗ trong bộ nhớ ngay ở dòng đầu tiên, thế nhưng bi kịch là nó vẫn chưa từng được hệ thống khởi tạo, do đó, nó bị niêm phong và tuyệt đối không thể được đem ra sử dụng vào lúc này.

Một câu hỏi mang tính triết học kỹ thuật được đặt ra là: làm thế quái nào mà chúng ta có thể thực hiện thao tác khởi tạo cho một biến số đang nằm trong tình trạng chưa được khởi tạo? Đối với các từ khóa let / const, con đường duy nhất và độc đạo để có thể hoàn thành tâm nguyện đó là thông qua một phép gán giá trị được móc nối và đính kèm trực tiếp vào một câu lệnh khai báo. Một phép gán đứng đơn độc bơ vơ giữa dòng đời là hoàn toàn bất lực và vô giá trị trong việc phá vỡ tình trạng này! Hãy nhớ lại những lập luận mà chúng ta đã không ngừng khẳng định từ đầu đến giờ rằng: Trình biên dịch rốt cuộc sẽ thẳng tay loại bỏ toàn bộ các từ khóa khai báo, và thay thế chúng bằng những chỉ thị mã máy nằm ở vị trí cao nhất của mỗi không gian phạm vi để tiến hành thủ tục đăng ký cho các định danh tương ứng. Khi đi sâu vào phân tích luồng chạy của cơ chế này, chúng ta sẽ khám phá ra một sắc thái kiến trúc bổ sung cực kỳ vi tế là: Trình biên dịch đồng thời cũng nhét thêm một chỉ thị mã máy nằm ở đâu đó khúc giữa của chương trình, ngay tại đúng cái tọa độ không gian mà cái biến số đó được khai báo vật lý, nhằm mục đích xử lý quá trình tự động khởi tạo cho cái câu lệnh khai báo đó. Chúng ta bị cấm tiệt việc sử dụng cái biến số đó vào bất kỳ thời điểm nào trước khi cái quá trình khởi tạo thiêng liêng đó thực sự được diễn ra thành công.

Cái thuật ngữ mang đậm chất học thuật do Ủy ban Kỹ thuật 39 sáng tạo ra nhằm ám chỉ cái khoảng thời gian kéo dài đằng đẵng từ khoảnh khắc bánh xe thực thi lăn vào một không gian phạm vi cho đến tận khi cái thao tác tự động khởi tạo của biến số đó chính thức được hoàn tất là: Vùng chết tạm thời (Temporal Dead Zone). Vùng chết tạm thời chính là một khung cửa sổ thời gian tăm tối nơi mà một biến số dù đã tồn tại vật lý nhưng vẫn mang thân xác trống rỗng, chưa được khởi tạo, và hệ quả là nó miễn nhiễm và từ chối mọi quyền truy cập dưới bất kỳ hình thức nào. Quyền năng duy nhất có thể phá vỡ lời nguyền này và hoàn tất việc khởi tạo chính là việc luồng thực thi chạy qua những chỉ thị mà Trình biên dịch đã cẩn thận bỏ lại ngay tại cái tọa độ của câu lệnh khai báo gốc. Chỉ sau khi cái khoảnh khắc lịch sử đó trôi qua, Vùng chết tạm thời mới chính thức tan biến, và cái biến số đó mới được trả tự do để có thể được sử dụng một cách thoải mái cho toàn bộ phần đời còn lại của không gian phạm vi. Từ khóa kiểu cũ về mặt lý thuyết kỹ thuật cũng sở hữu cho riêng nó một Vùng chết tạm thời, nhưng độ dài thời gian của cái vùng chết này bằng không tuyệt đối, và do đó nó trở nên vô hình và không thể nào quan sát được đối với các chương trình của chúng ta! Chỉ duy nhất letconst mới bị mắc kẹt với một Vùng chết tạm thời có thể cảm nhận và quan sát được.

Có một sự thật là chữ tạm thời nằm trong Vùng chết tạm thời thực sự và chắc chắn đang ám chỉ đến yếu tố thời gian thực thi. chứ tuyệt đối không phải là vị trí vật lý trong đoạn mã.. Mặc dù xét về mặt vị trí hình học, cái hàm gọi sử dụng biến số nằm ở tít dưới cái dòng lệnh khai báo, thế nhưng nếu xét về dòng chảy thời gian, cái hàm đó lại bị hệ thống gọi ra thực thi từ trước khi cái câu lệnh let kịp được cỗ máy chạm tới, và tất nhiên trong suốt cái khoảng thời gian đó, cái biến số tội nghiệp vẫn đang bị giam cầm trong Vùng chết tạm thời của nó! Đó chính là cội nguồn sâu xa kích nổ cái lỗi hệ thống. Đang tồn tại một nhận thức méo mó cực kỳ phổ biến trong cộng đồng rằng Vùng chết tạm thời mang ý nghĩa là các từ khóa hiện đại hoàn toàn miễn nhiễm và không bị kéo lên. Đây là một lời khẳng định sai lệch hoàn toàn, hoặc bét nhất cũng là một sự định hướng gây nhầm lẫn trầm trọng. Chúng chắc chắn và hiển nhiên bị kéo lên. Tóm tắt lại một cách sắc bén, những cái lỗi Vùng chết tạm thời bị kích nổ là bởi vì các câu lệnh khai báo hiện đại thực sự đã nhấc bổng các định danh của chúng lên tận vị trí cao nhất của không gian phạm vi, thế nhưng, trái ngược với từ khóa kiểu cũ, chúng đã tàn nhẫn trì hoãn cái thao tác tự động khởi tạo của các biến số đó cho đến tận cái thời khắc nằm trên dòng chảy thời gian của đoạn mã nơi mà cái câu lệnh khai báo gốc xuất hiện vật lý.

Kết luận

Thao tác và vật lộn với các biến số mang trong mình mức độ sắc thái và chiều sâu kiến trúc phức tạp hơn gấp ngàn lần so với những gì mà vẻ bề ngoài đơn giản của chúng đánh lừa trực giác ban đầu. Hiện tượng kéo lên, cơ chế (tái) khai báo, và cái hố đen Vùng chết tạm thời (TDZ) là những cội nguồn bất tận thường xuyên gieo rắc sự hoang mang và lú lẫn cho giới phát triển phần mềm, đặc biệt là đối với những người nhập cư từ các hệ sinh thái ngôn ngữ khác chuyển sang dấn thân vào vùng đất JavaScript. Trước khi nhổ neo tiến về phía trước, bạn bắt buộc phải đảm bảo rằng cái mô hình tư duy kiến trúc của bản thân đã được cắm rễ một cách vững chắc và sâu sắc vào những khía cạnh cốt lõi này của không gian phạm vi và vòng đời biến số trong ngôn ngữ. Hành vi khai báo và tái khai báo các biến số thường xuyên châm ngòi cho sự lúng túng nếu như chúng bị tư duy sai lệch như là những thao tác của thời gian chạy. Nhưng một khi bạn đã giác ngộ và dịch chuyển hệ quy chiếu tư duy để nhìn nhận những thao tác này dưới lăng kính của thời gian biên dịch, những sự lố bịch và những chiếc bóng ám ảnh sẽ tự động tan biến vào hư vô. Lỗi Vùng chết tạm thời mang đến một trải nghiệm cực kỳ quái đản và gây ức chế tột độ khi bạn không may va phải nó. Thật may mắn thay, cái bóng ma này lại tương đối dễ dàng để bị né tránh và tiêu diệt nếu như bạn tự rèn luyện cho mình một thói quen cẩn trọng và kỷ luật: hãy luôn luôn đặt toàn bộ các câu lệnh khai báo hiện đại của mình ở vị trí cao nhất của bất kỳ không gian phạm vi nào. Khi bạn đã thành công lèo lái con thuyền tư duy vượt qua mọi khúc cua ngoằn ngoèo và hiểm hóc của không gian phạm vi biến số này, chương tài liệu tiếp theo sẽ tiếp tục trải thảm đỏ để phơi bày ra toàn bộ những nhân tố cốt lõi đóng vai trò kim chỉ nam định hướng cho các quyết định kiến trúc của chúng ta khi phải lựa chọn vị trí đặt các câu lệnh khai báo vào những không gian phạm vi muôn hình vạn trạng, đặc biệt là những khối lồng ghép sâu.

Chuyên mục lap-trinh

Theo dõi hành trình

Hãy để lại thông tin, khi có gì mới thì Nhà văn sẽ gửi thư đến bạn để cập nhật. Cam kết không gửi email rác.

Họ và tên

Email liên lạc

Đôi dòng chia sẻ