Thấu hiểu các JavaScript Closure: Phương pháp tiếp cận thực tiễn

617

Học một ngôn ngữ mới yêu cầu đến một loạt các bước, để thành thạo cần có sự kiên nhẫn, thực hành, sai lầm và rút ra kinh nghiệm.

Một số developer sẽ có đủ kiến thức để cung cấp các tính năng theo nhu cầu của khách hàng, nhưng phải mất nhiều thời gian hơn để trở thành developer tốt.

Một developer tốt là người cần có những kiến thức nền tảng về ngôn ngữ

Hôm nay chúng ta hãy nhìn sâu vào JavaScript closure và hy vọng rằng kiến thức bạn học sẽ có lợi trong các dự án.

JavaScript closure là gì?

JavaScript Closure là khi một inner function có quyền truy cập tới các thành viên của outer function (lexical scope) ngay cả khi thực thi bên ngoài phạm vi của outer function.

Vì vậy, chúng tôi không thể đủ khả năng để nói về closure trong khi bỏ ra các functions và scope.

Scope trong JavaScript

Scope đề cập đến mức độ hiển thị của một biến được xác định trong một chương trình. Các cách để tạo ra scope trong JavaScript là thông qua: try-catch blocksfunctionslet keyword  với } trong số những thứ khác. Chúng tôi chủ yếu có hai biến thể: global scope và local scope.

var initialBalance = 0 // Global Scope

function deposit (amount) {
  /**
   * Local Scope
   * Code here has access to anything declared in the global scope
   */
  var newBalance = parseInt(initialBalance) + parseInt(amount)
  return newBalance
}

Mỗi function trong JavaScript tạo ra local scope riêng của nó khi được khai báo.

Điều này có nghĩa là bất cứ điều gì được khai báo bên trong local scope của function thì không thể truy cập từ bên ngoài. Xem xét minh hoạ dưới đây:

var initialBalance = 300 // Variable declared in the Global Scope

function withdraw (amount) {
  var balance // Variable declared in function scope

  balance = parseInt(initialBalance) - parseInt(amount)
  return balance
}
console.log(initialBalance) // Will output initialBalance value as it is declared in the global scope
console.log(balance) // ReferenceError: Can't find variable: balance

Lexical Scope

JavaScript Lexical Scope được xác định trong giai đoạn biên soạn. Nó xác định scope của một biến để nó chỉ có thể được gọi / tham khảo từ bên trong khối mã mà nó được định nghĩa.

Một function được khai báo bên trong một function block xung quanh có quyền truy cập vào các biến trong lexical scope của function xung quanh.

var initialBalance = 300 // Global Scope

function withdraw (amount) {
  /**
   * Local Scope
   * Code here has access to anything declared in the global scope
   */
  var balance = parseInt(initialBalance) - parseInt(amount)

  const actualBalance = (function () {
    const TRANSACTIONCOST = 35
    return balance - TRANSACTIONCOST /**
     * Accesses balance variable from the lexical scope
     */
  })() // Immediately Invoked Function expression. IIFE

  // console.log(TRANSACTIONCOST) // ReferenceError: Can't find variable: TRANSACTIONCOST
  return actualBalance
}

Gọi một inner function bên ngoài enclosing function của nó và vẫn duy trì quyền truy cập vào các biến trong enclosing function (lexical scope) tạo ra một JavaScript Closure.

function person () {
  var name = 'Paul'  // Local variable

  var actions = {
    speak: function () {
    //  new function scope
      console.log('My name is ', name) /**
      * Accessing the name variable from the outer function scope (lexical scope)
      */
    }
  } // actions object with a function

  return actions /**
  * We return the actions object
  * We then can invoke the speak function outside this scope
  */
}

person().speak() // Inner function invoked outside its lexical Scope

Closure cho phép sử dụng một giao diện cộng đồng trong khi cùng một lúc ẩn và bảo vệ các xâm phạm từ phạm vi bên ngoài.

Một số mẫu thiết kế JavaScript sử dụng closure.

Module Pattern

Một trong những mô hình được triển khai tốt này là module pattern, mô hình này cho phép bạn mô phỏng: private, public và privileged member.

var Module = (function () {
  var foo = 'foo' // Private Property

  function addToFoo (bam) { // Private Method
    foo = bam
    return foo
  }

  var publicInterface = {
    bar: function () { // Public Method
      return 'bar'
    },
    bam: function () { // Public Method
      return addToFoo('bam') // Invoking the private method
    }
  }

  return publicInterface // Object will contain public methods
})()

Module.bar() // bar
Module.bam() // bam

Từ module pattern mô tả ở trên, chỉ các phương pháp công khai và thuộc tính trong đối tượng trả về sẽ có sẵn bên ngoài ngữ cảnh thực thi của closure.

Tất cả các thành viên private sẽ vẫn tồn tại khi bối cảnh thực hiện của họ được bảo vệ nhưng bị che giấu khỏi outside scope.

Thêm ví dụ về Closures

Khi chúng ta vượt qua một function trong setTimeout hoặc bất kỳ kiểu gọi lại nào. Function vẫn còn nhớ lexical scope vì closure.

When we pass a function into a setTimeout or any kind of callback. The function still remembers the lexical scope because of the closure.function foo () {
  var bar = 'bar'
  setTimeout(function () {
    console.log(bar)
  }, 1000)
}

foo() // bar

Closure và loop

for (var i = 1; i <= 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i)
}
/**
* Prints 1 thorugh 5 after each second
* Closure enables us to remember the variable i
* An IIFE to pass in a new value of the variable i for each iteration
* IIFE (Immediately Invoked Function expression)
*/
for (let i = 1; i <= 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i)
}
/**
* Prints 1 through 5 after each second
* Closure enabling us to remember the variable i
* The let keyword rebinds the value of i for each iteration
*/

Tôi tin rằng bây giờ chúng ta có một sự hiểu biết về closure và có thể làm như sau:

  • Minh hoạ các trường hợp sử dụng của nó hoặc xác định nó trong ngữ cảnh chúng ta không bao giờ biết
  • Giữ bối cảnh thực hiện như dự đoán
  • Triển khai code trong module pattern của JavaScript
  • Sử dụng closure trong code của chúng tôi, với sự hiểu biết rõ ràng

TopDev via Scotch

Báo cáo bài viết vi phạm bản quyền>>