Hi,

Ngoài lề: Theo như ông chú làm ở Spiderum mình cho hay thì hình như Spiderum được viết trên nodejs/expressjs phía sever còn front-end thì sử dụng framework cũng họ nhà JavaScript là Angular2 with TypeScript (1 superset của Javascript). Vậy các bạn đã đủ thấy JS bá đạo chưa :))

Khoảng gần 1 tháng trước, lúc mình mới bắt đầu yêu JavaScript thì mình quyết định học theo cuốn Data Structures and Algorithms with JavaScript của O'Reilly, vì mình nghĩ cấu trúc dữ liệu và giải thuật chính là trái tim của lập trình. Lúc đầu khá suôn sẻ, mọi thứ cuốn sách viết đều rất rõ ràng và tỉ mỉ. Nhưng được một thời gian thì mình cảm thấy bắt đầu khô khan và dần đánh mất đi một phần nào động lực. Mình bắt đầu tìm đến những nguồn học khác. Và tình cơ vài ngày trước mình khám phá ra khóa học JavaScript trên Udemy quả thực đã khai sáng và tiếp thêm động lực cho mình rất nhiều. À tất nhiên mình vẫn tiếp tục học DS&A nhé. 

Mình sẽ tiếp tục với bài học mà mình đã học được vài ngày trước. Hứa hẹn rằng bài viết này sẽ rất dài. 

#2 Objects, The global environment, The Creation and Hoisting

Objects - Đối tượng

Object  là một khái niệm vô cùng quan trọng trong JavaScript và chúng ta sẽ dành phần lớn thời gian với nó. Nhưng trước hết chúng ta cần biết nó là gì phải không?

Name/Value pair: A name which maps to an unique value.

Tại sao phải bắt đầu với cặp name/value (hay còn được gọi là key/value pair hay attribute/value pair) ? Hãy xem!

Với mỗi tên sẽ được ánh xạ (không biết mình dùng từ này có đúng không?) tới một giá trị duy nhất. 

Tên có thể được định nghĩa nhiều lần nhưng chỉ có thể có một giá trị trong 1 context nhất định.

Một giá trị (value) có thể có chứa tập hợp những name/value pair khác.

Có vẻ lằng nhằng rồi đúng không? Hãy xem 1 ví dụ sau:

đây chính là 1 cặp name/value với name: 'adress'  và giá trị được gán tương ứng là '96 Le Thanh Nghi' . 

Khi nói đến Object chúng ta có thể dùng thuật ngữ name/value pair để định nghĩa nó:

Object is a collection of name/value pairs

Object là một tập hợp các cặp name/value. Đây có thể coi là một định nghĩa đơn giản nhất khi nói về object trong JavaScript.

Lúc trước chúng ta có đề cập đến, đó là 1 giá trị có thể chứa nhiều cặp name/value khác? vậy là sao? Hãy xem hình minh họa


Rõ ràng chứ? Object là tập hợp các name/value pair. Các value lại có thể là tập hợp của các name/value pair khác...


The Global Object and The Global Environment

Mỗi khi các dòng lệnh được thực thi. Chúng được thực thi trong một excution context (Global) (Javascript engine sẽ parsing  (phân tích cú pháp), verify rồi execute... những dòng lệnh đó). Javascript engine sẽ wrap (gói) toàn bộ các dòng lệnh của bạn trong 1 execution context. Khi các bạn nhìn vào một chương trình javascript đầu tiên sau đây các bạn sẽ được xem execution context được tạo ra như thế nào.

Khi chương trình javascript đầu tiên của bạn được khởi động. Thì ngay lập tức được JS Engine tạo 1 global environment chứa đựng 1 global object và một biến đặc biệt đó là 'this'.


Khi chạy chương trình Js engine sẽ tạo cho ta 1 global object và một biến đặc biệt 'this' nằm trong 1 execution context (global). Global object này không bao giờ được sử dụng trực tiếp, không thể được tạo ra bằng từ khóa 'new' . Được tạo ra ngay lập tức cùng với các hàm, hằng số có sẵn khi các đoạn mã script được khời tạo.

Mình sẽ chứng minh cho các bạn thấy. khi mình chạy một chương trình rỗng. Global object được tạo ra như thế nào.

Đây là khi mình chạy một chương trình rỗng:


Đây là cửa sổ console mình sử dụng qua live preview trên bracket. các bạn có thể tải về và học cách sử dụng tại brackets.io.

Bây giờ hãy xem chuyện gì xảy ra khi mình dùng từ khóa 'this'

What? Có gì đó ở đây à? Tôi đâu có đưa những thứ này vào chương trình của tôi đâu? Đúng vậy. Execution context đã được tạo bởi javascript engine và nó quyết định giá trị của 'this' sẽ là gì. Ở đây chúng ta có thể thấy this chính là window hay browser window bởi vì chúng ta đang chạy Javascript trên browser. Và thật thú vị. Chúng ta có một object 'window'  cũng có cùng giá trị bằng cách hit 'window' trên cửa sổ console:

Biến đặc biệt mà js engine đã tạo ra: 'this' đã reference đến global object (window) nên chúng có cùng giá trị!

Vậy mỗi khi chúng ta chạy javascript trên window thì việc đầu tiên là js engine sẽ khởi tạo global object window. Mỗi tab trên trình duyệt sẽ tạo 1 execution context khác nhau, tạo ra các object window riêng biệt.

Vậy tiếp theo chuyện gì sẽ xảy ra nếu mình viết một vài dòng code ở đây?

Giờ run nó nhé! Mình sẽ dùng từ khóa this để xem có chuyện gì xảy ra với global object:

Nên nhớ window objectcollection của các name/value pair. Chúng ta có thể tìm thấy ở đây biến 'a' và function 'b()' trong window object. Trong javascript khi bạn khai báo 1 variable hoặc 1 function không nằm trong 1 function khác thì những biến và function này sẽ được nhận diện trong global object. Bạn có thể gọi những biến hoặc hàm này lên như thế này. 

Thật là vi diệu đúng không :)))

The creation phase and Hoisting

Thế nào là the creation phase (giai đoạn khởi tạo)? Chúng ta hãy cũng xem 1 ví dụ, thử xem qua đoạn code sau xem sao: 

Các bạn mong đợi chuyện gì sẽ xảy ra? Cái gì sẽ được in lên màn hình thông qua việc gọi (invoke) hàm b() và in ra màn hình biến a qua dòng lệnh console.log(a) ? Các bạn cũng đoán được kết quả là: 'Hello Spiderum' và 'Xem có gì hay ho không?' đúng k?

Quả đúng như những gì ta mong đợi. Vậy bây giờ thử làm một số thứ điên điên 1 chút xem sao. Thay đổi 1 chút nhỉ:

Bây giờ bạn mong đợi điều gì sau khi chạy đoạn code này? Khi mà chúng ta gọi thực thi hàm b() trước khi function b() được định nghĩa?

Hầu hết các programing languages đều không cho phép chúng ta làm điều này vì hầu hết các programing languages đều execute từ trên xuống. (one line at a time). Chúng ta chưa thể sử dụng b() khi nó còn chưa được định nghĩa. Vì vậy chúng ta hi vọng rằng nó sẽ văng ra 1 lỗi nào đó đúng k? Nên nhớ Javascript rất "tà đạo" :)) 

Hãy cùng xem kết quả:

Quả thực JS thật vi diệu. Nó đã chạy function b() để cho ra kết quả 'Xem có gì hay ho không' và thay vì báo lỗi khi chạy console.log(a), nó lại trả về kết quả là 1 giá trị đặc biệt 'undefined' . Tại sao? Giờ chúng ta thử thay đổi 1 chút: 

Chúng ta sẽ comment dòng khai báo biến a lại. Chương trình biên dịch sẽ bỏ qua dòng này coi như không khai báo nó. và xem thử kết quả:

Và kết quả là a is not defined! Đến lúc hack não nè. Undefined khác với is not defined ư? Yep! Chúng khác nhau. Undefined là một từ khóa và là một giá trị đặc biệt được setup space trên memory còn một biến được gọi là is not defined thì không. 


Hoisting:

Trong JavaScript có một thuật ngữ được gọi là hoisting. Là khi chương trình được thực thi, Javascript engine sẽ phisically move toàn bộ functionsvariables lên đầu mỗi excution context. Như thế này:

Ơ nếu nó thế thì vẫn có gì đó sai sai. Sao mình rõ ràng có khai báo biến a = 'Hello Spiderum' rồi, rồi thì biết a được hoist lên đầu execution context rồi cơ mà. Sao lại nhận được giá trị là undefined

Đúng thế. Sau khi hoist tất cả variablesfunctions lên top mỗi execution context, JS engine còn assign (gán) cho mỗi variables một giá trị đặc biệt là undefined, và được setup space trên memory.  

The Creation Phase: Giai đoạn khởi tạo:

 

Thực chất trước khi các dòng code được thực thi line by line thì JS engine đã sẵn sàng xong việc setup memory space cho các variablesfunctions đặt chúng ở trạng thái sẵn sàng truy cập. Còn đối với các biến chúng được gán tạm một giá trị chưa xác định là undefined. Nên khi chúng ta execute đến đoạn console.log(a) thì oops! Tôi chưa biết thằng 'a' này là cái khỉ gì cả, trong bộ nhớ nó vẫn là undefined!  Tôi sẽ trả nó về giá trị undefined!

That's it!

Rõ ràng rồi chứ? 

Đó là toàn bộ những gì mình hiểu sơ lược về Object, The Global environment, The creation phase and Hoisting mà mình muốn chia sẻ trong bài viết này. Hi vọng là mình đã không hiểu sai chỗ nào. Và tin mình đi. Mình sẽ còn đào sâu những vấn đề này nhiều lần ở những bài viết sau. Hãy đi lên từ căn bản

JavaScipt thật vi diệu phải không :))) 

Xin cám ơn!

==============================================================

Previous | Contents | Next