Hàm () javascript

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

  1. 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
  2. Í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 Knuth
Hàm () javascript

Hà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);
// → 10
1 để 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);
// → 10
2. 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);
// → 10
3) 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);
// → 10
4 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);
// → 10
5 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 < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024

Một số hàm tạo ra một giá trị, chẳng hạn như

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
5 và
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
1, và một số thì không, chẳng hạn như
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
4, mà kết quả duy nhất của chúng là một tác dụng phụ. Câu lệnh
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
9 xác định giá trị mà hàm trả về. Khi điều khiển bắt gặp một câu lệnh như vậy, nó sẽ ngay lập tức nhảy ra khỏi hàm hiện tại và đưa giá trị trả về vào mã gọi hàm. Một từ khóa
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
9 không có biểu thức sau nó sẽ khiến hàm trả 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");
};
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);
// → 10
9, chẳng hạn như
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
4, 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);
// → 10
3 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);
// → 10
2 đượ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);
// → 10
1 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);
// → 10
2, 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 < exponent; count++) {
    result *= base;
  }
  return result;
};

Mũi tên xuất hiện sau danh sách các tham số và theo sau là phần thân của hàm. Nó thể hiện điều gì đó giống như “đầu vào này (các tham số) tạo ra kết quả này (phần thân)”

Khi chỉ có một tên tham số, bạn có thể bỏ dấu ngoặc quanh danh sách tham số. Nếu phần thân là một biểu thức đơn lẻ, chứ không phải là một khối trong dấu ngoặc nhọn, thì biểu thức đó sẽ được trả về từ hàm. Vì vậy, hai định nghĩa của

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
1 làm điều tương tự

