JavaScript là một ngôn ngữ đơn luồng, nghĩa là mỗi lần chỉ có thể thực thi một tác vụ. Khi trình thông dịch JavaScript ban đầu thực thi mã, trước tiên, nó sẽ đi vào ngữ cảnh thực thi chung theo mặc định. Mỗi lần gọi hàm từ thời điểm này trở đi sẽ dẫn đến việc tạo ngữ cảnh thực thi mới
Đây là nơi mà sự nhầm lẫn thường xảy ra, bối cảnh thực thi thuật ngữ thực sự dành cho tất cả các ý định và mục đích đề cập nhiều hơn đến phạm vi chứ không phải bối cảnh. Đó là một quy ước đặt tên đáng tiếc, tuy nhiên, đó là thuật ngữ được định nghĩa bởi đặc tả ECMAScript, vì vậy chúng tôi hơi khó hiểu với nó
Mỗi khi một bối cảnh thực thi mới được tạo, nó sẽ được thêm vào đầu ngăn xếp thực thi. Trình duyệt sẽ luôn thực thi ngữ cảnh thực thi hiện tại nằm trên ngăn xếp thực thi. Sau khi hoàn thành, nó sẽ bị xóa khỏi đỉnh ngăn xếp và điều khiển sẽ quay trở lại ngữ cảnh thực thi bên dưới
Bối cảnh thực thi có thể được chia thành giai đoạn tạo và thực thi. Trong giai đoạn tạo, trước tiên trình thông dịch sẽ tạo một đối tượng biến [còn được gọi là đối tượng kích hoạt] bao gồm tất cả các biến, khai báo hàm và đối số được xác định bên trong ngữ cảnh thực thi. Từ đó, chuỗi phạm vi được khởi tạo tiếp theo và giá trị của chuỗi này được xác định cuối cùng. Sau đó, trong giai đoạn thực thi, mã được diễn giải và thực thi
2. bối cảnh này
Bối cảnh “này” là gì? . Khi một hàm được gọi là một phương thức của một đối tượng, điều này được đặt thành đối tượng mà phương thức đó được gọi
var obj = {
foo: function[] {
return this;
}
};
obj.foo[] === obj; // true
Nguyên tắc tương tự cũng được áp dụng khi gọi một hàm với toán tử new để tạo một thể hiện của một đối tượng. Khi được gọi theo cách này, giá trị của this trong phạm vi của hàm sẽ được đặt thành phiên bản mới được tạo
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
Khi được gọi là chức năng không liên kết, chức năng này sẽ mặc định là đối tượng cửa sổ hoặc ngữ cảnh chung trong trình duyệt. Tuy nhiên, nếu chức năng được thực thi ở chế độ nghiêm ngặt, ngữ cảnh sẽ mặc định là không xác định
3. Phạm vi biến đổi
Một biến có thể được xác định trong phạm vi cục bộ hoặc toàn cầu, thiết lập khả năng truy cập của biến từ các phạm vi khác nhau trong thời gian chạy. Bất kỳ biến toàn cục được xác định nào, nghĩa là bất kỳ biến nào được khai báo bên ngoài thân hàm sẽ tồn tại trong suốt thời gian chạy và có thể được truy cập và thay đổi trong bất kỳ phạm vi nào. Các biến cục bộ chỉ tồn tại trong thân hàm mà chúng được xác định và sẽ có phạm vi khác nhau cho mỗi lần gọi hàm đó. Ở đó, nó chỉ có thể gán giá trị, truy xuất và thao tác trong cuộc gọi đó và không thể truy cập được bên ngoài phạm vi đó
ECMAScript 6 [ES6/ES2015] đã giới thiệu từ khóa let và const hỗ trợ khai báo biến cục bộ phạm vi khối. Điều này có nghĩa là biến sẽ bị giới hạn trong phạm vi của một khối mà nó được xác định trong đó, chẳng hạn như câu lệnh if hoặc vòng lặp for và sẽ không thể truy cập được bên ngoài dấu ngoặc nhọn mở và đóng của khối. Điều này trái ngược với các khai báo var có thể truy cập được bên ngoài các khối mà chúng được xác định trong. Sự khác biệt giữa let và const là khai báo const, đúng như tên gọi của nó, là hằng số - một tham chiếu chỉ đọc đến một giá trị. Điều này không có nghĩa là giá trị là bất biến, chỉ là không thể gán lại định danh biến
Trong JavaScript, bạn viết một số mã và nó được giải thích bởi công cụ JavaScript. Để hiểu những gì xảy ra đằng sau hậu trường, bạn cần có hiểu biết về những điều cơ bản. Trong bài viết này, chúng tôi sẽ tập trung vào sự khác biệt giữa phạm vi, bối cảnh và bối cảnh thực thi
Phạm vi
Vì bài viết này là một phần của loạt bài Tìm hiểu các nguyên tắc cơ bản về JavaScript, hãy xem phần còn lại của loạt bài này qua các liên kết ở cuối bài viết nếu bạn muốn tìm hiểu thêm về các loại phạm vi hoặc cách bạn có thể sử dụng nó
Đối với một lời giải thích ngắn gọn, phạm vi có liên quan chặt chẽ đến khả năng hiển thị của các biến. Phạm vi và bối cảnh thường bị nhầm lẫn, nhưng trên thực tế chúng hoàn toàn khác nhau. Với phạm vi, bạn kiểm soát khả năng truy cập của các biến của mình. Các biến được tạo trong phạm vi toàn cầu có thể được truy cập từ bất kỳ phạm vi nào trong khi các biến cục bộ có thể truy cập được trong hàm mà chúng được tạo
Bối cảnhNgữ cảnh đơn giản là giá trị của “
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5”, thuộc tính của ngữ cảnh thực thi sẽ được giải thích sau trong bài viết này. Nó cũng đề cập đến đối tượng mà hàm/phương thức thuộc vềGiá trị của
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 khác nhau tùy theo cách gọi hàm. Trong phạm vi toàn cầu, giá trị của function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 luôn là đối tượng cửa sổconsole.log[this]; // window
Nếu hàm là một phương thức, giá trị của
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 là đối tượng mà phương thức đó thuộc về. Tất nhiên, từ khóa function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 không đơn giản để hiểu. Trong bài viết này, tôi không đi sâu vào chi tiết cách thức hoạt động của từ khóa function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5, mà chỉ nhấn mạnh mối quan hệ của nó với phạm vi, bối cảnh, bối cảnh thực thi. Hiểu cách hoạt động của function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 là một trong những chủ đề khó nhất và cũng quan trọng nhất trong JavaScript. May mắn thay, có rất nhiều tài nguyên. Nếu bạn không quen thuộc, tôi khuyên bạn nên kiểm tra chúng- MDN
- Javascript. thông tin
- Làm chủ JavaScript Từ khóa này
Ý nghĩa của từ khóa
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 phụ thuộc vào cách thức và vị trí hàm được gọi chứ không phải nơi nó được khai báo. Ý nghĩa của nó thay đổi mỗi khi một hàm được gọi từ ngữ cảnh thực thi khác nhau. Tại sao bối cảnh thực hiện? Bối cảnh thực hiệnBối cảnh thực thi là thứ mà bạn cần biết để hiểu cách mã JavaScript chạy. Trước hết, nó là một khái niệm trừu tượng đại diện cho môi trường mà JavaScript chạy trong đó. Điều xảy ra bên trong bối cảnh thực thi về cơ bản là hai điều. Đầu tiên là phân tích cú pháp từng dòng mã và thứ hai là lưu trữ các biến và hàm vào bộ nhớ. Nói một cách đơn giản, nó có hai loại
- Bối cảnh thực thi toàn cầu
- Bối cảnh thực thi cục bộ
Bối cảnh thực thi toàn cầu là thứ đầu tiên được tạo khi bạn viết mã JavaScript. Đó là bối cảnh mặc định
Bối cảnh thực thi cục bộ được tạo khi bạn gọi một hàm [không xác định hàm]
Bởi vì nó là một khái niệm trừu tượng, tôi sẽ hỗ trợ nó bằng một hình ảnh
Hãy xem qua hình ảnh. Khi công cụ JS bắt đầu đọc mã của bạn, nó sẽ tạo bối cảnh thực thi toàn cầu. Nó bắt đầu phân tích từng dòng một và thêm các biến của bạn vào bộ nhớ còn được gọi là môi trường biến toàn cục
Giả sử bạn đã định nghĩa một hàm như thế này
function adding[num] {
let number=num+2;
return number;
}
Nếu bạn gọi hàm
adding[3];
Trong khi công cụ đang phân tích cú pháp, nếu nó cần thực thi chức năng, ngữ cảnh thực thi cục bộ mới sẽ được tạo. Trong ngữ cảnh thực thi đó, quá trình phân tích cú pháp diễn ra và biến
function adding[num] {
let number=num+2;
return number;
}
2 được thêm vào bộ nhớ cục bộ, sau đó quá trình phân tích cú pháp tiếp tục. Sau đó, công cụ trở lại bối cảnh thực thi trước đóThoát khỏi bối cảnh thực thi cục bộ và tiếp tục phân tích cú pháp trong bối cảnh thực thi trước đó đạt được bằng từ khóa
function adding[num] {
let number=num+2;
return number;
}
3. Những mũi tên trong hình đại diện cho chu kỳ này. Mỗi khi một hàm được gọi, điều này lại xảy ra. Mỗi lệnh gọi hàm dẫn đến một bối cảnh thực thi cục bộ khác nhauTong hop mot thoi gian ngan
- Bối cảnh thực thi toàn cầu được tạo trước
- Bất cứ khi nào một chức năng được gọi, được gọi hoặc được thực thi, một ngữ cảnh thực thi cục bộ mới sẽ được tạo
- Công cụ JavaScript bắt đầu phân tích cú pháp mã trong bối cảnh thực thi toàn cầu
- Khi công cụ bắt gặp một lệnh gọi hàm, nó sẽ đi vào ngữ cảnh thực thi cục bộ và tiếp tục phân tích cú pháp trong đó
- Khi nó xử lý việc thực thi chức năng, nó sẽ thoát khỏi bối cảnh thực thi cục bộ đó, trở về bối cảnh trước đó
Điều này đưa chúng ta đến một khái niệm quan trọng khác. Làm cách nào để công cụ biết bối cảnh thực thi nào sẽ vào hoặc thoát?
Ngăn xếp cuộc gọi là một cơ chế để Công cụ JavaScript theo dõi các bối cảnh thực thi, bối cảnh nào sẽ vào, bối cảnh nào sẽ thoát hoặc quay lại. Ở dưới cùng của ngăn xếp là bối cảnh thực thi toàn cầu. Nếu một hàm được gọi, chúng ta có ngữ cảnh thực thi cục bộ mới và ngữ cảnh này được đẩy lên đầu ngăn xếp cuộc gọi. Sau khi hoàn thành, nó sẽ bật ra. Hãy để tôi giải thích nó với một hình ảnh
Chuyện gì đang xảy ra ở đây vậy?
- Công cụ bắt đầu phân tích cú pháp, bối cảnh thực thi toàn cầu sẽ tự động được đẩy vào ngăn xếp cuộc gọi
function adding[num] {
4 được gọi, bối cảnh thực thi cục bộ được đẩy lên đầu bối cảnh thực thi toàn cầu. Công cụ sẽ tiếp tục phân tích cú pháp sau khi
let number=num+2;
return number;
}function adding[num] {
4 được thực thi
let number=num+2;
return number;
}- Bên trong
function adding[num] {
4, ngữ cảnh thực thi mới được tạo và được đẩy lên đầu ngăn xếp cuộc gọi. Sau khi
let number=num+2;
return number;
}function adding[num] {
7 được thực thi, nó sẽ bật ra khỏi ngăn xếp cuộc gọi
let number=num+2;
return number;
} function adding[num] {
4 được bật ra sau khi thực hiện xong
let number=num+2;
return number;
}- Cuối cùng, nó trở lại bối cảnh thực thi toàn cầu. Công cụ tiếp tục phân tích cú pháp và tất cả mã được thực thi
Trong suốt bài viết, bạn có thể tự hỏi làm thế nào ngữ cảnh thực thi được tạo ra. Mặc dù trừu tượng nhưng nó là một quy trình và động cơ tuân theo một số bước trong quy trình
Về cơ bản nó có hai giai đoạn
- Giai đoạn sáng tạo
- Giai đoạn thực hiện
Trong giai đoạn tạo, trước tiên công cụ tạo đối tượng Kích hoạt hoặc đối tượng Biến. Đối tượng này bao gồm các biến, đối số, khai báo hàm. Trong giai đoạn này, chúng được gán giá trị là
function adding[num] {
let number=num+2;
return number;
}
9Thuộc tính đối số cũng là một đối tượng [một đối tượng giống như mảng] có thuộc tính độ dài và tất cả các đối số được truyền cho lệnh gọi hàm được lưu trữ trong đối tượng này
Sau đó, công cụ tạo chuỗi phạm vi. Mỗi bối cảnh thực thi biết phạm vi của nó. Nó có một tham chiếu đến phạm vi bên ngoài của nó cho đến phạm vi toàn cầu và công cụ tìm kiếm các biến [nếu tồn tại hoặc không] bắt đầu từ phạm vi hiện tại đến phạm vi toàn cầu. Và đây được gọi là chuỗi phạm vi. Chuỗi phạm vi là một danh sách các đối tượng bao gồm đối tượng biến của chính nó và đối tượng biến của cha mẹ nó
Cuối cùng, giá trị của
function foo[] {
alert[this];
}
foo[] // window
new foo[] // foo
5 được xác định. Trong bối cảnh toàn cầu, giá trị của nó là đối tượng adding[3];
1/adding[3];
2 trong khi ở mọi lệnh gọi hàm, giá trị của nó có thể khácTrong giai đoạn thực thi, các biến được gán một giá trị và công cụ thực thi mã
Nếu bạn muốn đọc thêm về Nguyên tắc cơ bản về JavaScript, vui lòng xem Chuỗi Tìm hiểu về nguyên tắc cơ bản của JavaScript