Thứ ba, 31/03/2020 | 00:00 GMT+7

Hiểu các tham số mặc định trong JavaScript

Trong ECMAScript 2015 , các tham số hàm mặc định đã được đưa vào ngôn ngữ JavaScript . Những điều này cho phép các nhà phát triển khởi tạo một hàm với các giá trị mặc định nếu các đối số không được cung cấp cho lệnh gọi hàm. Khởi tạo các tham số hàm theo cách này sẽ giúp các hàm của bạn dễ đọc hơn và ít bị lỗi hơn, đồng thời sẽ cung cấp hành vi mặc định cho các hàm của bạn. Điều này sẽ giúp bạn tránh các lỗi bắt nguồn từ việc truyền các đối số undefined và hủy cấu trúc các đối tượng không tồn tại.

Trong bài viết này, bạn sẽ xem xét sự khác biệt giữa tham số và đối số, tìm hiểu cách sử dụng tham số mặc định trong các hàm, xem các cách thay thế để hỗ trợ tham số mặc định và tìm hiểu những loại giá trị và biểu thức nào được dùng làm tham số mặc định. Bạn cũng sẽ chạy qua các ví dụ minh họa cách các tham số mặc định hoạt động trong JavaScript.

Đối số và tham số

Trước khi giải thích các tham số hàm mặc định, điều quan trọng là phải biết các tham số có thể mặc định là gì. Do đó, trước tiên ta sẽ xem xét sự khác biệt giữa các đối sốtham số trong một hàm. Nếu bạn muốn tìm hiểu thêm về sự khác biệt này, hãy xem bài viết trước của ta trong loạt bài viết về JavaScript , Cách xác định các hàm trong JavaScript .

Trong khối mã sau, bạn sẽ tạo một hàm trả về khối lập phương của một số nhất định, được định nghĩa là x :

// Define a function to cube a number function cube(x) {   return x * x * x } 

Biến x trong ví dụ này là một tham số — một biến có tên được truyền vào một hàm. Một tham số phải luôn được chứa trong một biến và không bao giờ được có giá trị trực tiếp.

Bây giờ hãy xem khối mã tiếp theo này, khối này gọi hàm cube mà bạn vừa tạo:

// Invoke cube function cube(10) 

Điều này sẽ cho kết quả sau:

Output
1000

Trong trường hợp này, 10 là một đối số —một giá trị được truyền cho một hàm khi nó được gọi. Thường thì giá trị cũng sẽ được chứa trong một biến, chẳng hạn như trong ví dụ tiếp theo này:

// Assign a number to a variable const number = 10  // Invoke cube function cube(number) 

Điều này sẽ mang lại kết quả tương tự:

Output
1000

Nếu bạn không truyền một đối số cho một hàm mong đợi một đối số, hàm sẽ mặc nhiên sử dụng undefined làm giá trị:

// Invoke the cube function without passing an argument cube() 

Kết quả sẽ trả về :

Output
NaN

Trong trường hợp này, cube() đang cố gắng tính toán giá trị của undefined * undefined * undefined , kết quả là NaN , hoặc “không phải là một số”. Để biết thêm về điều này, hãy xem phần số của Hiểu các loại dữ liệu trong JavaScript .

Hành vi tự động này đôi khi có thể là một vấn đề. Trong một số trường hợp, bạn có thể cần tham số có giá trị ngay cả khi không có đối số nào được truyền vào hàm. Đó là nơi mà tính năng tham số mặc định trở nên hữu ích, một chủ đề mà bạn sẽ đề cập trong phần tiếp theo.

Cú pháp tham số mặc định

Với việc bổ sung các tham số mặc định trong ES2015, giờ đây bạn có thể gán giá trị mặc định cho bất kỳ tham số nào, mà hàm sẽ sử dụng thay vì undefined khi được gọi mà không có đối số. Phần này trước tiên sẽ hướng dẫn bạn cách thực hiện việc này theo cách thủ công, sau đó sẽ hướng dẫn bạn cách cài đặt các thông số mặc định.

Nếu không có thông số mặc định, bạn sẽ phải kiểm tra rõ ràng các giá trị undefined để đặt giá trị mặc định, như được minh họa trong ví dụ này:

// Check for undefined manually function cube(x) {   if (typeof x === 'undefined') {     x = 5   }    return x * x * x }  cube() 

Điều này sử dụng một câu lệnh có điều kiện để kiểm tra xem giá trị có được tự động cung cấp dưới dạng undefined , sau đó đặt giá trị của x5 . Điều này sẽ dẫn đến kết quả sau:

Output
125

Ngược lại, việc sử dụng các tham số mặc định sẽ đạt được cùng một mục tiêu với ít mã hơn nhiều. Bạn có thể đặt giá trị mặc định cho tham số trong cube bằng cách gán nó với toán tử gán bằng ( = ), như được đánh dấu ở đây:

// Define a cube function with a default value function cube(x = 5) {   return x * x * x } 

Bây giờ khi hàm cube được gọi mà không có đối số, nó sẽ gán 5 cho x và trả về phép tính thay vì NaN :

// Invoke cube function without an argument cube() 
Output
125

Nó sẽ vẫn hoạt động như dự định khi một đối số được truyền, bỏ qua giá trị mặc định:

// Invoke cube function with an argument cube(2) 
Output
8

Tuy nhiên, một lưu ý quan trọng cần lưu ý là giá trị tham số mặc định cũng sẽ overrides một giá trị undefined rõ ràng undefined truyền dưới dạng đối số cho một hàm, như được minh họa ở đây:

// Invoke cube function with undefined cube(undefined) 

Điều này sẽ cho phép tính với x bằng 5 :

Output
125

Trong trường hợp này, các giá trị tham số mặc định đã được tính toán và một giá trị undefined rõ ràng không overrides chúng.

Đến đây bạn đã có ý tưởng về cú pháp cơ bản của các tham số mặc định, phần tiếp theo sẽ chỉ ra cách các tham số mặc định hoạt động với các kiểu dữ liệu khác nhau.

Các kiểu dữ liệu tham số mặc định

Bất kỳ giá trị hoặc đối tượng nguyên thủy nào cũng được dùng làm giá trị tham số mặc định. Trong phần này, bạn sẽ thấy cách mà tính linh hoạt này làm tăng cách thức sử dụng các tham số mặc định.

Đầu tiên, đặt các tham số bằng cách sử dụng một số , chuỗi , boolean , đối tượng, mảng và giá trị null làm giá trị mặc định. Ví dụ này sẽ sử dụng cú pháp hàm mũi tên :

// Create functions with a default value for each data type const defaultNumber = (number = 42) => console.log(number) const defaultString = (string = 'Shark') => console.log(string) const defaultBoolean = (boolean = true) => console.log(boolean) const defaultObject = (object = { id: 7 }) => console.log(object) const defaultArray = (array = [1, 2, 3]) => console.log(array) const defaultNull = (nullValue = null) => console.log(nullValue) 

Khi các hàm này được gọi mà không có tham số, tất cả chúng sẽ sử dụng các giá trị mặc định:

// Invoke each function defaultNumber() defaultString() defaultBoolean() defaultObject() defaultArray() defaultNull() 
Output
42 "Shark" true {id: 7} (3) [1, 2, 3] null

Lưu ý bất kỳ đối tượng nào được tạo trong một tham số mặc định sẽ được tạo mỗi khi hàm được gọi. Một trong những trường hợp sử dụng phổ biến cho các tham số mặc định là sử dụng hành vi này để lấy các giá trị từ một đối tượng. Nếu bạn cố gắng phá hủy hoặc truy cập một giá trị từ một đối tượng không tồn tại, nó sẽ gây ra lỗi. Tuy nhiên, nếu tham số mặc định là một đối tượng trống, nó sẽ chỉ cung cấp cho bạn các giá trị undefined thay vì đưa ra lỗi:

// Define a settings function with a default object function settings(options = {}) {   const { theme, debug } = options    // Do something with settings } 

Điều này sẽ tránh được lỗi do cấu trúc các đối tượng không tồn tại.

Đến đây bạn đã thấy cách các tham số mặc định hoạt động với các kiểu dữ liệu khác nhau, phần tiếp theo sẽ giải thích cách nhiều tham số mặc định có thể hoạt động cùng nhau.

Sử dụng nhiều tham số mặc định

Bạn có thể sử dụng nhiều tham số mặc định như bạn muốn trong một hàm. Phần này sẽ chỉ cho bạn cách thực hiện việc này và cách sử dụng nó để thao tác DOM trong một ví dụ thực tế.

Đầu tiên, khai báo một hàm sum() với nhiều tham số mặc định:

// Define a function to add two values function sum(a = 1, b = 2) {   return a + b }  sum() 

Điều này sẽ dẫn đến phép tính mặc định sau:

Output
3

Ngoài ra, giá trị được sử dụng trong một tham số được dùng trong bất kỳ tham số mặc định nào tiếp theo, từ trái sang phải. Ví dụ: hàm createUser này tạo một đối tượng user userObj làm tham số thứ ba và tất cả những gì bản thân hàm thực hiện là trả về userObj với hai tham số đầu tiên:

// Define a function to create a user object using parameters function createUser(name, rank, userObj = { name, rank }) {   return userObj }  // Create user const user = createUser('Jean-Luc Picard', 'Captain') 

Nếu bạn gọi user ở đây, bạn sẽ nhận được những điều sau:

Output
{name: "Jean-Luc Picard", rank: "Captain"}

Bạn thường nên đặt tất cả các tham số mặc định ở cuối danh sách các tham số để bạn có thể dễ dàng loại bỏ các giá trị tùy chọn. Nếu bạn sử dụng một tham số mặc định trước, bạn sẽ phải chuyển một cách rõ ràng undefined để sử dụng giá trị mặc định.

Đây là một ví dụ với tham số mặc định ở đầu danh sách:

// Define a function with a default parameter at the start of the list function defaultFirst(a = 1, b) {   return a + b } 

Khi gọi hàm này, bạn sẽ phải gọi defaultFirst() với hai đối số:

defaultFirst(undefined, 2) 

Điều này sẽ cung cấp những điều sau:

Output
3

Đây là một ví dụ với tham số mặc định ở cuối danh sách:

// Define a function with a default parameter at the end of the list function defaultLast(a, b = 1) {   return a + b }  defaultLast(2) 

Điều này sẽ mang lại cùng một giá trị:

Output
3

Cả hai hàm đều có cùng kết quả, nhưng hàm có giá trị mặc định cuối cùng cho phép gọi hàm sạch hơn nhiều.

Đối với một ví dụ trong thế giới thực, đây là một hàm sẽ tạo phần tử DOM và thêm nhãn văn bản và các lớp, nếu chúng tồn tại.

// Define function to create an element function createNewElement(tag, text, classNames = []) {   const el = document.createElement(tag)   el.textContent = text    classNames.forEach(className => {     el.classList.add(className)   })    return el } 

Bạn có thể gọi hàm với một số lớp trong một mảng:

const greeting = createNewElement('p', 'Hello!', ['greeting', 'active']) 

greeting gọi điện sẽ cung cấp giá trị sau:

Output
<p class="greeting active">Hello!</p>

Tuy nhiên, nếu bạn bỏ mảng classNames ra khỏi lệnh gọi hàm, nó vẫn hoạt động.

const greeting2 = createNewElement('p', 'Hello!') 

greeting2 bây giờ có giá trị sau:

Output
<p>Hello!</p>

Trong ví dụ này, forEach() được dùng trên một mảng trống mà không gặp sự cố. Nếu mảng trống đó không được đặt trong tham số mặc định, bạn sẽ gặp lỗi sau:

Output
VM2673:5 Uncaught TypeError: Cannot read property 'forEach' of undefined at createNewElement (<anonymous>:5:14) at <anonymous>:12:18

