Web nâng cao (3) - JavaScript cho React (2)

 Bài trước: Web nâng cao (2) - JavaScript cho React (1)

----

1.1       JavaScript cho React (2)

Hàm (function) là một đoạn mã nguồn được đặt tên. Hàm thường giải quyết một công việc nào đó và có thể tái sử dụng.

JavaScript cho phép bạn có thể tạo ra các hàm bằng nhiều cách. Tùy theo từng tình huống sử dụng, bạn sẽ chọn phương pháp tạo hàm cho phù hợp. Trong phần này, bạn sẽ tìm hiểu một số phương pháp định nghĩa hàm và các nội dung liên quan đến hàm như truyền đối số cho hàm, hàm trả về một đối tượng (object).

1.1.1       Hàm

Định nghĩa bằng từ khóa function

Cách đơn giản và quen thuộc để định nghĩa (hay khai báo) một hàm là sử dụng từ khóa function, theo sau là tên của hàm, tiếp theo là dấu (), sau cùng là nội dung của hàm. Nội dung của hàm được đặt trong cặp dấu {}. Ví dụ,

// định nghĩa hàm

function xinChao() {

    console.log('Chào bác Tèo');

}

Khi đã định nghĩa hàm, bạn có thể gọi nó để thực thi.

// gọi hàm để thực thi

xinChao();

Mở cửa sổ console của trình duyệt để xem kết quả.

Định nghĩa hàm kiểu biểu thức (function expression)

Với JavaScript, ngoài việc dùng từ khóa function để định nghĩa hàm, bạn có thể định nghĩa hàm như là một vế của biểu thức gán.

JavaScript xem một hàm như là một kiểu dữ liệu cơ sở (như string, number), do vậy hàm cũng là một đối tượng, từ đó bạn có thể định nghĩa hàm như là phần nội dung (vế phải) của một biểu thức gán, sau đó gán hàm cho một biến. Ví dụ:

// định nghĩa hàm và gán vào biến chao

const chao = function() {

    console.log('Chào bác Tèo');

}

// xuất nội dung hàm ra màn hình

console.log(chao);

// gọi hàm để thực thi

chao();

Một điều cần để ý là hàm được khai báo bằng từ khóa function có tính chất hoisting, còn hàm định nghĩa bằng kiểu biểu thức thì không có tính chất này. Hoisting là tính chất cho phép bạn gọi hàm để thực thi (sử dụng) trước khi định nghĩa. Từ hoist có nghĩa là nổi lên, hiểu nôm na là dù bạn định nghĩa hàm ở đâu trong chương trình thì JavaScript cũng sẽ cho đoạn mã khai báo nổi lên đầu của chương trình.

Ví dụ, bạn có thể viết đoạn chương trình theo kiểu dưới đây, nó vẫn chạy được bình thường,

// gọi hàm trước khi định nghĩa

    xinChao();

    // định nghĩa hàm

    function xinChao() {

        console.log('Chào bác Tèo');

    }

Tuy nhiên, cũng đoạn mã trên, nếu bạn khai báo hàm theo kiểu biểu thức, thì sẽ có lỗi:

// gọi hàm trước khi định nghĩa

    xinChao();

    // định nghĩa hàm

    const xinChao = function() {

        console.log('Chào bác Tèo');

    }

Hàm “mũi tên” (arrow function)

Đây là cách thứ ba để định nghĩa một hàm trong JavaScript. Bạn có thể sử dụng dấu mũi tên (arrow, =>) để định nghĩa một hàm. Bạn hãy quan sát ví dụ sau:

Chúng ta sẽ bắt đầu bằng việc định nghĩa một hàm theo kiểu thông thường, dùng từ khóa function:

// viết hàm trả về bình phương của một số

function square(x) {

    return x * x;

}

console.log(square(2));

Tiếp theo, chúng ta sẽ biến đổi cách khai báo hàm dùng từ khóa function thành kiểu biểu thức, khi đó hàm sẽ không có tên (anonymous function), vì vậy, chúng ta sẽ gán hàm cho một biến:

// viết hàm trả về bình phương của một số

const square = function(x) {

    return x * x;

}

console.log(square(2));

Sau hai bước trên, giờ chúng ta sẽ bỏ từ khóa function đi, thêm dấu mũi tên (=>), nội dung của hàm sẽ nằm sau dấu mũi tên.

var square = (x) => {

    return x * x;

}

console.log(square(2));

Vì nội dung của hàm chỉ có một hàng, nên sẽ bỏ dấu ngoặc nhọn {}, bỏ luôn chữ return đi cũng được. Cuối cùng chúng ta có hàm được định nghĩa theo kiểu mũi tên:

const square = (x) => x * x;

console.log(square(2));

Ví dụ, viết lại hàm tính tổng từ 1 > n bằng cách dùng hàm kiểu “mũi tên”. Nếu hàm có nhiều dòng lệnh thì dùng dấu {} để bao lại mã nguồn.

const sum = (n) => {

    let total = 0;

    for(let i = 1; i <= n; i++{

        total += i;

    }

    return total;

}

console.log(sum(5));

Truyền đối số cho hàm

Trong lập trình, có hai thuật ngữ hay được sử dụng với ý nghĩa khá giống nhau là tham số (parameter) và đối số (argument). Cả hai đều ám chỉ đến dữ liệu sẽ được truyền vào cho một hàm. Tuy nhiên, nếu phải phân biệt rõ ràng hai thuật ngữ này thì bạn có thể hiểu là:

– Tham số (parameter): là dữ liệu cần truyền cho hàm (khi định nghĩa hàm), dữ liệu được đại diện bằng các cái tên

– Đối số (argument): là giá trị của dữ liệu truyền cho hàm (khi gọi hàm để thực thi), nói cách khác, đối số chính là giá trị sẽ truyền vào cho các tham số

Ví dụ,

// n chính là tham số, là cái cần phải truyền cho hàm khi định nghĩa

function sum(n) {

    // trả về tổng từ 1 tới n

    let total = 0;

    for(let i = 1; i <= n; i++{

        total += i;

    }

    return total;

} 

// 5 chính là đối số, là giá trị truyền cho tham số của hàm khi thực thi

console.log('Ket qua la: ' + sum(5));

Hàm không xác định trước số tham số

JavaScript cho phép khi định nghĩa hàm không cần xác định trước số tham số. Tuy nhiên, khi thực thi thì truyền bao nhiêu đối số cũng được. Để ý tính chất này khi làm việc với hàm callback.

function anyFunction() {

    return arguments;

}

console.log(anyFunction(1,2, 'hello', true));

// [Arguments] { '0': 1, '1': 2, '2': 'hello', '3': true }

Ở ví dụ trên, khi định nghĩa hàm anyFunction(), bạn không khai báo là sẽ truyền vào bao nhiêu tham số. Nhưng khi sử dụng, bạn đã truyền vào 4 đối số, với các kiểu dữ liệu khác nhau. Lưu ý, với mỗi hàm, JavaScript tự tạo ra một biến kiểu mảng, có tên là arguments, biến này chứa các đối số đã được truyền vào cho hàm khi nó thực thi. Đoạn mã trên đã thực hiện xuất dữ liệu của mảng arguments.

Gán giá trị mặc định cho tham số

Bạn có thể gán giá trị mặc định cho tham số, để khi thực thi hàm, nếu người dùng không truyền giá trị cho tham số, thì hàm sẽ sử dụng giá trị mặc định để thực thi mà không sinh ra lỗi. Ví dụ:

function xinChao(name='Teo') {

    console.log(`Chao bac ${ name }` );

}

// không truyền giá trị cho đối số

console.log(xinChao());

// có truyền giá trị cho đối số

console.log(xinChao('Ti'));

Hàm trả về giá trị

Khi thực thi một hàm, nó có thể xuất trực tiếp dữ liệu ra cửa sổ console (như hàm xinChao), hoặc trả về một giá trị, xem ví dụ sau:

function sum() {

    // trả về tổng từ 1 tới 10

    let total = 0;

    for(let i = 1; i <= 10; i++{

        total += i;

    }

    return total;

} 

console.log('Ket qua la: ' + sum());

Hàm trả về một đối tượng

Đối tượng trong JavaScript được định nghĩa bằng cặp dấu {}, bên trong là các thuộc tính và phương thức, được biểu diễn dưới dạng name : value. Ví dụ:

 const sinhVien = {

           ho : 'Nguyen Van',

           ten : 'Teo'

       }

       console.log(sinhVien);

Ngoài cách định nghĩa đối tượng theo kiểu cố định như trên, bạn có thể tạo ra các đối tượng theo kiểu động bằng cách sử dụng hàm.

Ví dụ: xem xét hàm có tên là sinhVien, hàm này trả về một đối tượng dựa vào các đối số truyền vào. Thông thường sẽ định nghĩa như sau:

const sinhVien = (hoSV, tenSV) => {

          ho : hoSV,

          ten : tenSV

     };

console.log(sinhVien('Nguyen Van', 'Teo'));

Chạy đoạn chương trình trên sẽ bị lỗi. Hàm trả về một đối tượng thì cần bao lại nội dung của hàm bằng cặp dấu ngoặc tròn ( ). Chạy hàm sau sẽ không có lỗi.

const sinhVien = (hoSV, tenSV) => ({

          ho : hoSV,

          ten : tenSV

     });

console.log(sinhVien('Nguyen Van', 'Teo'));

1.1.2       Xem và đọc thêm

– Sử dụng các từ khóa sau để tìm kiếm trên mạng, đọc và xem thêm: hàm trong JavaScript, function declarations, function expressions, sự khác nhau giữa regular function và arrow function.

– [1] Alex Banks, Eve Porcello, Learning React – Mordern Patterns for Developing React Apps, O’Reilly Media, 2020, p12 – p17

1.1.3       Bài tập và thực hành

Bài tập 1. Viết lại các đoạn mã trong phần lý thuyết để chạy và kiểm tra lại kết quả.

Bài tập 2. (Tham khảo trên www.w3resource.com)

Write a JavaScript function that reverse a number. Using 3 types of function, including normal function, expression function and arrow function.

Sample Data and output:

Example x = 32243;

Expected Output: 34223

Bài tập 3. (Tham khảo trên www.w3resource.com)

Write a JavaScript function that returns a passed string with letters in alphabetical order.

Example string: 'webmaster'

Expected Output: 'abeemrstw'

Note: Assume punctuation and numbers symbols are not included in the passed string.

[Gợi ý]

Bài tập 2.

Write a JavaScript function that reverse a number. Using 3 types of function, including normal function, expression function and arrow function.

Sample Data and output:

Example x = 32243;

Expected Output: 34223

– Normal function

    function reverse_a_number(n){

   

        // convert number into string

        n = n + "";

        // convert string into array

        const arr = n.split("");

        // reverse array

        arr.reverse();

        // convert array into string

        const str = arr.join("");

        // convert string into number

        n = Number(str);

        // another way

        return n;

   

        /*another way

        n = n + "";

        return Number(n.split("").reverse().join(""));

        */

    }

    console.log(reverse_a_number(1234));

– Expression function

    const reverse_a_number = function(n){  

        n = n + "";

        return Number(n.split("").reverse().join(""));

    }

    console.log(reverse_a_number(1234));

– Arrow function

    const reverse_a_number = (n) => {  

        n = n + "";

        return Number(n.split("").reverse().join(""));

    }

    console.log(reverse_a_number(1234));

Bài tập 3. (Tham khảo trên www.w3resource.com)

Write a JavaScript function that returns a passed string with letters in alphabetical order.

Example string: 'webmaster'

Expected Output: 'abeemrstw'

Note: Assume punctuation and numbers symbols are not included in the passed string.

    const alphabetical_order = (str) => {  

        // convert string into array

        const arr = str.split("");

        // sorting array in alphabetical order

        arr.sort();

        // convert array into string

        str = arr.join("");

        return str;

        /* another solution

        return str.split("").sort().join("");

        */    

    }

    console.log(alphabetical_order("webmaster"));

1.1.4       Câu hỏi ôn tập

Câu 1. Trong JavaScript, hàm hoisting được hiểu là gì?

A. Là tính chất cho phép sử dụng hàm trước khi định nghĩa

B. Là hàm được định nghĩa bằng dấu mũi tên (arrow)

C. Là hàm được định nghĩa bằng biểu thức (expression)

D. Đối số truyền cho hàm chính là một hàm

Câu 2. Trong JavaScript có thể định nghĩa hàm bằng cách?

A. Dùng từ khóa function

B. Dùng biểu thức gán

C. Dùng dấu mũi tên

D. Cả 3 cách trên

Câu 3. Đoạn mã JavaScript const square = (x) => x * x; làm gì ?

A. Gán giá trị x vào biến square

B. So sánh x với x*x, kết quả trả về biến square

C. Đoạn mã không hợp lệ

D. Định nghĩa hàm square

Câu 4. Đoạn mã JavaScript này xuất gì ra cửa sổ console?

const chao = function() {

    console.log('Chào bác Tèo');

};

console.log(chao);

A. Xuất chữ “chao”

B. Xuất chuỗi “Chào bác Tèo”

C. Xuất nội dung của hàm chao()

D. Báo lỗi tham chiếu

Đáp án: 1 (A), 2 (D), 3 (D), 4 (C)

-----

Cập nhật: 7/10/2022

-----

Bài tiếp: Web nâng cao (4) - JavaScript cho React (3)