01/10/2018, 12:36

Nhờ giải thích đoạn Code JS

Chào các bạn trên diễn đàn, mình đang học về JS , mình có tham khảo được đoạn Code JS tạo effect thế này:

CodePen

VrdOeo

...

Nhưng mà có một vài chỗ mình thấy không hiểu (mình cũng đã thử search google nhưng chưa tìm ra dược câu trả lời) nên mình nhờ mọi người giúp đỡ mình.

  • Mình không hiểu tại sao mảng dots[] và mảng dotsVel [] lúc khởi tạo ban đầu chưa có giá trị nào vậy mà tại sao trong vòng For lại thực hiện được câu lệnh này dots[i] += dotsVel[i] += speed;

  • Một cái nữa mình cũng chưa hiểu là tại sao lại dùng Math.random() < 0.01 làm điều kiện kiểm tra trong hàm ``if````, mục đích của việc làm này là gì ạ ?

Mong các bạn giúp đỡ mình vs khúc mắc ở trên. Mình xin cảm ơn nhiều !

Thinh Minh Ha viết 14:40 ngày 01/10/2018

mình hiểu ý nghĩa của câu lệnh dots[i] += dotsVel[i] += speed; nhưng ý mình là khi gọi dots[i] ra thì đâu có giá trị nào đâu ?

明玉 viết 14:37 ngày 01/10/2018

Đúng là ban đầu nó không có giá trị, sau lệnh đó cả 2 chỗ đều sẽ có giá trị là NaN, hám số fillRect gặp NaN thì sẽ đơn giản là không làm gì cả.

if(Math.random() < 0.01){                   
    dots[i] = dotsVel[i] = 0;
}

Xác suất nhỏ hơn 1% để execute đoạn lệnh bên trong.

Đoán là tác giả code này cố tình troll để giấu nghề, hoặc đơn giản là lợi dụng đặc tính của Javascript để tiết kiệm dung lượng code.

Thinh Minh Ha viết 14:52 ngày 01/10/2018

Đúng là ban đầu nó không có giá trị, sau lệnh đó cả 2 chỗ đều sẽ có giá trị là NaN, hám số fillRect gặp NaN thì sẽ đơn giản là không làm gì cả.

Vậy thì sao lại tạo ra được Effect vậy bạn. Mình thực sự vẫn chưa hiểu. Bạn có thể nói chi tiết hơn được không.

if(Math.random() < 0.01){
dots[i] = dotsVel[i] = 0;
}

Xác suất nhỏ hơn 1% để execute đoạn lệnh bên trong.

Đoán là tác giả code này cố tình troll để giấu nghề.

Nhưn mà random() thế này làm sao mà code không bị ngắt quãng mà chạy trơn tru được vậy bạn.

Mình cũng không hiểu họ dùng cái dotsVel[i] ở đây để làm mục đích gì .

Bạn có thể giải thích cho mình hiểu hơn về cách hoạt động của effect này được không. Mình cám ơn bạn nhiều !

明玉 viết 14:42 ngày 01/10/2018

Mình chỉ giải thích nguyên lý thôi nhé bởi vì mình rất ghét đọc code, code thì bạn tự đọc lại:

  • Canvas ở đây có width và height;
  • Duyệt từng cột theo width của canvas;
  • Vì ban đầu (ở từng cột), dotsVel[i] và dots[i] đều là undefined nên code vẽ không hoạt động;
  • Theo xác suất dưới 1%, dots[i] và dotsVel[i] đều sẽ được reset về 0;
  • dotsVel là vận tốc sẽ được cộng tăng dần qua mỗi lần lặp, đồng thời cũng được cộng luôn vào dots chính là tọa độ y của giọt. Tạo ra cảm giác rơi nhanh dần;
  • fillRect vẽ giọt ở cột i dòng dots[i], kích thước 1x5;
  • Nhưng nếu vẽ liên tục như vậy thì không có hiệu ứng mờ dần, ra toàn là đường thẳng trơn thôi;
  • Cho nên ở đây có thêm fillRect trước khi vào vòng lặp, fill một màu đen nhưng có alpha = 0.05, đắp mờ lên những giọt mà được vẽ từ lần lặp trước, tạo hiệu ứng mờ dần.
Thinh Minh Ha viết 14:38 ngày 01/10/2018

Trước tiên mình cám ơn bạn vì đã giải thích giúp mình hiểu hơn .Tuy nhiên vì có một số chỗ mình đọc thấy vẫn chưa hiểu nên cho phép mình được phản hồi lại thế này:

Vì ban đầu (ở từng cột), dotsVel[i] và dots[i] đều là undefined nên code vẽ không hoạt động;

Thế vậy tại sao mình thấy khi load trang web thì effect liền hoạt động ngay lập tức mà không thấy có delay 1s nào cả ?

  • Theo xác suất dưới 1%, dots[i] và dotsVel[i] đều sẽ được reset về 0;

Vậy nếu trường hợp điều kiện không đúng thì sẽ như thế nào.

  • dotsVel là vận tốc sẽ được cộng tăng dần qua mỗi lần lặp

