0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Cách Làm Lập Trình JavaScript Thú Vị Như Clojure

Đăng vào 6 tháng trước

• 5 phút đọc

REPL?! Đây Là Gì?

REPL là viết tắt của Read-Eval-Print Loop, và trong Clojure, đây là cách làm việc với mã. Nó tương tác, nhanh chóng và thực sự rất thú vị. Bạn viết mã, chạy ngay lập tức và kết quả sẽ xuất hiện ngay lập tức.

Tuy nhiên, REPL mặc định của NodeJS không thực sự tiện lợi cho lập trình hàng ngày. Chạy nó trong terminal không thuận tiện: bạn không thấy toàn bộ bức tranh, mã của bạn không được kiểm tra trước, và bạn liên tục chuyển đổi giữa trình soạn thảo và terminal, làm mất tập trung và ngữ cảnh.

Vì vậy, trong bài viết này, tôi sẽ chỉ cho bạn cách làm cho việc lập trình JavaScript trở nên tương tác và thú vị hơn - giống như cách mọi người lập trình trong Clojure.

Ví Dụ Thực Tế

Ví dụ, trong JavaScript, bạn có thể viết:

javascript Copy
function add(a, b) { return a + b; }

Để kiểm tra nó, bạn thường phải thêm một số bài kiểm tra, hoặc làm điều gì đó như:

javascript Copy
console.log(add(36, 6));

Sau đó chạy nó với:

bash Copy
node index.js

Đó là rất nhiều bước cho một kết quả duy nhất.

Trong Clojure, mọi thứ trực tiếp hơn nhiều:

clojure Copy
(defn add [a b] (+ a b))
(add 35 7) ;; => 42

Chu kỳ phản hồi là ngay lập tức. (Tất nhiên, chúng ta vẫn cần các bài kiểm tra đúng cho phần mềm thực tế, nhưng để khám phá và giải quyết vấn đề, REPL là rất hiệu quả.)


Công Thức

Vậy làm thế nào để mang điều đó vào JavaScript?

Tôi đã viết một tiện ích mở rộng cho plugin Conjure trong Neovim. Việc thiết lập rất đơn giản - chỉ cần làm theo tài liệu:

  • Cài đặt Neovim
  • Cài đặt Conjure
  • Cài đặt NodeJS
  • Cài đặt Treesitter và chạy :TSInstall javascript trong Neovim
  • Tạo một tệp ".js" mới và mở nó trong Neovim (ví dụ: nvim repl-test.js trong terminal của bạn). Conjure sẽ tự động gắn kết nếu mọi thứ được thiết lập đúng. Đó là tất cả - bạn đã sẵn sàng để bắt đầu đánh giá JavaScript ngay từ trình soạn thảo.

Tại sao phải làm vậy? Bởi vì một khi bạn đã có vòng lặp REPL này, bạn sẽ có ít lỗi hơn, bạn thực sự có thể cảm nhận được dòng chảy của mã của bạn, và bạn có thể điều chỉnh mọi thứ nhanh hơn rất nhiều.

Ví Dụ:

javascript Copy
const mult = (a, b) => a * b;
mult(3, 4);  // (out) 12
mult(5, 3);  // (out) 15
mult(10, 8); // (out) 80

Bạn muốn thấy giá trị của một biểu thức nhanh chóng? Nhấn <localleader>ee (mặc định của Conjure). Cần khám phá một đối tượng? Chỉ cần đánh giá nó:

javascript Copy
const obj = { a: 1, b: { c: 3 } }; // đánh giá này trước
obj.b.c;                           // (out) 3

Gỡ Lỗi Ngay Lập Tức

Kiểm tra các bước trung gian trở nên đơn giản:

javascript Copy
[1, 2, 2, 3].reduce((acc, x) => { 
  console.log("acc", acc);
  console.log("x", x);
  console.log("val", acc[x]);
  return { ...acc, [x]: ++acc[x] || 1 }; 
}, {}); 

Bạn sẽ thấy ngay lập tức từng bước trong bộ đệm log của Conjure. Không cần phải chạy lại tệp, không cần phải chuyển đổi giữa các terminal. Chỉ cần... dòng chảy.


Ví Dụ Nhanh Về Clojure

Các lập trình viên Clojure thường định nghĩa một hàm và ngay lập tức kiểm tra nó bên trong một khối (comment ...):

clojure Copy
(defn name-extractor [m] (get m :name))
(comment 
   (name-extractor {:name "Kisha"}) ;; "Kisha"
   (name-extractor {:age 20}))      ;; nil

Nếu chúng ta muốn trả về :noname khi trường bị thiếu, chúng ta chỉ cần điều chỉnh hàm:

clojure Copy
(defn name-extractor [m]
   (get m :name :noname))

Và nếu chúng ta muốn xử lý chuỗi rỗng:

clojure Copy
(defn name-extractor [{:keys [name]}]
  (or (not-empty name) :noname))

Mỗi bước được thử nghiệm và hoàn thiện trong REPL.


Làm Tương Tự Trong JavaScript

javascript Copy
function nameExtractor({ name }) {
  return name || "noname";
}
nameExtractor({ name: "John" }); // 'John'
nameExtractor({ age: 15 });      // 'noname'
nameExtractor({ name: "" });     // 'noname' 

Giống như trong Clojure, bạn có thể viết các trường hợp thử nghiệm nhỏ trong mã và điều chỉnh hàm từng bước.


Khám Phá RXJS

RXJS có thể cảm thấy trừu tượng lúc đầu, nhưng với REPL, bạn có thể thử nghiệm một cách tương tác và thấy kết quả ngay khi bạn đi:

javascript Copy
import { BehaviorSubject } from "rxjs"
import { combineLatestWith, map, tap } from "rxjs/operators"

let o1 = new BehaviorSubject({ a: 1 })
let o2 = new BehaviorSubject({ b: 6 })

o1.pipe(combineLatestWith(o2),
  tap(x => console.log("combined:", x)),
  map(([{ a }, { b }]) => a + b),
  tap(x => console.log("sum:", x))
).subscribe()

o1.next({ a: 2 })
o2.next({ b: 8 })

o1.unsubscribe()
o2.unsubscribe()

Bạn có thể điều chỉnh giá trị, chạy lại chúng và ngay lập tức quan sát cách các biến đổi hoạt động.


Các Phím Tắt Hữu Ích

  • <localleader>ef - đánh giá toàn bộ tệp
  • <localleader>ts - chuyển đổi Stray Out Mode (để xem các đánh giá trì hoãn như setTimeout)
  • <localleader>cr - khởi động lại REPL (xóa tất cả các đánh giá trước đó)
  • <localleader>E - đánh giá một khối văn bản được chọn trong chế độ hình ảnh (rất hữu ích cho các ví dụ JSDoc)

Những Khó Khăn Trong NodeJS (Được Xử Lý Bởi Conjure)

  • Các hàm mũi tên không thể được định nghĩa lại trong REPL của NodeJS, nhưng Conjure sẽ chuyển đổi chúng thành các hàm thông thường.
  • import không được hỗ trợ trong REPL của NodeJS, nhưng Conjure sẽ chuyển nó thành require.

Kết Luận

Những mẹo này có thể làm cho quy trình làm việc của bạn trong JavaScript nhanh hơn, tương tác hơn và gần gũi hơn với phong cách REPL của Clojure. Một chu kỳ phản hồi ngắn hơn không chỉ làm cho việc lập trình trở nên thú vị hơn, mà còn giúp bạn viết mã sạch hơn, đáng tin cậy hơn.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào