Prototypes trong JavaScript là gì? Tại sao nó lại quan trọng?

Prototypes trong JavaScript là gì? Tại sao nó lại quan trọng?

Tin ngắn hàng ngày dành cho bạn
  • Mấy hôm trước OpenAI giới thiệu Deep Research - một công cụ duyệt web để nghiên cứu và cho ra một bản tổng hợp chỉ trong vài chục phút - so với nhiều giờ làm việc đối với con người, theo như họ công bố.

    Tính năng này hiện chỉ có sẵn cho người dùng Pro. Mặc dù chưa được dùng thử, nhưng qua nhiều bài viết đều nhấn mạnh vào sự ấn tượng trước khả năng của công cụ mới này. Nếu vẫn chưa biết Deep Research làm được gì thì bạn cứ hình dung như thế này: Nói với nó "Tôi cần thông tin nghiên cứu về lượng tiêu thụ cà phê của thế giới trong năm ngoái". Thế thôi! Ngồi chờ một lúc để nó tìm kiếm và tổng hợp lại kết quả và gửi lại cho bạn một bài báo cáo chi tiết. Chà, ghê thật chứ!

    Ngay lập tức huggingface đã lên một bài viết cố gắng tái tạo lại công cụ này theo cách của họ. Chi tiết tại Open-source DeepResearch – Freeing our search agents. Và không có gì ngạc nhiên khi cả 2 đều mang hơi hướng của AI Agents.

    » Xem thêm
  • Sống đủ lâu trong thế giới Internet, bạn có thể thấy rằng mọi người ở đây khá háo hức chạy theo xu hướng và chúng lan truyền với tốc độ chóng mặt.

    Chỉ vài tháng trước, chúng ta vẫn còn kinh ngạc về trí thông minh của các mô hình ngôn ngữ lớn (LLM) có thể trả lời giống như con người, và ngay sau đó, chúng đã được cập nhật với khả năng suy nghĩ và lý luận đáng kinh ngạc. Chúng được ứng dụng rộng rãi không chỉ trong lĩnh vực lập trình. Gần đây, thuật ngữ AI Agents đã tạo nên một sự khuấy động.

    Vậy, AI Agents là gì? Trong bài viết ngắn này, tất nhiên là không thể đưa ra một định nghĩa ngắn gọn nhưng toàn diện. Bạn đọc có thể tham khảo bài viết rất chi tiết này tại đây Agents | Chip Huyền. Để dễ hình dung hơn, AI Agents có thể được coi là một người hoặc một thực thể nào đó. Bản thân các Agents được trang bị tất cả các công cụ cần thiết. Từ đó, các Agents có thể kết hợp chúng để hoàn thành một nhiệm vụ mà chúng ta giao.

    Vẫn còn hơi mơ hồ phải không? Một ví dụ thực tế là khi bạn ra lệnh cho các Agents truy cập Facebook vào lúc 8 giờ tối mỗi ngày, kiểm tra bất kỳ tin tức nổi bật nào từ bạn bè, sau đó gửi tóm tắt đến Telegram. Vậy là xong!

    » Xem thêm
  • Hôm qua đến nay, lượt truy cập tới từ Facebook tăng đột biến. Thường như thế là do ai đó chia sẻ bài viết của blog vào một nhóm nào đó.

    Cơ mà lần này là liên kết trực tiếp đến trang chủ luôn. Tò mò ghê, không biết ai chia sẻ, chia sẻ ở đâu nữa. Muốn biết để tìm hiểu "insight" ghê 🥹

    » Xem thêm

Vấn đề

Nếu đã quen với một ngôn ngữ lập trình hướng đối tượng từ trước, class là cú pháp rõ ràng nhất để nhận biết cách khai báo một đối tượng mới. JavaScript cũng được coi là một ngôn ngữ lập trình hướng đối tượng, nhưng nếu là một lập trình viên JS đời đầu, cỡ cách đây khoảng chục năm về trước thì JavaScript không hề có cú pháp class, thay vào đó nó hỗ trợ kế thừa thông qua prototype. Cách viết này có phần khác biệt với cú pháp của OOP trong đa số ngôn ngữ lập trình hướng đối tượng, nó cũng không được đánh giá cao về khả năng hỗ trợ nhiều tính năng mạnh mẽ của OOP.

