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

----

1.1       JavaScript cho React

Trước khi tìm hiểu về React, bạn sẽ tìm hiểu một số kiến thức nền tảng JavaScript giúp việc tìm hiểu về React được thuận tiện hơn.

Từ khi ra đời năm 1995 đến nay, JavaScript đã có rất nhiều thay đổi. Ban đầu, người ta sử dụng JavaScript để tăng thêm khả năng tương tác cho các phần tử của trang web, như các nút bấm, thao tác huơ chuột (hover), kiểm tra dữ liệu của form. Sau đó, JavaScript được quan tâm nhiều hơn với DHTML và Ajax. Ngày nay, với Node.js, JavaScript đã trở thành một ngôn ngữ lập trình ứng dụng thực sự, có thể sử dụng để tạo ra một ứng dụng hoàn chỉnh. Hiện nay JavaScript đang được nhiều người quan tâm.

Sự tiến hóa của JavaScript được thúc đẩy bởi cộng đồng, các công ty và các nhà phát triển trình duyệt web. ECMA (European Computer Manufacturers Association – Hiệp hội các nhà sản xuất máy tính châu Âu) là tổ chức chịu trách nhiệm quản lý những thay đổi của JavaScript trong các năm qua. Các thay đổi được khởi phát và đệ trình từ các cá nhân/tổ chức trong cộng đồng, mọi người đều có thể đệ trình các thay đổi tới ECMA, tổ chức này sẽ quản lý và xét duyệt để đưa các đệ trình vào các đặc tả của JavaScript.

Như vậy, bạn có thể sử dụng hai từ tương đương là JavaScript hoặc ECMAScript (viết tắt là ES) khi nói về ngôn ngữ lập trình JavaScript. Các đặc tả JavaScript của ECMA gồm nhiều phiên bản, ví dụ: ES2015 (hay ES6), ES2016 (ES7), ES2021 (ES12). Có thể hiểu, JavaScript là một ngôn ngữ lập trình, còn ECMA là các chuẩn hóa (hay các phiên bản) của ngôn ngữ JavaScript.

Khi đọc các tài liệu tiếng Anh bạn sẽ thấy thuật ngữ “Vanilla JavaScript” ám chỉ là JavaScript thuần (bao gồm cả các bản ES), để phân biệt với các thư viện, framework dựa trên JavaScript. Việc nắm được các kiến thức, các kĩ thuật lập trình của JavaScript thuần là một lợi thế rất lớn, giúp bạn dễ dàng học, làm việc với các thư viện, framework và các chương trình JavaScript khác nhau.

1.1.1       Khai báo biến và phạm vi

Trước ES2015 (hay ES6) để khai báo biến, chỉ có một cách là sử dụng từ khóa var. Tuy nhiên, các phiên bản JavaScript từ ES2015 trở về sau, ngoài việc dùng từ khóa var, nó còn cho phép khai báo biến bằng một số cách khác.

Dùng từ khóa const

const là viết tắt của constant, nghĩa là hằng. Do là hằng nên bạn không thể thay đổi giá trị của nó sau khi đã khai báo và gán giá trị lần đầu.

Trong thực tế, có rất nhiều biến trong JavaScript không nên cho phép thay đổi giá trị, trong trường hợp này, bạn nên sử dụng từ khóa const để khai báo biến.

Ví dụ, với từ khóa var, bạn có thể ghi đè giá trị của biến:

var pizza = true;

pizza = false;

console.log(pizza); // false

Các bạn nên viết lại từng đoạn mã ví dụ và chạy trong trình duyệt, hoặc trong hệ thống Nodejs để xem kết quả.

Ví dụ chạy trên trình duyệt web:

Cách 1:

– Mở trình duyệt, mở cửa sổ Developer tools, chọn tab Console

– Nhập đoạn mã nguồn vào cửa sổ Console, để xuống dòng bấm phím Shift + Enter; bấm phím Enter để chạy chương trình; dùng hàm clear() hoặc console.clear() để xóa sạch màn hình.

Cách 2:

– Tạo một tập tin với phần mở rộng là .html (ví dụ test.html)

– Nhập mã nguồn JavaScript trong cặp thẻ <script></script>

– Mở tập tin test.html bằng trình duyệt web

– Mở cửa sổ Developer tools, chọn tab Console để xem kết quả

Ví dụ chạy trong hệ thống Nodejs:

– Cài đặt phần mềm Nodejs

– Tạo một tập tin mã nguồn, với phần mở rộng là .js (ví dụ test.js)

– Nhập mã JavaScript vào tập tin mã nguồn, lưu lại

– Mở cửa sổ dòng lệnh (cmd hoặc powershell)

– Di chuyển dấu nhắc lệnh tới vị trí của tập tin mã nguồn

– Gõ lệnh node taptinmanguon.js (ví dụ node test.js) để thực thi và xem kết quả

Ví dụ, dùng từ khóa const để khai báo và khởi tạo giá trị cho biến, sau đó bạn không thể thay đổi giá trị của biến:

const pizza = true;

pizza = false; // sẽ có thông báo lỗi

Nhắc lại một chút về khái niệm phạm vi (scope) trong ngôn ngữ lập trình

Phạm vi (scope) trong ngôn ngữ lập trình là một khái niệm dùng để xác định một vùng của chương trình máy tính, mà trong đó, biến có tồn tại và có thể tham chiếu tới nó để thực hiện các thao tác.

Trong JavaScript, phạm vi được xác định dựa trên mã nguồn (dựa trên văn bản), nên được gọi là phạm vi dựa trên từ vựng (lexical scope).

Phạm vi của biến dựa trên từ vựng được gọi là lexical variable scope.

Một vùng mã (code block) được xác định bằng các cặp dấu ngoặc nhọn ({}). Trong các hàm, cặp dấu ngoặc nhọn (liền sau tên hàm) giúp phân định phạm vi của một biến (khai báo bằng từ khóa var) là toàn cục (global) hay cục bộ (local).

Phạm vi cục bộ, biến được khai báo bên trong hàm, nên chỉ tồn tại ở trong hàm:

  function TeoFunction(){

            var x = 3;

            console.log("x trong ham: " + x);

        }

        TeoFunction(); // x trong ham: 3

        console.log("x ngoai ham: " + x); // báo lỗi, x is not defined

Phạm vi toàn cục, biến được khai báo ngoài hàm, nên có thể truy cập ở bên trong các hàm khác nhau, hay mọi vị trí trong trang mã nguồn:

  var x = 3;

        function TeoFunction(){

            console.log("x trong ham: " + x);

        }

        TeoFunction(); // x trong ham: 3

        console.log("x ngoai ham: " + x); // x ngoài hàm: 3

Ngoại lệ, biến được khai báo trong hàm nhưng không có từ khóa var cũng được xem là biến toàn cục, ví dụ:

  function TiFunction(){

            tiBien = "Cu Ti";

        }

        TiFunction(); // thực thi hàm để chạy lệnh khai báo biến

        console.log(tiBien); // Cu Ti

        function TeoFunction(){

            console.log("Teo chao " + tiBien);

        }

        TeoFunction(); // Teo chao Cu Ti

Trường hợp đã có biến toàn cục, bên trong hàm tiếp tục khai báo một biến cục bộ trùng tên với biến toàn cục, JavaScript vẫn cho phép, khi đó tồn tại hai biến trùng tên, một biến toàn cục và một biến cục bộ:

  function TiFunction(){

            tiBien = "Cu Ti";

        }

        TiFunction(); // thực thi hàm để chạy lệnh khai báo biến

        console.log(tiBien); // Cu Ti

        function TeoFunction(){

            var tiBien = "abc";

            console.log("Teo chao " + tiBien);

        }

        TeoFunction(); // Teo chao abc

        console.log(tiBien); // Cu Ti

