Computer >> Máy Tính >  >> Lập trình >> Javascript

Các nguyên tắc cơ bản về web:Phạm vi và Đóng JavaScript - Sơ lược

Một trong những từ thông dụng lớn nhất trong ngôn ngữ JavaScript là đóng. Đó là chủ đề của nhiều câu hỏi phỏng vấn xin việc tại các công ty FAANG. Trong bài viết này, chúng ta sẽ nói về việc đóng và phạm vi, minh họa các khái niệm của nó bằng các ví dụ đơn giản, sau đó kết thúc bằng một câu hỏi mẫu từ cuộc phỏng vấn với một trong những gã khổng lồ công nghệ lớn hơn.

Phạm vi

Khi ai đó nói với bạn điều gì đó nằm trong hoặc không thuộc phạm vi của một dự án, điều đó có nghĩa là gì?

Tôi muốn nghĩ đến kính tiềm vọng hoặc kính viễn vọng khi tôi nghĩ ra câu trả lời cho điều này. Những công cụ này cho chúng ta thấy tất cả những thứ trong giới hạn của ống kính mà nó có:nó nằm trong phạm vi . Nếu nó nằm ngoài phạm vi , bạn không thể nhìn quá đường kính của ống kính. Và chiếu ánh sáng vào thứ gì đó ngoài đường kính là không thể. Bạn nên suy nghĩ về điều này khi chúng ta nói về ba loại phạm vi rất quan trọng và khác biệt trong JavaScript:cục bộ, toàn cầu và từ vựng.

Phạm vi địa phương

Phạm vi địa phương là phạm vi nhỏ nhất trong ba phạm vi mà chúng ta sẽ nói đến hôm nay. Khi chúng ta khai báo một hàm, bất kỳ thứ gì bên trong dấu ngoặc ({}) đều được coi là cục bộ của hàm. Khi JavaScript engine đọc hàm, nó sẽ khai báo các biến; khi nó kết thúc nó sẽ phá hủy các biến.

function greeting() {
 var websiteName = 'Career Karma';
 return `Hello ${websiteName}`;
}
 
console.log(greeting()); // Hello Career Karma
console.log(websiteName); // ReferenceError: websiteName is not defined

Như bạn có thể thấy, khi chúng ta “console.log ()” kết quả của hàm chào được gọi, chúng ta có thể truy cập vào websiteName sau khi hàm được thực thi. Điều này cung cấp cho chúng tôi chuỗi "Hello Career Karma" mà chúng tôi đang tìm kiếm. console.log() của biến được khai báo bên trong hàm sẽ gây ra lỗi vì nó không được xác định.

Như đã đề cập, lý do tại sao websiteName không được xác định là vì các biến được tạo bên trong các hàm khi chúng được gọi và sau đó bị hủy khi chạy câu lệnh đầu cuối. Bất kỳ thứ gì bên ngoài hàm đều không có quyền truy cập vào nội dung bên trong hàm trừ khi nó có một thiết lập đặc biệt.

Phạm vi toàn cầu

Phạm vi tiếp theo này là một bản dịch theo nghĩa đen của cụm từ. Phạm vi toàn cục lấy các mục được khai báo bên ngoài một hàm và dự trữ chúng trong một không gian nơi tất cả các tập lệnh, phương thức và chức năng có thể truy cập và sử dụng chúng cho logic của chúng.

 
let counter = 0; // global -- declared outside function
 
const add = () => { // function declaration
   let counter = 0; // local -- declared inside function
   counter += 1; 
   // counter increased by 1 -- which counter variable increased?
   return counter;
}
 
add(); // invoke
add(); //  three
add(); //  times
console.log(counter) // is this 3 or 0? Why? 

Đoạn mã trên làm được gì nếu chúng ta console.log() quầy ở cuối mã? Bạn mong đợi điều gì sẽ xảy ra?

81% người tham gia cho biết họ cảm thấy tự tin hơn về triển vọng công việc công nghệ của mình sau khi tham gia chương trình đào tạo. Kết hợp với bootcamp ngay hôm nay.

Sinh viên tốt nghiệp bootcamp trung bình dành ít hơn sáu tháng để chuyển đổi nghề nghiệp, từ khi bắt đầu bootcamp đến khi tìm được công việc đầu tiên của họ.

Hãy xem qua mã:

  1. Biến bộ đếm được khai báo và khởi tạo trong môi trường toàn cầu.
  2. Thêm chức năng được khai báo trong môi trường toàn cục.
  3. Thêm được gọi.
  4. Biến bộ đếm được khai báo và khởi tạo trong môi trường cục bộ.
  5. Bộ đếm cục bộ tăng 1 ⇐ tại sao bộ đếm cục bộ chứ không phải toàn cầu?
  6. Bộ đếm được trả lại. Chức năng kết thúc.
  7. Thêm được gọi lại
  8. Thực hiện lại các bước từ 4 đến 6.
  9. Lặp lại các bước từ 3 đến 6 một lần nữa.
  10. console.log(counter); ⇐ Những gì được trả lại?

Bởi vì hàm kết thúc khi bộ đếm ở mức 1 mọi lúc, biến bộ đếm cục bộ của chúng ta được khai báo lại và khởi tạo lại ở 0 mỗi khi hàm chạy. Không có vấn đề gì xảy ra, bộ đếm sẽ luôn dừng ở 1 ở cấp địa phương.

Nếu một hàm tìm thấy một biến trong phạm vi của nó, nó sẽ không tìm đến phạm vi toàn cục cho biến đó - vì vậy biến toàn cục không bao giờ thay đổi. Vì vậy, console.log() của chúng tôi sẽ xuất ra 0 dưới dạng biến được xác định gần nhất của chúng ta trong môi trường của câu lệnh đó là trong môi trường toàn cầu.

Phạm vi từ vựng

Phạm vi từ vựng là một trong những khái niệm cơ bản nhất trong JavaScript. Ý tưởng là việc tạo ra một hàm hoặc một biến sẽ có thể truy cập được vào các phần nhất định của mã và sau đó không thể truy cập được đối với các phần khác của mã. Tất cả phụ thuộc vào vị trí khai báo của mỗi biến và hàm.

Hãy xem qua khối mã này:

const init = () => { // <== This is our outer function
 const var1 = 'Career'; // outer scope
 const second = () => { // <== This is our inner function
   const var2 = 'Karma'; // inner scope
   console.log(var1); // Career
   console.log(var2); // Karma
   return var1 + " " + var2;
 };
 
 // console.log(var2); // undefined
 
 
 return second();
};
init();
 

Ở đây chúng ta có một tập hợp các hàm lồng nhau. init() hàm khai báo một biến được gọi là var1, khai báo một hàm được gọi là thứ hai và gọi second() .

Khi trình biên dịch duyệt qua mã này lần đầu tiên, cần phải xem xét ở cấp độ cao những gì chúng ta có:

  1. init() chức năng
  2. gọi init()

Tại thời điểm này, chúng ta không thể thấy bất kỳ thứ gì khác bên trong hàm init () - chúng ta chỉ biết rằng hàm tồn tại. Khi hàm init () của chúng ta được gọi, trình biên dịch sẽ xem xét cấp độ cao khác về những gì bên trong hàm:

  1. var1
  2. second() chức năng
  3. gọi second()

init() hàm không biết gì về những gì đang diễn ra bên trong second() khối. Nó chỉ có thể nhìn thấy những gì trong môi trường từ vựng của nó - trạng thái xung quanh của nó.

Mỗi chức năng lồng nhau nằm trong một hộp chứa nhỏ hơn, giống như một bộ búp bê lồng bằng matryoshka của Nga (ví dụ:xem ở đầu trang nếu bạn không chắc chúng là gì). Những con búp bê chỉ biết về những gì đang diễn ra bên trong hộp đựng của chúng và những gì đã xảy ra hoặc đã được khai báo / đọc với bố mẹ. Ví dụ, con búp bê lớn nhất chỉ biết rằng con búp bê tiếp theo trong hộp đựng của nó tồn tại. Nó không biết về bất kỳ con búp bê nào khác trong bộ, chỉ biết điều gì trong môi trường từ vựng của nó (trạng thái của nó) và những gì đã xảy ra (phạm vi bên ngoài).