Cho mình hỏi nó tăng dần thế nào ạ ? Vì khi vòng i được tăng thêm 1 đv thì dòng lệnh này lại được gọi ra :
dots[i] += dotsVel[i] += speed;

Nhưng dotsVel[i] này là dotsVel[i] mới (nó là phần tử tiếp theo trong mảng) chứ có phải là

dotsVel[i] của vòng lặp trước đâu bạn.

Và như vậy tức là dotsVel[i] += speed <–> NaN = NaN + 0.05 Vậy thì nó tăng lên kiểu gì ạ ?

明玉 viết 14:41 ngày 01/10/2018

Thế vậy tại sao mình thấy khi load trang web thì effect cũng hoạt động ngay mà không thấy có delay 1s nào cả ?

Xác suất 1% dễ xảy ra lắm bạn , tích tắc là nó xảy ra à, đây là xác suất reset cột.

Vậy nếu trường hợp điều kiện không đúng thì sẽ như thế nào.

Thì ban đầu chỗ đó (cột đó) không có giọt nào xuất hiện cả, hoặc giọt cứ rơi hoài thôi, nhưng như ở trên, xác suất 1% của Math.random() (tức là kết quả bé hơn 0.01) rất là dễ xảy ra (đặc biệt là khi hàm này được gọi với tốc độ 60fps).

Cho mình hỏi nó tăng dần thế nào ạ ? Vì khi vòng i được tăng thêm 1 đv thì dòng lệnh này lại được gọi ra :
dots[i] += dotsVel[i] += speed;

Nhưng dotsVel[i] sẽ là phần tử tiếp theo trong mảng chứ có phải là phần tử cũ của vòng lặp trước đâu bạn.

Tức là dotsVel[i] += speed <–> NaN = NaN + 0.05 Vậy thì nó tăng lên kiểu gì ạ ?

Ban đầu đều là NaN cả thì ở cột đó không có điều gì xảy ra hết, khi gặp xác suất 1% thì dots[i] và dotsVel[i] được reset về 0.
dots[i] là vị trí tung độ của giọt ở cột i, dotsVel[i] là vận tốc của giọt ở cột i.
Tung độ mới tính bằng cách: dots[i] += dotsVel[i].
Để giọt rơi nhanh hơn, mỗi lần lặp ta phải tăng vận tốc, tăng bằng cách: dotsVel[i] += speed. (Nói đi nói lại, tác giả code đặt tên variable như shiet )
Code này:

dots[i] += dotsVel[i] += speed;

Có thể viết lại là:

dotsVel[i] += speed;
dots[i] += dotsVel[i];
Thinh Minh Ha viết 14:36 ngày 01/10/2018

Bạn ơi, cám ơn bạn đã phản hồi lại. Nhưng mà ở câu hỏi số 3 hình như bạn hiểu sai câu hỏi của mình ý.

dots[i] là vị trí tung độ của giọt ở cột i, dotsVel[i] là vận tốc của giọt ở cột i.
Tung độ mới tính bằng cách: dots[i] += dotsVel[i].
Để giọt rơi nhanh hơn, mỗi lần lặp ta phải tăng vận tốc, tăng bằng cách: dotsVel[i] += speed.

Cái nguyên lý này thì mình hiểu rồi.

dots[i] += dotsVel[i] += speed;
dotsVel[i] += speed;
dots[i] += dotsVel[i];

Cái code viết tắt này mình cũng hiểu rồi.

Nhưng cái mình không hiểu la qua mỗi vòng lặp thì giá trị dotsVel tăng lên bằng cách nào ý, vì khi i

tăng thêm 1 đv thì mình gọi cái dotsVel[i] ra thì nó sẽ là dotsVel[i] mới chứ có phải dotsVel[i]

cũ của vòng for lần trướcđâu ban ?

明玉 viết 14:46 ngày 01/10/2018

Phải là dotsVel mới, thì mới tạo hiệu ứng tăng tốc đc chứ, dotsVel cũ thì giọt nó cứ rơi đều đều.

Thinh Minh Ha viết 14:39 ngày 01/10/2018

Phải là dotsVel mới, thì mới tạo hiệu ứng tăng tốc đc chứ, dotsVel cũ thì giọt nó cứ rơi đều đều.

Mình viết thế này cho bạn dễ hiểu hơn nhé :