Dùng từ khóa let để khai báo biến

Như ở phần trước đã trình bày, trong  JavaScript, nếu dùng từ khóa var để khai báo biến thì phạm vi của biến được xác định bằng các hàm: khai báo trong hàm là cục bộ, khai báo ngoài hàm là toàn cục. Như vậy, trong trường hợp cần xác lập phạm vi của biến theo các khối lệnh, giới hạn bằng các cặp dấu ngoặc nhọn ({}), thì sẽ không thực hiện được với từ khóa var. Ví dụ:

 var topic = "JavaScript";

 

       if(topic) {

           var topic = "React";

           console.log("trong vung if: ", topic); // trong vung if: React

       }

       console.log("ngoai vung if: ", topic); // ngoai vung if: React

Ở đoạn mã trên, biến topic trong khối lệnh if đã thay đổi giá trị của biến toàn cục topic nằm bên ngoài.

Với ES6, bạn có thể sử dụng từ khóa let thay cho từ khóa var để khai báo biến, khi đó, phạm vi của  biến sẽ được xác lập theo các khối lệnh nằm trong các cặp dấu ngoặc nhọn ({}), giúp bảo vệ giá trị của các biến toàn cục. Ví dụ:

      var topic = "JavaScript";

 

       if(topic) {

           let topic = "React";

           console.log("trong vung if: ", topic); // trong vung if: React

       }

       console.log("ngoai vung if: ", topic); // ngoai vung if: JavaScript

 Một ví dụ khác về tình huống sử dụng từ khóa var trong vòng lặp for. Từ khóa var làm cho biến i trong vòng lặp for trở thành biến toàn cục, làm cho chương trình không còn đúng.

var div,

        container = document.getElementById("container");

 

    for (var i = 0; i < 5; i++) {

        div = document.createElement("div");

        div.onclick = function() {

            alert("Day la div thu: " + i);

        };

        container.appendChild(div);

    }

Vòng lặp for ở đoạn mã trên sẽ tạo ra 5 phần tử div đặt trong container, mỗi phần tử div được gắn một sự kiện click, để khi người dùng bấm vào mỗi div thì nó sẽ bật lên một thông báo cho biết số hiệu của phần tử div đó. Do từ khóa var làm cho biến i thuộc kiểu toàn cục, nên sau khi vòng lặp for chạy xong thì giá trị của biến i là 5, do vậy mọi phần tử đều có số hiệu là 5.