Vài năm trở lại đây, ES6 ra đời mang đến từ khóa class để giúp lập trình viên dễ dàng viết mã theo hướng OOP hơn, hay nói cách khác là thân thiện hơn cho ai đang quen với cú pháp của OOP. Nhưng bản chất đằng sau nó vẫn là sự có mặt của prototype. Bài viết ngày hôm nay chúng ta sẽ cùng nhau tìm hiểu xem prototype là gì mà tại sao nó lại quan trọng trong JavaScript nhé.

Prototypes là gì?

Prototypes là cơ chế mà các đối tượng JavaScript kế thừa các chức năng từ nhau. Mỗi đối tượng được tạo ra từ một hàm tạo đều có một prototype mặc định, đó là prototype của hàm tạo đó.

Mọi đối tượng trong JavaScript đều có các thuộc tính, phương thức được tích hợp sẵn gọi là prototype. Bản thân prototype cũng là một đối tượng, vì vậy prototype sẽ có prototype riêng, tạo nên một chuỗi prototype. Chuỗi này chỉ kết thúc khi prototype bằng null.

Prototypes định nghĩa các thuộc tính và phương thức mà mỗi đối tượng được tạo ra từ hàm tạo đó có thể truy cập được. Khi một đối tượng được tạo ra, nó sẽ kế thừa tất cả các thuộc tính và phương thức từ prototype của hàm tạo.

Ví dụ:

const myObject = {
  name: "2coffee",
  greet() {
    console.log(`Greetings from ${this.name}`);
  },
};

myObject.greet(); // Greetings from 2coffee

Trong ví dụ trên, greet() là một phương thức của myObject, do đó nó có thể gọi phương thức đó. Nhưng ngoài greet() ra, myObject là một Object nên nó kế thừa lại toàn bộ prototype của Object. Các prototype có trong myObject lúc này sẽ trông giống như là:

__defineGetter__
__defineSetter__
__lookupGetter__
__lookupSetter__
__proto__
name
constructor
greet
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
toLocaleString
toString
valueOf

myObject có toàn quyền truy cập vào các prototype này, ví dụ như gọi phương thức toString.

myObject.toString(); // "[object Object]"

Khi cố gắng truy cập một thuộc tính của một đối tượng, nếu không thể tìm thấy thuộc tính trong chính đối tượng đó, nó sẽ chuyển sang tìm kiếm trong prototype của đối tượng cha. Cứ thế cho đến khi tìm thấy thuộc tính hoặc kết thúc chuỗi kế thừa mà trả về giá trị undefined.

Ví dụ với một đối tượng Date trong JavaScript. Date là một instance của Object, Date cũng có prototype riêng nên một đối tượng được tạo mới từ Date sẽ có ít nhất 3 lớp prototype.

prototype trong đối tượng Date

Sử dụng Prototypes để làm gì?

Như tôi đã nói ở trên, prototype sinh ra cho mục đích kế thừa như trong lập trình hướng đối tượng. Việc sử dụng prototype trong JavaScript cho phép ta thêm các thuộc tính và phương thức vào các đối tượng trong một cách hiệu quả hơn. Thay vì tạo các phương thức và thuộc tính cho từng đối tượng, ta có thể thêm chúng vào prototype của hàm tạo, do đó tất cả các đối tượng được tạo ra từ hàm tạo đó đều có thể truy cập đến chúng.

Ví dụ cho một chương trình khai báo lớp Geometry với hai phương thức calculatePerimeter (tính chu vi) và calculateArea (tính diện tích). Hai lớp SquareCircle kế thừa từ Geometry thông qua prototype được viết như sau:

// Khai báo lớp Geometry
function Geometry() {}

// Phương thức tính chu vi
Geometry.prototype.calculatePerimeter = function() { return; }

// Phương thức tính diện tích
Geometry.prototype.calculateArea = function() { return; }

// Khai báo lớp Square kế thừa từ Geometry
function Square(sideLength) {
  this.sideLength = sideLength;
}

Square.prototype = Object.create(Geometry.prototype);
Square.prototype.constructor = Square;

// Override phương thức tính chu vi cho Square
Square.prototype.calculatePerimeter = function() {
  return this.sideLength * 4;
}

// Override phương thức tính diện tích cho Square
Square.prototype.calculateArea = function() {
  return this.sideLength * this.sideLength;
}

// Khai báo lớp Circle kế thừa từ Geometry
function Circle(radius) {
  this.radius = radius;
}

Circle.prototype = Object.create(Geometry.prototype);
Circle.prototype.constructor = Circle;