Về bản chất, chúng ta biết hai điều:

  1. Phạm vi bên ngoài không thể nhìn thấy phạm vi bên trong.
  2. Phạm vi bên trong có quyền truy cập vào phạm vi bên ngoài.

Bởi vì đối tượng bên ngoài không thể nhìn thấy những gì đang diễn ra trong phạm vi bên trong, chúng tôi có thể nói một cách an toàn rằng đây là mối quan hệ một chiều. Bên trong có thể nhìn thấy và sử dụng các biến từ phạm vi bên ngoài, nhưng bên ngoài không thể nhìn thấy bên trong. Đây được gọi là phạm vi từ vựng .

Cái hay của việc xác định phạm vi từ vựng là giá trị của một biến được xác định bởi vị trí của nó trong mã. Trước tiên, các hàm tìm kiếm ý nghĩa của một biến bên trong môi trường cục bộ của nó - nếu không thể tìm thấy, nó sẽ chuyển đến hàm đã xác định hàm đó. Nếu nó không thể tìm thấy nó ở đó, nó sẽ di chuyển chuỗi đến chức năng được xác định tiếp theo.

Điều này trở thành một khái niệm rất quan trọng trong JavaScript sẽ xuất hiện nhiều lần khi bạn tìm hiểu thêm về các khung JavaScript và cách chúng hoạt động. Bạn có thể đi xuống từ bên ngoài, nhưng bạn không bao giờ có thể “đi lên” theo hướng khác. Điều này rất quan trọng khi chúng ta đi đến chủ đề chính: kết thúc .

Đóng cửa

Định nghĩa của Closure rất giống với định nghĩa của phạm vi từ vựng. Sự khác biệt chính giữa hai hàm này là hàm đóng là một hàm bậc cao hơn và phạm vi từ vựng thì không. Một hàm bậc cao có một đặc điểm cơ bản:nó trả về một hàm hoặc sử dụng một hàm làm tham số.

Đóng là một hàm có thể truy cập phạm vi từ vựng của nó, ngay cả khi hàm đó đang được gọi sau đó.

Cả phạm vi đóng và phạm vi từ vựng đều có các biến riêng của chúng, có thể truy cập các biến và tham số của hàm mẹ và có thể sử dụng các biến toàn cục. Hãy xem qua đoạn mã sau:

function greeting() { //outer scope (parent function)
 const userName = "CrrKrma1952"; // parent variable
 function welcomeGreeting() { // inner function
   console.log("Hello, " + userName); // accesses parent var
   return "Hello, " + userName; // terminal statement
 }
 return welcomeGreeting; // returns a function (which makes it HOF)
} // end of greeting()
 
const greetUser = greeting(); //
greetUser(); //  Hello, CrrKrma1952
  1. greeting() chức năng tồn tại, nhưng chúng tôi chưa biết nội dung.
  2. greetUser tồn tại, nhưng chưa biết nội dung
  3. greetUser() - điều này sẽ gọi dòng trước đó, đến lượt nó, nó sẽ gọi hàm welcome ().
  4. userName được khai báo
  5. welcomeGreeting() tồn tại, nhưng chưa biết nội dung
  6. Câu lệnh trả lại bên dưới welcomeGreeting() khối trả về chính hàm đó
  7. console.log(‘Hello, ‘ + userName); Console.log của chúng tôi tại đây có thể truy cập phạm vi chính để nhận giá trị của userName
  8. Câu lệnh đầu cuối kết thúc hàm và hủy bỏ ý nghĩa của các biến bên trong khối mã.

Trong đoạn mã này, chúng ta đang truyền thông tin bằng cách lồng các hàm lại với nhau để có thể truy cập phạm vi chính sau này.



Kết luận

Trong bài viết này, chúng ta đã nói về một chủ đề JavaScript khá hấp dẫn:Phạm vi và Đóng. Tôi khuyên bạn nên phân nhánh và đọc một số bài báo khác nhau về chủ đề này. Cách dạy này có thể xuất phát từ nhiều quan điểm khác nhau - tất nhiên có nghĩa là có rất nhiều cách để học nó. Tôi hy vọng tài liệu này hữu ích cho bạn! Chúc may mắn tiếp tục nghiên cứu của bạn khi kết thúc!