Trong vòng lặp for, nếu thay từ khóa var bằng từ khóa let thì biến i sẽ có phạm vi trong vòng lặp. Do vậy, khi bấm vào mỗi div thì nó sẽ có số hiệu từ 0 đến 4 tương ứng.

          const container = document.getElementById('container');

          let div;

 

          for (let i = 0; i < 5; i++{

               div = document.createElement('div');

               div.onclick = function() {

                    alert("Day la div thu: " + i);

               }

               container.appendChild(div);

          }

1.1.2       Mẫu xuất chuỗi

Trong tiếng Anh, ba từ này là tương đương: template strings, template literals và string templates tạm gọi là mẫu dùng để xuất chuỗi.

Thông thường, bạn hay sử dụng dấu cộng (+) để nối chuỗi với giá trị của biến, ví dụ:

          console.log('Ho ten la: ' + ho + ' ' + ten);

Ngoài cách trên, bạn có thể sử dụng mẫu (template) để xuất chuỗi cùng với giá trị của biến, sử dụng cú pháp ${}.

Ví dụ:

          console.log(`Ho ten la: ${ ho } ${ ten }`);

Để ý ở đoạn mã trên, đừng nhầm dấu nháy đơn (‘’) với dấu (``).

Khi hiển thị template, các khoảng trắng và dấu xuống dòng vẫn được duy trì so với mã nguồn, vì vậy rất tiện cho việc thiết kế các mẫu dữ liệu xuất ra màn hình, như một email hoặc một đoạn mã nguồn minh họa.

Ví dụ:

          const ten = 'Teo';

          const qty = 4;

          const email = `

          Xin chao ban ${ ten },

 

          Chung toi ra vui khi nhan duoc ${ qty } don hang tu ban.

          

          Cam on ban.`;

          console.log(email);

Hoặc bạn có thể sử dụng template để xuất trực tiếp trên trang HTML như ví dụ sau:

          const article = {

               title: 'Xuat template',

               body: 'Su dung template de xuat truc tiep len trang web'

          };

          document.body.innerHTML = `

          <section>

               <header>

                    <h1>Hoc React</h1>

               </header>

               <article>

                    <h2>${article.title}</h2>

                    ${article.body}

               </article>

               <footer>

                    <p>copyright ${new Date().getFullYear()} | Hoc React</p>

               </footer>

          </section>

          `;

1.1.3       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: biến, phạm vi của biến, lexical variable scope, template strings, template literals và string templates.

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

– Phạm vi của  biến: https://levunguyen.com/laptrinhjavascript/2021/02/12/su-dung-scope-trong-javascript/

– Phạm vi (tầm vực): https://vi.wikipedia.org/wiki/T%E1%BA%A7m_v%E1%BB%B1c_(khoa_h%E1%BB%8Dc_m%C3%A1y_t%C3%ADnh)

1.1.4       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. Viết một trang web hoàn chỉnh, minh họa cho việc sử dụng từ khóa varlet trong vòng lặp for (đã đề cập trong phần lý thuyết của bài học).

Gợi ý:

Bài tập 2: Viết một trang web hoàn chỉnh, minh họa cho việc sử dụng từ khóa varlet trong vòng lặp for (đã đề cập trong phần lý thuyết của bài học).

Minh họa cho trường hợp dùng từ khóa var:

[test.html]

<!DOCTYPE html>

<html>

<head>

    <style>

        div {

            background-color: red;

            height: 100px;

            width: 100px;

            margin-top: 10px;

        }

    </style>

</head>

<body>

    <section id="container">

    </section>

    <script>

        const container = document.getElementById("container");

        var div;

        for (var i = 0; i < 5; i++) {

            div = document.createElement("div");

            div.onclick = function() {

            alert("This is box #: " + i);

        };

        container.appendChild(div);

        }

    </script>

</body>

</html>

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

Câu 1. Trong JavaScript, câu lệnh console.log("Teo chao " + tiBien); trong đoạn mã sau sẽ xuất ra nội dung gì?

function TiFunction(){

            tiBien = "Cu Ti";

        }

        TiFunction();

        console.log(tiBien);

        function TeoFunction(){

            var tiBien = "abc";

            console.log("Teo chao " + tiBien);

        }

A. Teo chao Cu Ti

B. Teo chao abc

C. null

D. Báo lỗi trùng tên biến

Câu 2. Trong JavaScript, để khai báo biến toàn cục, bạn sử dụng cách nào?

A. khai báo ở trong hàm với từ khóa let

B. khai báo ở ngoài hàm

C. khai báo ở trong hàm với từ khóa var

D. khai báo trong khối lệnh (code block) với từ khóa var

Câu 3. Trong JavaScript, để khai báo biến cục bộ trong phạm vi từng khối lệnh, sử dụng từ khóa nào?

A. const

B. let

C. var

D. không dùng từ khóa

Câu 4. Trong JavaScript, muốn tạo ra một biến mà không cho phép thay đổi giá trị sau khi đã được khởi tạo giá trị ban đầu, thì dùng từ khóa nào?

A. const

B. let

C. var

D. không dùng từ khóa

Câu 5. Thuật ngữ “mẫu xuất chuỗi”, trong tiếng Anh có tên gọi là:

A. template strings

B. template literals

C. string templates

D. cả ba đáp án trên

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

-----

Cập nhật: 26/2/2022

-----

Bài sau: Web nâng cao (3) - JavaScript cho React (2)