const square1 = (x) => { 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 < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
0

Không có lý do sâu xa nào để có cả hàm mũi tên và biểu thức

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
2 trong ngôn ngữ. Ngoại trừ một chi tiết nhỏ, mà chúng ta sẽ thảo luận trong Chương 6, chúng cũng làm điều tương tự. Các hàm mũi tên đã được thêm vào năm 2015, chủ yếu là để có thể viết các biểu thức hàm nhỏ theo cách ít dài dòng hơn. Chúng ta sẽ sử dụng chúng rất nhiều trong Chương 5

ngăn xếp cuộc gọi

Cách kiểm soát chảy qua các chức năng có phần liên quan. Hãy xem xét kỹ hơn về nó. Đây là một chương trình đơn giản thực hiện một vài lời gọi hàm

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
1

Chạy qua chương trình này đại khái như thế này. lệnh gọi tới

function square(x) {
  return x * x;
}
4 khiến điều khiển chuyển đến đầu chức năng đó (dòng 2). Hàm gọi
function square(x) {
  return x * x;
}
5, chiếm quyền điều khiển, thực hiện công việc của nó và sau đó trả lại quyền điều khiển cho dòng 2. Ở đó, nó đến cuối hàm
function square(x) {
  return x * x;
}
4, vì vậy nó quay trở lại nơi đã gọi nó, đó là dòng 4. Đường dây sau đó gọi lại
function square(x) {
  return x * x;
}
5. Sau khi quay trở lại, chương trình kết thúc

Chúng ta có thể hiển thị luồng điều khiển theo sơ đồ như thế này

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
2

Bởi vì một chức năng phải quay trở lại vị trí đã gọi nó khi nó quay trở lại, máy tính phải nhớ ngữ cảnh mà cuộc gọi đã xảy ra. Trong một trường hợp,

function square(x) {
  return x * x;
}
5 phải quay lại hàm
function square(x) {
  return x * x;
}
4 khi thực hiện xong. Trong trường hợp khác, nó quay trở lại cuối chương trình

Nơi máy tính lưu trữ bối cảnh này là ngăn xếp cuộc gọi. Mỗi khi một chức năng được gọi, ngữ cảnh hiện tại được lưu trữ trên đầu ngăn xếp này. Khi một hàm trả về, nó sẽ loại bỏ ngữ cảnh trên cùng khỏi ngăn xếp và sử dụng ngữ cảnh đó để tiếp tục thực thi

Lưu trữ ngăn xếp này cần dung lượng trong bộ nhớ của máy tính. Khi ngăn xếp phát triển quá lớn, máy tính sẽ bị lỗi với thông báo như “hết dung lượng ngăn xếp” hoặc “quá nhiều đệ quy”. Đoạn mã sau minh họa điều này bằng cách hỏi máy tính một câu hỏi thực sự khó gây ra sự qua lại vô hạn giữa hai chức năng. Thay vào đó, nó sẽ là vô hạn, nếu máy tính có một ngăn xếp vô hạn. Như vậy, chúng tôi sẽ hết dung lượng hoặc "thổi tung ngăn xếp"

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
3

Đối số tùy chọn

Đoạn mã sau được cho phép và thực thi mà không gặp bất kỳ sự cố nào

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
4

Chúng tôi đã xác định

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
1 chỉ với một tham số. Vậy mà khi ta gọi nó bằng ba, ngôn ngữ không phàn nàn. Nó bỏ qua các đối số phụ và tính bình phương của đối số đầu tiên

JavaScript cực kỳ rộng rãi về số lượng đối số bạn chuyển đến một hàm. Nếu bạn vượt quá nhiều, những cái thừa sẽ bị bỏ qua. Nếu bạn chuyển quá ít, các tham số còn thiếu sẽ được gán giá trị

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

Nhược điểm của điều này là có thể—có khả năng, thậm chí—bạn sẽ vô tình chuyển sai số lượng đối số cho các hàm. Và sẽ không ai nói với bạn về điều đó

Ưu điểm là hành vi này có thể được sử dụng để cho phép một hàm được gọi với số lượng đối số khác nhau. Ví dụ: hàm

console.log("The future says:", future());

function future() {
  return "You'll never have flying cars";
}
2 này cố bắt chước toán tử
console.log("The future says:", future());

function future() {
  return "You'll never have flying cars";
}
3 bằng cách tác động lên một hoặc hai đối số

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
5

Nếu bạn viết một toán tử

console.log("The future says:", future());

function future() {
  return "You'll never have flying cars";
}
4 sau một tham số, theo sau là một biểu thức, thì giá trị của biểu thức đó sẽ thay thế đối số khi nó không được đưa ra

Ví dụ: phiên bản này của

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
5 làm cho đối số thứ hai của nó là tùy chọn. Nếu bạn không cung cấp hoặc chuyển giá trị
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, giá trị này sẽ mặc định là hai và hàm sẽ hoạt động như
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
1

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
6

Trong phần này, chúng ta sẽ thấy cách mà một thân hàm có thể lấy toàn bộ danh sách các đối số mà nó được truyền vào. Điều này rất hữu ích vì nó giúp một hàm có thể chấp nhận bất kỳ số lượng đối số nào. Ví dụ:

function square(x) {
  return x * x;
}
5 thực hiện điều này—nó xuất ra tất cả các giá trị được cung cấp

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
7

Khép kín

Khả năng coi các hàm là các giá trị, kết hợp với thực tế là các liên kết cục bộ được tạo lại mỗi khi một hàm được gọi, sẽ đưa ra một câu hỏi thú vị. Điều gì xảy ra với các liên kết cục bộ khi lệnh gọi hàm tạo ra chúng không còn hoạt động?

Đoạn mã sau đây cho thấy một ví dụ về điều này. Nó định nghĩa một chức năng,

console.log("The future says:", future());

function future() {
  return "You'll never have flying cars";
}
9, tạo ra một liên kết cục bộ. Sau đó, nó trả về một hàm truy cập và trả về liên kết cục bộ này

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
8

Điều này được cho phép và hoạt động như bạn mong muốn—cả ​​hai phiên bản của ràng buộc vẫn có thể được truy cập. Tình huống này là một minh chứng tốt về thực tế là các ràng buộc cục bộ được tạo lại cho mỗi cuộc gọi và các cuộc gọi khác nhau không thể chà đạp lên các ràng buộc cục bộ của nhau

Tính năng này—có thể tham chiếu đến một thể hiện cụ thể của ràng buộc cục bộ trong một phạm vi kèm theo—được gọi là bao đóng. Một chức năng tham chiếu các ràng buộc từ các phạm vi cục bộ xung quanh nó được gọi là một bao đóng. Hành vi này không chỉ giúp bạn không phải lo lắng về thời gian tồn tại của các ràng buộc mà còn giúp bạn có thể sử dụng các giá trị hàm theo một số cách sáng tạo

Với một thay đổi nhỏ, chúng ta có thể biến ví dụ trước thành một cách để tạo các hàm nhân với một lượng tùy ý

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
9

Liên kết rõ ràng

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
0 từ ví dụ
console.log("The future says:", future());

function future() {
  return "You'll never have flying cars";
}
9 không thực sự cần thiết vì bản thân một tham số đã là một liên kết cục bộ

Suy nghĩ về các chương trình như thế này cần một số thực hành. Một mô hình tinh thần tốt là nghĩ về các giá trị chức năng chứa cả mã trong phần thân của chúng và môi trường mà chúng được tạo ra. Khi được gọi, thân hàm nhìn thấy môi trường mà nó được tạo ra, không phải môi trường mà nó được gọi

Trong ví dụ,

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
2 được gọi và tạo một môi trường trong đó tham số
let launchMissiles = function() {
  missileSystem.launch("now");
};
if (safeMode) {
  launchMissiles = function() {/* do nothing */};
}
4 của nó được liên kết với 2. Giá trị hàm mà nó trả về, được lưu trữ trong
const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
4, ghi nhớ môi trường này. Vì vậy, khi được gọi, nó sẽ nhân đối số của nó với 2

đệ quy

Việc một hàm tự gọi chính nó là hoàn toàn bình thường, miễn là nó không làm điều đó thường xuyên đến mức tràn ngăn xếp. Một chức năng gọi chính nó được gọi là đệ quy. Đệ quy cho phép một số chức năng được viết theo một phong cách khác. Lấy ví dụ, triển khai thay thế này của

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
5

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
0

Điều này khá gần với cách các nhà toán học định nghĩa lũy thừa và được cho là mô tả khái niệm này rõ ràng hơn biến thể vòng lặp. Hàm gọi chính nó nhiều lần với số mũ nhỏ hơn bao giờ hết để đạt được phép nhân lặp lại

Nhưng việc triển khai này có một vấn đề. trong triển khai JavaScript điển hình, nó chậm hơn khoảng ba lần so với phiên bản vòng lặp. Chạy qua một vòng lặp đơn giản thường rẻ hơn so với gọi một hàm nhiều lần

Tiến thoái lưỡng nan của tốc độ so với sự thanh lịch là một điều thú vị. Bạn có thể xem nó như một dạng liên tục giữa thân thiện với con người và thân thiện với máy móc. Hầu như bất kỳ chương trình nào cũng có thể được thực hiện nhanh hơn bằng cách làm cho nó lớn hơn và phức tạp hơn. Lập trình viên phải quyết định một sự cân bằng thích hợp

Trong trường hợp của hàm

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
5, phiên bản (lặp) không phù hợp vẫn khá đơn giản và dễ đọc. Không có ý nghĩa gì khi thay thế nó bằng phiên bản đệ quy. Tuy nhiên, thông thường, một chương trình xử lý các khái niệm phức tạp như vậy nên việc loại bỏ một số hiệu quả để làm cho chương trình trở nên đơn giản hơn là hữu ích

Lo lắng về hiệu quả có thể là một sự phân tâm. Đó là một yếu tố khác làm phức tạp việc thiết kế chương trình và khi bạn đang làm một việc gì đó vốn đã khó, thì điều cần lo lắng thêm đó có thể khiến bạn tê liệt.

Do đó, hãy luôn bắt đầu bằng cách viết một cái gì đó chính xác và dễ hiểu. Nếu bạn lo lắng rằng nó quá chậm—điều này thường không xảy ra vì đơn giản là hầu hết các mã không được thực thi thường xuyên đủ để mất bất kỳ khoảng thời gian đáng kể nào—bạn có thể đo lường sau đó và cải thiện nó nếu cần

Đệ quy không phải lúc nào cũng chỉ là một giải pháp thay thế không hiệu quả cho vòng lặp. Một số vấn đề thực sự dễ giải quyết bằng đệ quy hơn là bằng vòng lặp. Thông thường, đây là những bài toán yêu cầu khám phá hoặc xử lý một số "nhánh", mỗi nhánh có thể lại phân nhánh thành nhiều nhánh hơn nữa

Hãy xem xét câu đố này. bằng cách bắt đầu từ số 1 và lặp đi lặp lại cộng 5 hoặc nhân với 3, có thể tạo ra một bộ số vô hạn. Làm thế nào bạn có thể viết một hàm, cho trước một số, cố gắng tìm một chuỗi các phép cộng và phép nhân tạo ra số đó?

Ví dụ: số 13 có thể đạt được bằng cách nhân 3 trước rồi cộng 5 hai lần, trong khi số 15 hoàn toàn không thể đạt được

Đây là một giải pháp đệ quy

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
1

Lưu ý rằng chương trình này không nhất thiết phải tìm chuỗi hoạt động ngắn nhất. Nó hài lòng khi nó tìm thấy bất kỳ chuỗi nào

Không sao nếu bạn không thấy nó hoạt động ngay lập tức. Hãy cùng nhau giải quyết nó, vì nó tạo ra một bài tập tuyệt vời về tư duy đệ quy

Hàm bên trong

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
7 thực hiện việc đệ quy. Phải mất hai đối số. số hiện tại và một chuỗi ghi lại cách chúng tôi đạt được số này. Nếu nó tìm thấy một giải pháp, nó sẽ trả về một chuỗi cho biết cách đến mục tiêu. Nếu không tìm thấy giải pháp nào bắt đầu từ số này, nó sẽ trả về
const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
8

Để làm điều này, chức năng thực hiện một trong ba hành động. Nếu số hiện tại là số mục tiêu, thì lịch sử hiện tại là một cách để đạt được mục tiêu đó, vì vậy nó được trả về. Nếu số hiện tại lớn hơn mục tiêu, sẽ không có ý nghĩa gì khi khám phá thêm nhánh này vì cả phép cộng và phép nhân sẽ chỉ làm cho số lớn hơn, do đó, nó trả về

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
8. Cuối cùng, nếu chúng ta vẫn ở dưới số mục tiêu, hàm sẽ thử cả hai đường dẫn có thể bắt đầu từ số hiện tại bằng cách gọi chính nó hai lần, một lần để cộng và một lần để nhân. Nếu cuộc gọi đầu tiên trả về thứ gì đó không phải là
const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
8, nó sẽ được trả lại. Mặt khác, cuộc gọi thứ hai được trả về, bất kể nó tạo ra một chuỗi hay
const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
8

Để hiểu rõ hơn cách chức năng này tạo ra hiệu ứng mà chúng ta đang tìm kiếm, hãy xem xét tất cả các cuộc gọi đến

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
7 được thực hiện khi tìm kiếm giải pháp cho số 13

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
2

Vết lõm cho biết độ sâu của ngăn xếp cuộc gọi. Lần đầu tiên

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
7 được gọi, nó bắt đầu bằng cách gọi chính nó để khám phá giải pháp bắt đầu bằng
const square1 = (x) => { return x * x; };
const square2 = x => x * x;
4. Cuộc gọi đó sẽ tiếp tục lặp lại để khám phá mọi giải pháp tiếp tục mang lại một số nhỏ hơn hoặc bằng số mục tiêu. Vì nó không tìm thấy cái nào bắn trúng mục tiêu, nên nó trả về
const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
8 trở lại cuộc gọi đầu tiên. Ở đó, toán tử
const square1 = (x) => { return x * x; };
const square2 = x => x * x;
6 thực hiện cuộc gọi khám phá
const square1 = (x) => { return x * x; };
const square2 = x => x * x;
7. Tìm kiếm này có nhiều may mắn hơn—cuộc gọi đệ quy đầu tiên của nó, thông qua một cuộc gọi đệ quy khác, chạm vào số mục tiêu. Lệnh gọi trong cùng đó trả về một chuỗi và mỗi toán tử
const square1 = (x) => { return x * x; };
const square2 = x => 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 < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
00 sau chúng và các số 0 được đệm trước cả hai số để chúng luôn có ba chữ số

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
3

Điều này yêu cầu một hàm gồm hai đối số—số lượng bò và số lượng gà. Hãy viết 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
4

Viết

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
01 sau một biểu thức chuỗi sẽ cho ta độ dài của chuỗi đó. Do đó, các vòng lặp
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
02 tiếp tục thêm các số 0 vào trước các chuỗi số cho đến khi chúng dài ít nhất ba ký tự

nhiệm vụ hoàn thành. Nhưng ngay khi chúng tôi chuẩn bị gửi mã cho người nông dân (cùng với một hóa đơn đắt tiền), cô ấy gọi điện và nói với chúng tôi rằng cô ấy cũng bắt đầu nuôi lợn và chúng tôi có thể vui lòng mở rộng phần mềm để in cả lợn không?

chúng tôi chắc chắn có thể. Nhưng ngay khi chúng tôi đang trong quá trình sao chép và dán bốn dòng đó một lần nữa, chúng tôi dừng lại và xem xét lại. Có phải là một cách tốt hơn. Đây là nỗ lực đầu tiên

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
5

Nó hoạt động. Nhưng tên đó,

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
03, hơi khó xử. Nó kết hợp ba thứ—in, không đệm và thêm nhãn—vào một chức năng duy nhất

Thay vì loại bỏ phần lặp đi lặp lại trong chương trình bán buôn của chúng tôi, hãy thử chọn ra một khái niệm duy nhất

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
6

Một hàm có tên đẹp, rõ ràng như

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
04 giúp người đọc mã dễ dàng tìm ra chức năng của nó. Và một chức năng như vậy hữu ích trong nhiều tình huống hơn là chỉ chương trình cụ thể này. Ví dụ: bạn có thể sử dụng nó để giúp in các bảng số được căn chỉnh đẹp mắt

Chức năng của chúng ta nên thông minh và linh hoạt như thế nào?

Một nguyên tắc hữu ích là không thêm sự thông minh trừ khi bạn hoàn toàn chắc chắn rằng mình sẽ cần đến nó. Có thể rất hấp dẫn khi viết các “khuôn khổ” chung cho mọi chức năng mà bạn gặp phải. Chống lại sự thôi thúc đó. Bạn sẽ không hoàn thành bất kỳ công việc thực tế nào—bạn sẽ chỉ viết mã mà bạn không bao giờ sử dụng

Chức năng và tác dụng phụ

Các chức năng có thể được tạm chia thành những chức năng được gọi cho tác dụng phụ của chúng và những chức năng được gọi cho giá trị trả về của chúng. (Mặc dù chắc chắn cũng có thể có tác dụng phụ và trả về giá trị. )

Hàm trợ giúp đầu tiên trong ví dụ trang trại,

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
03, được gọi vì tác dụng phụ của nó. nó in một dòng. Phiên bản thứ hai,
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
04, được gọi cho giá trị trả về của nó. Không phải ngẫu nhiên mà cái thứ hai hữu ích trong nhiều tình huống hơn cái thứ nhất. Các hàm tạo giá trị dễ kết hợp theo những cách mới hơn các hàm trực tiếp thực hiện các tác dụng phụ

Hàm thuần túy là một loại hàm tạo giá trị cụ thể không chỉ không có tác dụng phụ mà còn không phụ thuộc vào tác dụng phụ từ mã khác—ví dụ: nó không đọc các liên kết toàn cầu có giá trị có thể thay đổi. Một hàm thuần túy có thuộc tính dễ chịu là khi được gọi với các đối số giống nhau, nó luôn tạo ra cùng một giá trị (và không làm gì khác). Một cuộc gọi đến một hàm như vậy có thể được thay thế bằng giá trị trả về của nó mà không làm thay đổi ý nghĩa của mã. Khi bạn không chắc rằng một hàm thuần túy có hoạt động chính xác hay không, bạn có thể kiểm tra nó bằng cách gọi nó và biết rằng nếu nó hoạt động trong ngữ cảnh đó thì nó sẽ hoạt động trong mọi ngữ cảnh. Các chức năng không thuần túy có xu hướng yêu cầu nhiều giàn giáo hơn để kiểm tra

Tuy nhiên, bạn không cần phải cảm thấy tồi tệ khi viết các hàm không thuần túy hoặc tiến hành một cuộc thánh chiến để loại bỏ chúng khỏi mã của bạn. Tác dụng phụ thường hữu ích. Chẳng hạn, sẽ không có cách nào để viết một phiên bản thuần túy của

function square(x) {
  return x * x;
}
5, và thật tốt khi có
function square(x) {
  return x * x;
}
5. Một số hoạt động cũng dễ dàng hơn để thể hiện một cách hiệu quả khi chúng ta sử dụng các tác dụng phụ, vì vậy tốc độ tính toán có thể là một lý do để tránh sự thuần khiết

Tóm lược

Chương này đã dạy bạn cách viết các hàm của riêng bạn. Từ khóa

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
2, khi được sử dụng như một biểu thức, có thể tạo ra một giá trị hàm. Khi được sử dụng như một câu lệnh, nó có thể được sử dụng để khai báo một liên kết và đặt cho nó một hàm làm giá trị của nó. Hàm mũi tên là một cách khác để tạo 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
7

Một khía cạnh quan trọng trong việc hiểu chức năng là hiểu phạm vi. Mỗi khối tạo ra một phạm vi mới. Các tham số và ràng buộc được khai báo trong một phạm vi nhất định là cục bộ và không thể nhìn thấy từ bên ngoài. Các liên kết đượ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");
};
7 hoạt động khác—chúng kết thúc ở phạm vi chức năng gần nhất hoặc phạm vi toàn cầu

