Phạm vi xác định thời gian tồn tại và khả năng hiển thị của một biến. Các biến không thể nhìn thấy bên ngoài phạm vi mà chúng được khai báo.
JavaScript có phạm vi mô-đun, phạm vi chức năng, phạm vi khối, phạm vi từ vựng và phạm vi toàn cầu.
Phạm vi toàn cầu
Các biến được xác định bên ngoài bất kỳ phạm vi chức năng, khối hoặc mô-đun nào đều có phạm vi toàn cầu. Các biến trong phạm vi toàn cầu có thể được truy cập từ mọi nơi trong ứng dụng.
Khi một hệ thống mô-đun được kích hoạt, việc tạo các biến toàn cục sẽ khó hơn, nhưng người ta vẫn có thể làm được. Bằng cách xác định một biến trong HTML, bên ngoài bất kỳ chức năng nào, một biến toàn cục có thể được tạo:
<script>
let GLOBAL_DATA = { value : 1};
</script>
console.log(GLOBAL_DATA);
Khi không có hệ thống mô-đun, việc tạo các biến toàn cục sẽ dễ dàng hơn rất nhiều. Một biến được khai báo bên ngoài bất kỳ hàm nào, trong bất kỳ tệp nào, là một biến toàn cục.
Các biến toàn cầu có sẵn trong suốt vòng đời của ứng dụng.
Một cách khác để tạo biến toàn cục là sử dụng window
đối tượng toàn cầu ở bất cứ đâu trong ứng dụng:
window.GLOBAL_DATA = { value: 1 };
Tại thời điểm này, các GLOBAL_DATA
biến có thể nhìn thấy ở mọi nơi.
console.log(GLOBAL_DATA)
Như bạn có thể tưởng tượng những thực hành này là thực hành xấu.
phạm vi mô-đun
Trước các mô-đun, một biến được khai báo bên ngoài bất kỳ hàm nào là biến toàn cục. Trong các mô-đun, một biến được khai báo bên ngoài bất kỳ chức năng nào sẽ bị ẩn và không khả dụng đối với các mô-đun khác trừ khi nó được xuất rõ ràng.
Việc xuất cung cấp một chức năng hoặc đối tượng cho các mô-đun khác. Trong ví dụ tiếp theo, tôi xuất một hàm từ sequence.js
tập tin mô-đun:
// in sequence.js
export { sequence, toList, take };
Nhập làm cho một chức năng hoặc đối tượng, từ các mô-đun khác, có sẵn cho mô-đun hiện tại.
import { sequence, toList, toList } from "./sequence";
Theo một cách nào đó, chúng ta có thể hình dung một mô-đun như một chức năng tự thực thi lấy dữ liệu nhập làm đầu vào và trả về dữ liệu xuất.
Phạm vi chức năng
Phạm vi chức năng có nghĩa là các tham số và biến được xác định trong một hàm có thể nhìn thấy ở mọi nơi trong hàm nhưng không nhìn thấy bên ngoài hàm.
Hãy xem xét chức năng tiếp theo tự động thực hiện, được gọi là IIFE.
(function autoexecute() {
let x = 1;
})();
console.log(x);
//Uncaught ReferenceError: x is not defined
IIFE là viết tắt của Biểu thức hàm được gọi ngay lập tức và là một hàm chạy ngay sau định nghĩa của nó.
Các biến được khai báo với var
chỉ có phạm vi chức năng. Hơn nữa, các biến được khai báo với var
được nâng lên đầu phạm vi của chúng. Bằng cách này, chúng có thể được truy cập trước khi được khai báo. Hãy xem đoạn mã dưới đây:
function doSomething(){
console.log(x);
var x = 1;
}
doSomething(); //undefined
Điều này không xảy ra đối với let
. Một biến được khai báo với let
có thể được truy cập chỉ sau định nghĩa của nó.
function doSomething(){
console.log(x);
let x = 1;
}
doSomething();
//Uncaught ReferenceError: x is not defined
Một biến được khai báo với var
có thể được khai báo lại nhiều lần trong cùng một phạm vi. Mã sau đây là tốt:
function doSomething(){
var x = 1
var x = 2;
console.log(x);
}
doSomething();
Các biến được khai báo với let
hoặc const
không thể được khai báo lại trong cùng một phạm vi:
function doSomething(){
let x = 1
let x = 2;
}
//Uncaught SyntaxError: Identifier 'x' has already been declared
Có lẽ chúng ta thậm chí không phải quan tâm đến điều này, vì var
đã bắt đầu trở nên lỗi thời.
Phạm vi chặn
Phạm vi khối được xác định bằng dấu ngoặc nhọn. Nó được ngăn cách bởi {
và }
.
Các biến được khai báo với let
và const
có thể có phạm vi khối. Chúng chỉ có thể được truy cập trong khối mà chúng được xác định.
Xem xét đoạn mã tiếp theo nhấn mạnh let
phạm vi khối:
let x = 1;
{
let x = 2;
}
console.log(x); //1
Ngược lại, các var
khai báo không có phạm vi khối:
var x = 1;
{
var x = 2;
}
console.log(x); //2
Một vấn đề phổ biến khác khi không có phạm vi khối là việc sử dụng thao tác không đồng bộ như setTimeout()
trong một vòng lặp. Mã vòng lặp chảy hiển thị số 5, năm lần.
(function run(){
for(var i=0; i<5; i++){
setTimeout(function logValue(){
console.log(i); //5
}, 100);
}
})();
Các for
câu lệnh lặp, với let
khai báo, tạo một ngôn ngữ biến mới cho phạm vi khối, cho mỗi lần lặp lại. Mã vòng lặp tiếp theo hiển thị 0 1 2 3 4 5
.
(function run(){
for(let i=0; i<5; i++){
setTimeout(function log(){
console.log(i); //0 1 2 3 4
}, 100);
}
})();
Phạm vi từ vựng
Phạm vi từ vựng là khả năng của hàm bên trong truy cập vào phạm vi bên ngoài mà nó được định nghĩa.
Hãy xem xét mã tiếp theo:
(function autorun(){
let x = 1;
function log(){
console.log(x);
};
function run(fn){
let x = 100;
fn();
}
run(log);//1
})();
Các log
chức năng là một đóng cửa. Nó đề cập đến x
biến từ hàm cha của nó autorun()
không phải là một từ run()
chức năng.
Hàm đóng có quyền truy cập vào phạm vi mà nó được tạo, không phải phạm vi mà nó được thực thi.
Phạm vi chức năng cục bộ của autorun()
là phạm vi từ vựng của log()
chức năng.
Chuỗi phạm vi
Mỗi phạm vi có một liên kết đến phạm vi cha mẹ. Khi một biến được sử dụng, JavaScript sẽ xem xét chuỗi phạm vi cho đến khi nó tìm thấy biến được yêu cầu hoặc cho đến khi nó đạt đến phạm vi toàn cầu, đó là phần cuối của chuỗi phạm vi.
Nhìn vào ví dụ tiếp theo:
let x0 = 0;
(function autorun1(){
let x1 = 1;
(function autorun2(){
let x2 = 2;
(function autorun3(){
let x3 = 3;
console.log(x0 + " " + x1 + " " + x2 + " " + x3);//0 1 2 3
})();
})();
})();
Các autorun3()
chức năng bên trong có quyền truy cập vào địa phương x3
Biến đổi. Nó cũng có quyền truy cập vào x1
và x2
các biến từ các chức năng bên ngoài và x0
biến toàn cục.
Nếu nó không tìm thấy biến, nó sẽ trả về lỗi ở chế độ nghiêm ngặt.
"use strict";
x = 1;
console.log(x)
//Uncaught ReferenceError: x is not defined
Ở chế độ không nghiêm ngặt, được gọi là “chế độ cẩu thả”, nó sẽ làm một điều tồi tệ và tạo ra một biến toàn cục.
x = 1;
console.log(x); //1
Phần kết luận
Các biến được xác định trong phạm vi toàn cầu có sẵn ở mọi nơi trong ứng dụng.
Trong một mô-đun, một biến được khai báo bên ngoài bất kỳ chức năng nào sẽ bị ẩn và không khả dụng đối với các mô-đun khác trừ khi nó được xuất rõ ràng.
Phạm vi hàm có nghĩa là các tham số và biến được xác định trong hàm hiển thị ở mọi nơi trong hàm
Các biến được khai báo với let
và const
có phạm vi khối. var
không có phạm vi khối.
Khám phá JavaScript chức năng được đặt tên là một trong những sách Lập trình hàm mới hay nhất của BookAuthority!
Để biết thêm về cách áp dụng các kỹ thuật lập trình chức năng trong React, hãy xem Phản ứng chức năng.
Học hỏi phản ứng chức năngtheo cách dựa trên dự án, với Kiến trúc chức năng với React và Redux.
Theo dõi trên Twitter