// Override phương thức tính chu vi cho Circle
Circle.prototype.calculatePerimeter = function() {
  return 2 * Math.PI * this.radius;
}

// Override phương thức tính diện tích cho Circle
Circle.prototype.calculateArea = function() {
  return Math.PI * this.radius * this.radius;
}

Prototypes và Class

Kể từ ES6, JavaScript mang đến cho chúng ta cú pháp mới để kế thừa. Đó chính là từ khóa class, bằng cách sử dụng mới này, giúp chúng ta quen thuộc hơn với cú pháp giống như lập trình hướng đối tượng từ các ngôn ngữ khác.

Ví dụ cũng là chương trình trên nhưng viết lại bằng class mã sẽ trông gọn gàng hơn rất nhiều:

// Khai báo lớp Geometry
class Geometry {
  calculatePerimeter() { return; }

  calculateArea() { return; }
}

// Khai báo lớp Square kế thừa từ Geometry
class Square extends Geometry {
  constructor(sideLength) {
    super();
    this.sideLength = sideLength;
  }

  calculatePerimeter() {
    return this.sideLength * 4;
  }

  calculateArea() {
    return this.sideLength * this.sideLength;
  }
}

// Khai báo lớp Circle kế thừa từ Geometry
class Circle extends Geometry {
  constructor(radius) {
    super();
    this.radius = radius;
  }

  calculatePerimeter() {
    return 2 * Math.PI * this.radius;
  }

  calculateArea() {
    return Math.PI * this.radius * this.radius;
  }
}

class có từ ES6, tuy nhiên nó vẫn có nhiều hạn chế so với OOP trong các ngôn ngữ thuần hướng đối tượng khác như Java, C#... Một phần là do bản chất của class vẫn là dựa trên prototype, có điều nó tạo ra để giảm sự phức tạp của mã, giúp mã dễ đọc và gọn gàng hơn.

Tầm quan trọng của Prototypes

Prototypes là một khái niệm rất quan trọng trong JavaScript vì nó cho phép ta tạo ra các đối tượng với tính kế thừa và sử dụng lại mã nguồn một cách hiệu quả.

Các đối tượng được tạo ra từ cùng một hàm tạo đều có thể chia sẻ các thuộc tính và phương thức được định nghĩa trong prototype của hàm tạo đó. Điều này giúp giảm sự trùng lặp trong mã nguồn và tiết kiệm bộ nhớ cho ứng dụng.

Nếu để ý, bạn sẽ thấy gần như mọi thứ trong JavaScript đều xuất phát từ prototype. Tạo ra một object mới, nó sẽ kế thừa toàn bộ prototype từ Object, tạo ra một function, nó sẽ kế thừa toàn bộ prototype từ Function...

prototype của object

Ngoài ra, việc sử dụng prototype cũng cho phép ta tạo các đối tượng con kế thừa các thuộc tính và phương thức từ đối tượng cha. Điều này giúp tăng tính tái sử dụng trong mã nguồn, giảm thiểu sự trùng lặp và tăng tính bảo trì của ứng dụng.

Thêm vào đó, prototype cũng cung cấp một cách để mở rộng các đối tượng có sẵn trong JavaScript. Bằng cách thêm các thuộc tính và phương thức vào prototype của đối tượng, ta có thể mở rộng tính năng của đối tượng đó mà không cần thay đổi mã nguồn gốc.

Do đó, prototype là một khái niệm quan trọng trong JavaScript và là một trong những cách để tăng tính linh hoạt, hiệu quả và bảo trì sau này.

Tổng kết

Prototypes là cơ chế mà các đối tượng JavaScript kế thừa các chức năng từ nhau. Lập trình viên đời đầu phải viết mã kế thừa dựa trên prototype. Vài năm trở lại đây, ES6 ra đời mang đến cú pháp class giúp việc viết mã trở nên thân thiện hơn khi giờ đây các cú pháp của nó gần với ngôn ngữ hướng đối tượng hơn. Prototypes là một khái niệm quan trọng trong JavaScript, hầu như mọi thứ đều dựa trên prototype để hoạt động như Object, Function... vì thế hiểu rõ bản chất của Prototypes sẽ giúp cho việc học hỏi thêm kiến thức sau này.

Tài liệu tham khảo:

Cao cấp
Hello

Bí mật ngăn xếp của Blog

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...
Bấm hoặc cuộn mạnh để sang bài mới