Việc tách các tác vụ mà chương trình của bạn thực hiện thành các chức năng khác nhau rất hữu ích. Bạn sẽ không phải lặp lại nhiều lần và các hàm có thể giúp tổ chức một chương trình bằng cách nhóm mã thành các phần thực hiện những công việc cụ thể

bài tập

tối thiểu

Hàm tiêu chuẩn được giới thiệu

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
11 trả về đối số nhỏ nhất của nó. Chúng ta có thể xây dựng một cái gì đó như thế bây giờ. Viết một hàm
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
12 nhận vào hai đối số và trả về giá trị nhỏ nhất của chúng

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
8

Nếu bạn gặp khó khăn khi đặt dấu ngoặc nhọn và dấu ngoặc đơn vào đúng vị trí để có được định nghĩa hàm hợp lệ, hãy bắt đầu bằng cách sao chép một trong các ví dụ trong chương này và sửa đổi nó

Một hàm có thể chứa nhiều câu lệnh

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
9

đệ quy

Chúng ta đã thấy rằng có thể sử dụng

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
14 (toán tử còn lại) để kiểm tra xem một số là chẵn hay lẻ bằng cách sử dụng
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
15 để xem liệu nó có chia hết cho hai hay không. Đây là một cách khác để xác định xem một số nguyên dương là số chẵn hay số lẻ

  • Số không là số chẵn

  • Một là lẻ

  • Đối với bất kỳ số nào khác N, số chẵn của nó giống như N - 2