Có phải câu lệnh này : ```dots[i] += dotsVel[i] += speed````

được gọi ở mỗi đầu vòng for không . Với :

i = 0 :

dots[0] += dotsVel[0] += speed;```` -->dotsVel[0] = dotsVel[0] +speed;```` --> = NaN

Xét đk if nếu đúng thì dots[0] = 0 nếu không thì vẫn là NaN

i = 1 :

dots[1] += dotsVel[1] += speed;```` -->dotsVel[1] = dotsVel[1] +speed;```` --> = NaN

cứ như vậy …Vậy làm sao nó tăng đc bạn

明玉 viết 14:48 ngày 01/10/2018

dữ liệu của các cột ko liên quan đến nhau nhé bạn.
cái này tốt nhất là bạn debug và đặt breakpoint, cho vòng for chỉ duyệt 1 cột cho tiện debug, đặt breakpoint vào đầu vòng lặp và đặt vào dưới Math.random, giờ mình ko xài laptop nên ko tiện chỉ thêm.

明玉 viết 14:38 ngày 01/10/2018

OK, đây mình sẽ làm diễn biến variable cho 1 cột, các cột còn lại y chang.
Ban đầu, dots[i] và dotsVel[i] đều là undefined, cho nên hàm fillRect không hoạt động (bởi vì nó nhận tham số NaN).
Sau khi Math.random cho giá trị < 0.01, dots[i] và dotsVel[i] đều bằng 0.
Bây giờ thuật toán trước hàm fillRect mới có ý nghĩa. Ví dụ:

Lần 1:

(dotsVel[i] += speed) == 0.05; // Vận tốc
(dots[i] += dotsVel[i]) == 0.05; // Tung độ

Vẽ dot ở tung độ 0.05.

Lần 2:

(dotsVel[i] += speed) == 0.1; // Vận tốc
(dots[i] += dotsVel[i]) == 0.15; // Tung độ

Vẽ dot ở tung độ 0.15.

Lần 3:

(dotsVel[i] += speed) == 0.15; // Vận tốc
(dots[i] += dotsVel[i]) == 0.3; // Tung độ

Vẽ dot ở tung độ 0.3.

Đó, bạn đã thấy tung độ tăng nhanh dần chưa? (Vận tốc tăng đều, nhưng tung độ tăng nhanh dần)

Khi gặp xác suất dưới 1%, tung độ và vận tốc lại bị reset về 0, để ý các giọt hay rơi nửa chừng rồi lại có giọt mới ngay bên trên.

Thinh Minh Ha viết 14:45 ngày 01/10/2018

Đó, bạn đã thấy tung độ tăng nhanh dần chưa? (Vận tốc tăng đều, nhưng tung độ tăng nhanh dần)

Khi gặp xác suất dưới 1%, tung độ và vận tốc lại bị reset về 0, để ý các giọt hay rơi nửa chừng rồi lại có giọt mới ngay bên trên.

Cám ơn bạn, mình đã hiểu rồi. Cái chính ở đây là còn do thằng này nữa window.requestAnimationFrame(anim)

Chính nó mới làm cho dotsVel[i] tăng dần chứ không phải vòng for . Hồi sáng mình đã quên không để ý đến nó.
Cám ơn bạn nhiều nhiều nghen !

Thinh Minh Ha viết 14:43 ngày 01/10/2018

Bạn ơi mình phiền bạn chút nữa nha

Về Code thì mình không có gì để hỏi nữa. Mình muốn học hỏi thêm 1 chút kiến thức debug Code từ bạn.

Ở đây bạn có hướng dẫn mình làm vầy để thấy được quá trình hoạt động của Code :

cái này tốt nhất là bạn debug và đặt breakpoint, cho vòng for chỉ duyệt 1 cột cho tiện debug, đặt breakpoint vào đầu vòng lặp và đặt vào dưới Math.random, giờ mình ko xài laptop nên ko tiện chỉ thêm.

Và mình có làm theo bằng cách đặt breakpoint như bạn nói, nhưng mà nó chỉ hiển thị lên giá trị của biến i thôi, bạn cho mình hỏi làm sao để nó nó hiển thị được cả giá trị của dots[i]dotsVel[i] ra được vậy. Mình dùng Chrome Dev Tool.

Cám ơn bạn trước nha !

Thinh Minh Ha viết 14:49 ngày 01/10/2018

Bạn MeigyokuThmn ơi, bạn có đọc được bài của mình chưa. Mong sớm nhận được phản hồi từ bạn.

明玉 viết 14:42 ngày 01/10/2018

Giải thích debug cho bạn còn lâu hơn cả bài tập này, rất nhiều thứ, tốt nhất là bạn tự google nhé.
https://techmaster.vn/posts/34380/huong-dan-debugging-javascript-trong-chrome-dev-tools
https://toidicodedao.com/2015/10/08/su-ba-dao-cua-chrome-developer-tools-phan-1/

Người bị bơ viết 14:44 ngày 01/10/2018

Còn không thì xem hướng dẫn debug từ đây, có ví dụ chi tiết:

Google Developers

Get Started with Debugging JavaScript in Chrome DevTools  |  Tools for Web...

Learn how to use Chrome DevTools to find and fix JavaScript bugs.

Thinh Minh Ha viết 14:38 ngày 01/10/2018

Mình có đọc qua mấy bài về hướng dẫn Debug trên Google rồi nhưng chắc có lẽ vẫn chưa hiểu được nhiều thứ, chắc sẽ phải bỏ nhiều thời gian hơn để tìm hiểu. Mình sẽ đọc thêm ở link các bạn gởi bên trên.

Cám ơn các bạn nhé !

Bài liên quan
0