Các hàm JavaScript được sử dụng để thực hiện các thao tác. Chúng ta có thể gọi hàm JavaScript nhiều lần để sử dụng lại mã
Lợi thế của chức năng JavaScript
Có hai ưu điểm chính của các hàm JavaScript
- khả năng tái sử dụng mã. Chúng ta có thể gọi một chức năng nhiều lần để nó tiết kiệm mã hóa
- Ít mã hóa hơn. Nó làm cho chương trình của chúng tôi nhỏ gọn. Chúng ta không cần phải viết nhiều dòng mã mỗi lần để thực hiện một tác vụ chung
Cú pháp hàm JavaScript
Cú pháp khai báo hàm được đưa ra dưới đây
Hàm JavaScript có thể có 0 hoặc nhiều đối số
Ví dụ hàm JavaScript
Hãy xem ví dụ đơn giản về hàm trong JavaScript không có đối số
Kiểm tra nó ngay bây giờĐầu ra của ví dụ trên
Đối số chức năng JavaScript
Chúng ta có thể gọi hàm bằng cách truyền đối số. Hãy xem ví dụ về hàm có một đối số
Kiểm tra nó ngay bây giờĐầu ra của ví dụ trên
Hàm có giá trị trả về
Chúng ta có thể gọi hàm trả về một giá trị và sử dụng nó trong chương trình của mình. Hãy xem ví dụ về hàm trả về giá trị
Kiểm tra nó ngay bây giờĐầu ra của ví dụ trên
Đối tượng hàm JavaScript
Trong JavaScript, mục đích của hàm tạo Hàm là tạo một đối tượng Hàm mới. Nó thực thi mã trên toàn cầu. Tuy nhiên, nếu chúng ta gọi trực tiếp hàm tạo, hàm sẽ được tạo động nhưng theo cách không an toàn
Mọi người nghĩ rằng khoa học máy tính là nghệ thuật của những thiên tài nhưng thực tế thì ngược lại, chỉ là nhiều người làm những việc xây dựng lên nhau, giống như một bức tường đá nhỏ
Donald KnuthHàm là cốt lõi của lập trình JavaScript. Khái niệm gói một đoạn chương trình trong một giá trị có nhiều công dụng. Nó cho chúng ta một cách để cấu trúc các chương trình lớn hơn, giảm sự lặp lại, liên kết tên với các chương trình con và cách ly các chương trình con này với nhau.
Ứng dụng rõ ràng nhất của các chức năng là xác định từ vựng mới. Tạo từ mới trong văn xuôi thường là phong cách xấu. Nhưng trong lập trình thì không thể thiếu
Những người nói tiếng Anh trưởng thành điển hình có khoảng 20.000 từ trong vốn từ vựng của họ. Rất ít ngôn ngữ lập trình đi kèm với 20.000 lệnh được tích hợp sẵn. Và từ vựng có sẵn có xu hướng được định nghĩa chính xác hơn, và do đó kém linh hoạt hơn so với ngôn ngữ của con người. Do đó, chúng tôi thường phải giới thiệu các khái niệm mới để tránh lặp lại chính mình quá nhiều
Định nghĩa một hàm
Định nghĩa hàm là một liên kết thông thường trong đó giá trị của liên kết là một hàm. Ví dụ: mã này định nghĩa
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 101 để chỉ một hàm tạo bình phương của một số đã cho
const square = function[x] { return x * x; }; console.log[square[12]]; // → 144
Một hàm được tạo với một biểu thức bắt đầu bằng từ khóa
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 102. Các hàm có một tập hợp các tham số [trong trường hợp này, chỉ có
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 103] và một phần thân chứa các câu lệnh sẽ được thực thi khi hàm được gọi. Thân hàm của một hàm được tạo theo cách này phải luôn được đặt trong dấu ngoặc nhọn, ngay cả khi nó chỉ bao gồm một câu lệnh
Một hàm có thể có nhiều tham số hoặc không có tham số nào cả. Trong ví dụ sau,
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 104 không liệt kê bất kỳ tên tham số nào, trong khi
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 105 liệt kê hai
const makeNoise = function[] { console.log["Pling!"]; }; makeNoise[]; // → Pling! const power = function[base, exponent] { let result = 1; for [let count = 0; count 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };1. Các hàm hoàn toàn không có câu lệnh
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 109, chẳng hạn như
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 104, trả về tương tự
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };1
Các tham số cho một hàm hoạt động giống như các ràng buộc thông thường, nhưng các giá trị ban đầu của chúng được cung cấp bởi người gọi hàm, không phải mã trong chính hàm đó
Ràng buộc và phạm vi
Mỗi ràng buộc có một phạm vi, đó là một phần của chương trình trong đó ràng buộc có thể nhìn thấy. Đối với các liên kết được xác định bên ngoài bất kỳ hàm hoặc khối nào, phạm vi là toàn bộ chương trình—bạn có thể tham khảo các liên kết đó ở bất cứ đâu bạn muốn. Chúng được gọi là toàn cầu
Nhưng các ràng buộc được tạo cho các tham số của hàm hoặc được khai báo bên trong một hàm chỉ có thể được tham chiếu trong hàm đó, vì vậy chúng được gọi là các ràng buộc cục bộ. Mỗi khi hàm được gọi, các phiên bản mới của các ràng buộc này được tạo. Điều này cung cấp một số cách ly giữa các chức năng—mỗi lệnh gọi chức năng hoạt động trong thế giới nhỏ bé của riêng nó [môi trường cục bộ của nó] và thường có thể hiểu được mà không cần biết nhiều về những gì đang diễn ra trong môi trường toàn cầu
Các ràng buộc được khai báo với
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };5 và
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };6 trên thực tế là cục bộ đối với khối mà chúng được khai báo, vì vậy nếu bạn tạo một trong các ràng buộc đó bên trong một vòng lặp, mã trước và sau vòng lặp sẽ không thể “thấy” nó. Trong JavaScript trước năm 2015, chỉ các hàm tạo phạm vi mới, do đó, các liên kết kiểu cũ, được tạo bằng từ khóa
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };7, hiển thị trong toàn bộ hàm mà chúng xuất hiện—hoặc trong phạm vi toàn cục, nếu chúng không có trong một hàm
let x = 10; if [true] { let y = 20; var z = 30; console.log[x + y + z]; // → 60 } // y is not visible here console.log[x + z]; // → 40
Mỗi phạm vi có thể “nhìn ra” phạm vi xung quanh nó, vì vậy,
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 103 có thể nhìn thấy bên trong khối trong ví dụ. Ngoại lệ là khi nhiều liên kết có cùng tên—trong trường hợp đó, mã chỉ có thể nhìn thấy liên kết trong cùng. Ví dụ: khi mã bên trong hàm
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };9 đề cập đến
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }0, nó đang nhìn thấy
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }0 của chính nó, chứ không phải toàn bộ
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }0
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 10
Phạm vi lồng nhau
JavaScript không chỉ phân biệt các ràng buộc toàn cầu và cục bộ. Các khối và chức năng có thể được tạo bên trong các khối và chức năng khác, tạo ra nhiều mức độ địa phương
Ví dụ: chức năng này—xuất các thành phần cần thiết để tạo ra một mẻ hummus—có một chức năng khác bên trong nó
const hummus = function[factor] { const ingredient = function[amount, unit, name] { let ingredientAmount = amount * factor; if [ingredientAmount > 1] { unit += "s"; } console.log[`${ingredientAmount} ${unit} ${name}`]; }; ingredient[1, "can", "chickpeas"]; ingredient[0.25, "cup", "tahini"]; ingredient[0.25, "cup", "lemon juice"]; ingredient[1, "clove", "garlic"]; ingredient[2, "tablespoon", "olive oil"]; ingredient[0.5, "teaspoon", "cumin"]; };
Mã bên trong hàm
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }3 có thể thấy ràng buộc
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }4 từ hàm bên ngoài. Nhưng các ràng buộc cục bộ của nó, chẳng hạn như
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }5 hoặc
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }6, không hiển thị trong hàm bên ngoài
Tập hợp các liên kết hiển thị bên trong một khối được xác định bởi vị trí của khối đó trong văn bản chương trình. Mỗi phạm vi cục bộ cũng có thể nhìn thấy tất cả các phạm vi cục bộ chứa nó và tất cả các phạm vi có thể nhìn thấy phạm vi toàn cầu. Cách tiếp cận này để ràng buộc khả năng hiển thị được gọi là phạm vi từ vựng
Chức năng như giá trị
Một ràng buộc chức năng thường chỉ đóng vai trò là tên cho một phần cụ thể của chương trình. Một ràng buộc như vậy được xác định một lần và không bao giờ thay đổi. Điều này khiến bạn dễ nhầm lẫn giữa hàm và tên của nó
Nhưng cả hai khác nhau. Một giá trị hàm có thể làm tất cả những việc mà các giá trị khác có thể làm—bạn có thể sử dụng nó trong các biểu thức tùy ý, không chỉ gọi nó. Có thể lưu trữ một giá trị hàm trong một liên kết mới, chuyển nó làm đối số cho một hàm, v.v. Tương tự, một liên kết giữ một hàm vẫn chỉ là một liên kết thông thường và có thể, nếu không phải là hằng số, được gán một giá trị mới, như vậy
let launchMissiles = function[] { missileSystem.launch["now"]; }; if [safeMode] { launchMissiles = function[] {/* do nothing */}; }
Trong Chương 5, chúng ta sẽ thảo luận về những điều thú vị có thể được thực hiện bằng cách chuyển các giá trị của hàm cho các hàm khác
ký hiệu khai báo
Có một cách ngắn hơn một chút để tạo ràng buộc hàm. Khi từ khóa
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 102 được sử dụng ở đầu câu lệnh, nó hoạt động khác đi
function square[x] { return x * x; }
Đây là một khai báo hàm. Câu lệnh xác định ràng buộc
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 101 và trỏ nó vào hàm đã cho. Nó dễ viết hơn một chút và không yêu cầu dấu chấm phẩy sau hàm
Có một sự tinh tế với dạng định nghĩa hàm này
console.log["The future says:", future[]]; function future[] { return "You'll never have flying cars"; }
Mã trước hoạt động, mặc dù chức năng được xác định bên dưới mã sử dụng nó. Khai báo hàm không phải là một phần của luồng kiểm soát từ trên xuống dưới thông thường. Về mặt khái niệm, chúng được chuyển lên đầu phạm vi của chúng và có thể được sử dụng bởi tất cả các mã trong phạm vi đó. Điều này đôi khi hữu ích vì nó cho phép tự do sắp xếp mã theo cách có ý nghĩa mà không phải lo lắng về việc phải xác định tất cả các chức năng trước khi chúng được sử dụng
chức năng mũi tên
Có một ký hiệu thứ ba cho các chức năng, trông rất khác so với các ký hiệu khác. Thay vì từ khóa
const halve = function[n] { return n / 2; }; let n = 10; console.log[halve[100]]; // → 50 console.log[n]; // → 102, nó sử dụng một mũi tên [
function square[x] { return x * x; }0] được tạo thành từ một dấu bằng và một ký tự lớn hơn [đừng nhầm với toán tử lớn hơn hoặc bằng, được viết là
function square[x] { return x * x; }1]
const power = [base, exponent] => { let result = 1; for [let count = 0; count { return x * x; }; const square2 = x => x * x;
Khi một hàm mũi tên hoàn toàn không có tham số, danh sách tham số của nó chỉ là một tập hợp các dấu ngoặc đơn trống
const makeNoise = function[] { console.log["Pling!"]; }; makeNoise[]; // → Pling! const power = function[base, exponent] { let result = 1; for [let count = 0; count x * x;6 trong các lệnh gọi trung gian sẽ chuyển chuỗi đó theo, cuối cùng trả về giải pháp
chức năng phát triển
Có hai cách ít nhiều tự nhiên để các hàm được đưa vào chương trình
Đầu tiên là bạn thấy mình viết mã tương tự nhiều lần. Bạn không muốn làm điều đó. Có nhiều mã hơn có nghĩa là có nhiều không gian hơn cho các lỗi cần che giấu và nhiều tài liệu hơn để đọc cho những người đang cố gắng hiểu chương trình. Vì vậy, bạn lấy chức năng lặp đi lặp lại, tìm một cái tên hay cho nó và đặt nó vào một chức năng
Cách thứ hai là bạn thấy mình cần chức năng nào đó mà bạn chưa viết ra và nghe có vẻ như nó xứng đáng với chức năng riêng của nó. Bạn sẽ bắt đầu bằng cách đặt tên cho hàm, sau đó bạn sẽ viết phần thân của nó. Bạn thậm chí có thể bắt đầu viết mã sử dụng hàm trước khi bạn thực sự xác định chính hàm đó
Việc tìm một cái tên hay cho một hàm khó đến mức nào là một dấu hiệu tốt cho thấy khái niệm mà bạn đang cố gắng bao hàm rõ ràng đến mức nào. Hãy đi qua một ví dụ
Chúng tôi muốn viết một chương trình in ra hai số. số lượng bò và gà trong một trang trại, với các từ
const square1 = [x] => { return x * x; }; const square2 = x => x * x;9 và
const makeNoise = function[] { console.log["Pling!"]; }; makeNoise[]; // → Pling! const power = function[base, exponent] { let result = 1; for [let count = 0; count