Xác định hàm đệ quy

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
16 tương ứng với mô tả này. Hàm phải chấp nhận một tham số duy nhất (số dương, số nguyên) và trả về giá trị Boolean

Kiểm tra nó trên 50 và 75. Xem cách nó hoạt động trên -1. Tại sao?

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
9

Hàm của bạn có thể trông hơi giống với hàm

const power = (base, exponent) => {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};
7 bên trong hàm đệ quy
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
18 trong chương này, với một chuỗi
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
19/
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
20/
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
21 để kiểm tra xem trường hợp nào trong ba trường hợp được áp dụng.
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
21 cuối cùng, tương ứng với trường hợp thứ ba, thực hiện cuộc gọi đệ quy. Mỗi nhánh phải chứa một câu lệnh
const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
9 hoặc theo cách khác sắp xếp để trả về một giá trị cụ thể

Khi được cung cấp một số âm, hàm sẽ lặp đi lặp lại nhiều lần, truyền cho chính nó một số âm ngày càng nhiều, do đó càng ngày càng xa kết quả trả về. Cuối cùng nó sẽ hết dung lượng ngăn xếp và hủy bỏ

đếm đậu

Bạn có thể lấy ký tự hoặc chữ cái thứ N từ một chuỗi bằng cách viết

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
24. Giá trị được trả về sẽ là một chuỗi chỉ chứa một ký tự (ví dụ:
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
25). Ký tự đầu tiên có vị trí 0, khiến ký tự cuối cùng được tìm thấy ở vị trí
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
26. Nói cách khác, một chuỗi hai ký tự có độ dài 2 và các ký tự của nó có vị trí 0 và 1