Đến đây bạn đã thấy cách nhiều tham số mặc định có thể tương tác, bạn có thể chuyển sang phần tiếp theo để xem cách gọi hàm hoạt động như tham số mặc định.

Gọi hàm dưới dạng tham số mặc định

Ngoài các nguyên thủy và đối tượng, kết quả của việc gọi một hàm được dùng như một tham số mặc định.

Trong khối mã này, bạn sẽ tạo một hàm để trả về một số ngẫu nhiên, rồi sử dụng kết quả làm giá trị tham số mặc định trong một hàm cube :

// Define a function to return a random number from 1 to 10 function getRandomNumber() {   return Math.floor(Math.random() * 10) }  // Use the random number function as a default parameter for the cube function function cube(x = getRandomNumber()) {   return x * x * x } 

Bây giờ việc gọi hàm cube mà không có tham số sẽ có các kết quả có thể khác nhau mỗi khi bạn gọi nó:

// Invoke cube function twice for two potentially different results cube() cube() 

Đầu ra từ các lệnh gọi hàm này sẽ khác nhau:

Output
512 64

Bạn thậm chí có thể sử dụng các phương thức tích hợp sẵn, như các phương thức trên đối tượng Math và sử dụng giá trị được trả về trong một lệnh gọi hàm làm tham số trong một hàm khác.

Trong ví dụ sau, một số ngẫu nhiên được gán cho x , được sử dụng làm tham số trong hàm cube bạn đã tạo. Tham số y sau đó sẽ tính toán căn bậc hai của số và kiểm tra xem xy có bằng nhau hay không:

// Assign a random number to x // Assign the cube root of the result of the cube function and x to y function doesXEqualY(x = getRandomNumber(), y = Math.cbrt(cube(x))) {   return x === y }  doesXEqualY() 

Điều này sẽ cung cấp những điều sau:

Output
true

Một tham số mặc định thậm chí có thể là một định nghĩa hàm, như được thấy trong ví dụ này, định nghĩa một tham số là hàm inner và trả về lời gọi hàm của parameter :

// Define a function with a default parameter that is an anonymous function function outer(   parameter = function inner() {     return 100   } ) {   return parameter() }  // Invoke outer function outer() 
Output
100

Hàm inner này sẽ được tạo từ đầu mỗi khi hàm outer được gọi.

Kết luận

Trong bài viết này, bạn đã biết các tham số hàm mặc định là gì và cách sử dụng chúng. Như vậy, bạn có thể sử dụng các tham số mặc định để giúp giữ cho các chức năng của bạn sạch sẽ và dễ đọc. Bạn cũng có thể gán các đối tượng và mảng trống cho các tham số để giảm độ phức tạp và dòng mã khi xử lý các tình huống như truy xuất giá trị từ một đối tượng hoặc lặp qua một mảng.

Nếu bạn muốn tìm hiểu thêm về JavaScript, hãy xem trang chủ của loạt bài Cách viết mã trong JavaScript của ta hoặc duyệt qua loạt bài Cách viết mã trong Node.js của ta để biết các bài viết về phát triển back-end.


Tags:

Các tin liên quan

Cookie là gì và cách làm việc với chúng bằng JavaScript
2020-03-19
Tham quan nhanh về date-fns, Thư viện ngày JavaScript đơn giản
2020-03-18
Phương thức getOwnPropertyDescriptors trong JavaScript
2020-03-12
Cây tìm kiếm nhị phân thông qua JavaScript
2020-03-03
Tree Traversal qua JavaScript
2020-03-02
Hiểu về Trình tạo trong JavaScript
2020-02-28
Triển khai Thành phần Tab từ Scratch trong Vanilla JavaScript
2020-02-24
Khám phá cây qua JavaScript
2020-02-23
Giới thiệu về danh sách được liên kết qua JavaScript - Phần 2: Triển khai
2020-02-23
Khám phá các và hàng đợi qua JavaScript
2020-02-23