Scope và Closure là các khái niệm rất cơ bản và quan trọng mà một Javascript developer nên biết và hiểu rõ, vì chỉ có như vậy chúng ta mới có thể tránh được một số lỗi thường gặp và đồng thời giúp ta bước thêm một bước trên con đường trở thành master Javascipt.
Bài viết gồm các mục như sau:
Ví dụ
Ta có thể thấy,
Ta có thể thấy, trong đoạn code trên,
Như ta thấy, khi hàm
Biến outer trỏ đến 1 hàm mà nó luôn biết rằng có giá trị 5 đã được truyền vào. Ta có thể tưởng tượng
Cuối cùng, khi ta gọi outer và truyền vào cho nó giá trị 10, thì nó sẽ cộng thêm 5 vào và trả về kết quả là 15
Kết luận, closure là việc inner function có thể access 1 local variable của outer function khi outer function đã return.
Nội dung của ví dụ này như sau:
Bạn muốn tạo ra 5 link từ tag
Ta hiện thực như sau:
Khi chạy đoạn code trên ta thấy trên màn hình có 5 tag a với giá trị là
Để giải thích cho hiện tượng này, ta cần chú ý đến scope của vòng lặp for và của hàm
Để khắc phục hiện tượng này ta thực hiện như sau:
Nếu các bạn thấy bài viết có ích hãy chia sẻ cho mọi người cùng biết. Nếu có ý kiến đóng góp, đừng ngần ngại để lại comment bên dưới nhé. Xin cảm ơn!
Bài viết gồm các mục như sau:
- Scope in JS
- Closure in JS
- The Infamous Loop Problem
1. Scope in JS
Khái niệm Scope
Trong Javascript, Scope có thể hiểu như là một nơi mà các variable và function có thể truy cập và sử dụng được thông qua tên trực tiếp. Về căn bản, các variable và function có thể được định nghĩa ở local scope và global scopeGlobal scope
Là scope mà bất cứ biến và hàm nào được định nghĩa trong nó đều có thể access được ở bất kì nơi nào.Ví dụ
var globalVar = 1234;
globalFunc() {
console.log(globalVar)
return "This is global function"
}
globalVar
là biến global (global variable), và globalFunc
là hàm global (global function). Chúng ta có thể access globalVar
từ bất kì đâu, kể cả bên trong globalFunc
Local scope
Ngược lại với global scope, local scope là khi một biến hoặc hàm được định nghĩa và access được bên trong 1 phần nào đó của code, ví dụ trong thân của 1 function chẳng hạnvar globalVar = 1234
globalFunc() {
var localVariable = "this is local variable"
console.log(globalVar)
console.log(localVariable) // 1
return "This is global function"
}
console.log(localVariable) // 2
Ta có thể thấy, trong đoạn code trên,
localVariable
được định nghĩa bên trong thân hàm globalFunc
nên nó là biến local, nó chỉ có thể được access bên trong scope của nó ở console.log số 1. Ta không thể access ở ngoài scope của biến được. console.log số 2 sẽ bị lỗi2. Closure
Để hiểu được khái niệm closure, trước tiên ta xét đến ví dụ saufunction outerFunc (x) { function innerFunc (y) { return x + y } return innerFunc }
var outer = outerFunc(5) // (1) console.log(outer(10)) // Display 15 in console
outerFunc
được gọi, nó trả về 1 hàm, sau đó outerFunc
sẽ close context hiện tại của nó lại là nhớ giá trị 5 được truyền vào.Biến outer trỏ đến 1 hàm mà nó luôn biết rằng có giá trị 5 đã được truyền vào. Ta có thể tưởng tượng
outer
như sau// This is outer
function outer (y) { return 5 + y }
Kết luận, closure là việc inner function có thể access 1 local variable của outer function khi outer function đã return.
3. The Infamous Loop Problem
Closure là một khái niệm dễ gây nhầm lẫn và khó nắm rõ đối với người mới tìm hiểu về JS, và đây là một trong những ví dụ điển hình để minh họa cho sự nhầm lẫn này.Nội dung của ví dụ này như sau:
Bạn muốn tạo ra 5 link từ tag
<a>
, innerHTML của tag a đó chính là giá trị i và khi click vào link sẽ hiện alert với giá trị i tương ứng của link đó.<a>Link 0 </a>
<a>Link 1 </a>
<a>Link 2 </a>
<a>Link 3 </a>
<a>Link 4 </a>
function addLinks () {
for (var i = 0, link; i < 5; i++) {
link = document.createElement('a')
link.innerHTML = "Link" + i
link.onclick = function () {
alert(i)
}
document.body.appendChild(link);
}
}
Link0 Link1 Link2 Link3 Link4
Tuy nhiên khi click vào bất kì tag a nào đều alert giá trị là 5 chứ ko phải giá trị i tương ứng.Để giải thích cho hiện tượng này, ta cần chú ý đến scope của vòng lặp for và của hàm
addLinks
. Biến i được gán vào hàm onclick là biến i của hàm addLinks
. Và tại thời điểm ta click vào bất kì link nào trên browser thì lúc đó vòng lặp for đã thực hiện xong, giá trị của i lúc đó là 5 rồi, nên khi đó lúc nào alert cũng hiện ra là 5.Để khắc phục hiện tượng này ta thực hiện như sau:
function addLinks () {
var click = function(i) {
return function() {
alert(i)
}
}
for (var i = 0, link; i < 5; i++) {
link = document.createElement('a')
link.innerHTML = "Link" + i
link.onclick = click(i)
document.body.appendChild(link);
}
}
Kết
Hi vọng qua bài viết này sẽ giúp các bạn có cái nhìn rõ ràng hơn về hai khái niệm scope và closure trong Javascript, qua đó có thể ứng dụng vào trong công việc hàng ngày.Nếu các bạn thấy bài viết có ích hãy chia sẻ cho mọi người cùng biết. Nếu có ý kiến đóng góp, đừng ngần ngại để lại comment bên dưới nhé. Xin cảm ơn!
Reference
Advertisement