Viết một hàm

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
27 nhận một chuỗi làm đối số duy nhất của nó và trả về một số cho biết có bao nhiêu ký tự chữ “B” viết hoa trong chuỗi

Tiếp theo, hãy viết một hàm có tên là

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
28 hoạt động giống như hàm
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
27, ngoại trừ nó nhận một đối số thứ hai cho biết ký tự sẽ được đếm (thay vì chỉ đếm các ký tự chữ hoa “B”). Viết lại
const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
27 để sử dụng chức năng mới này

const halve = function(n) {
  return n / 2;
};

let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
0

Hàm của bạn sẽ cần một vòng lặp xem xét mọi ký tự trong chuỗi. Nó có thể chạy một chỉ mục từ 0 đến 1 dưới độ dài của nó (

const makeNoise = function() {
  console.log("Pling!");
};

makeNoise();
// → Pling!

const power = function(base, exponent) {
  let result = 1;
  for (let count = 0; count < exponent; count++) {
    result *= base;
  }
  return result;
};

console.log(power(2, 10));
// → 1024
31). Nếu ký tự ở vị trí hiện tại giống với ký tự mà hàm đang tìm kiếm, nó sẽ thêm 1 vào biến đếm. Khi vòng lặp kết thúc, bộ đếm có thể được trả về

Hãy cẩn thận để tạo tất cả các ràng buộc được sử dụng trong hàm cục bộ cho hàm bằng cách khai báo chúng đúng cách với 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");
};
5 hoặc
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

Cấu trúc hàm () )() trong JavaScript là gì?

Cấu trúc (function() { } )() trong JavaScript là gì? . Nó là một chức năng, thực thi khi tạo. an immediately invoked function expression (IIFE). It is a function, which executes on creation.

Phương thức gọi chức năng () là gì?

nguyên mẫu. call() Phương thức call() gọi hàm với giá trị this đã cho và các đối số được cung cấp riêng lẻ .

3 loại chức năng trong JavaScript là gì?

Đối với mỗi loại chức năng, có ba cách để xác định nó. Khai báo . hàm, hàm*, hàm không đồng bộ, hàm không đồng bộ*

Làm cách nào để chạy một hàm trong JavaScript?

Tất cả những gì bạn cần làm là sử dụng tên hàm theo sau là dấu ngoặc đơn . Bên trong dấu ngoặc đơn, bạn có thể chỉ định bất kỳ đối số nào mà hàm cần chạy.