Prototype là gì? Cách thiết lập Prototype
Prototype là khái niệm cốt lõi trong JavaScript và là cơ chế quan trọng trong việc thực thi mô hình OOP trong JavaScript (nhưng không thực sự không hoàn chỉnh như trong các ngôn ngữ class-based khác), vì như đã biết, trong JavaScript, không có khái niệm class như các ngôn ngữ hướng đối tượng khác như Java hay C#. Bài viết này Bizfly Cloud sẽ trình bày sơ lược về khái niệm này.
Prototype là gì?
Prototype là một dạng cơ chế có trong Javascript. Đây là một trong những hệ lập trình điển hình giúp mọi người tạo nên một trang web theo yêu cầu. Trong hệ lập trình này Prototype được sử dụng để thực hành mô hình OPP.
Với Prototype người dùng sẽ tạo được sự kế thừa trong Javascript thông qua các object khác. Mỗi Prototype sẽ đi kèm với một object riêng để chúng có thể kế thừa thuộc tính cũng như các phương thức đi kèm.
Với những lập trình viên mới có thể tạm hiểu một cách đơn giản là bản thân Prototype chính là một Object trong Javascript. Tuy nhiên nó thuộc phân loại đối tượng Prototype để phân biệt thuộc tính riêng của Prototype trong Function.
Khi sử dụng Prototype trong JavaScript các bạn có thể định nghĩa được các thuộc tính đồng thời chia sẻ chúng giữa nhiều đối tượng khác nhau. Qua đó giúp bộ nhớ được tiết kiệm đáng kể và tốc độ thực thi của chương trình cũng sẽ được cải thiện đáng kể.
Ngoài ra ngôn ngữ này cũng cho phép lập trình viên thêm các thuộc tính và phương thức mới vào Prototype của chúng. Nhờ đó việc mở rộng các đối tượng có sẵn sẽ dễ dàng và linh hoạt hơn.
Prototype cho phép người dùng tái sử dụng code đồng thời tạo thành cơ sở kế thừa Object trong JavaScript. Nhờ vậy người dùng có thể khắc phục tình trạng bộ nhớ dư thừa và quản lý nó hiệu quả hơn.
Tìm hiểu cách hoạt động của Prototype trong Javascript
Việc hiểu rõ cách thức hoạt động của Prototype sẽ giúp mọi người nắm được bản chất của nó để sử dụng sao cho phù hợp. Theo đó Prototype trong Javascript hoạt động theo 2 cách thức cơ bản như sau:
Bổ sung các thuộc tính cho đối tượng
Bước đầu tiên trong công việc lập trình viên sẽ khởi tạo các Object dựa vào các hàm Construction thông dụng. Sau khi hàm được khởi tạo thành công sẽ thêm thuộc tính Prototype cho hàm đó. Lúc này thuộc tính sẽ trỏ đến Prototype Object và được xử lý rồi trả về một Instance tương ứng.
Tìm kiếm Prototype Property
Bên cạnh khả năng bổ sung thuộc tính cho đối tượng thì ngôn ngữ này còn có vai trò tìm kiếm Prototype property tự động những thuộc tính được yêu cầu. Kết quả sẽ được trả về ngay lập tức nếu như những thuộc tính đó đang tồn tại.
Nếu thuộc tính không tồn tại thì sẽ tiến hành kiểm tra những đối tượng nguyên mẫu hoặc kế thừa. Sau khi rà soát thành công sẽ trả về kết quả về thông tin thuộc tính cần tìm. Nếu nó vẫn không tồn tại thì kết quả tìm kiếm sẽ là undefined.
Prototype của object
Để dễ hiểu, chúng ta xem xét function sau:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Khi Function Person được tạo, mặc định nó sẽ có một Property có tên là Prototype (lưu ý là function trong JavaScript cũng là một Object). Property này là một Object mà ban đầu chỉ có chứa một Property là Constructor trỏ ngược lại function Person. Và khi function Person này được gọi với từ khóa New, Object mới được tạo sẽ kế thừa tất cả các Property từ Peron.prototype. Để kiểm tra, chúng ta thêm vào Person.prototype một Method là showFullName() như sau:
Person.prototype.showFullName = function() {
console.log(this.firstName ' ' this.lastName);
}
var justin = new Person('Justin', 'Vo');
console.log(justin); // Person {firstName: "Justin", lastName: "Vo"}
justin.showFullName(); // Justin Vo
Người ta còn gọi Person.prototype là Prototype Object hay gọn hơn là Prototype của Object Justin, cũng như bất kì Object nào được tạo với cú pháp new Person(...).
var david = new Person('David', 'Truong');
console.log(david); // Person {firstName: "David", lastName: "Truong"}
david.showFullName(); // David Truong
Thật ra chúng ta có thể khai báo Method showFullName() ngay bên trong function Person. Tuy nhiên, do Method showFullName() là giống nhau ở mọi Object, nên chúng ta đưa nó lên Person.prototype để các object kế thừa lại (nguyên lý Don't Repeat Yourself - DRY). Và đó cũng là một trong số các Best Practice trong JavaScript: constructor chỉ khởi tạo các Property riêng biệt cho mỗi Object được tạo, còn các Method áp dụng chung cho mọi Object sẽ được tạo ở Prototype.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.friends = [];
}
Person.prototype.showFullName = function() {
console.log(this.firstName ' ' this.lastName);
}
Person.prototype.addFriend = function(friend) {
this.friends.push(friend);
}
var vancanh = new Person('Canh', 'Dinh');
var justin = new Person('Justin', 'Vo');
var micheal = new Person('Micheal', 'Huynh');
console.log(vancanh.friends); // [];
vancanh.addFriend(justin);
vancanh.addFriend(micheal);
console.log(vancanh.friends); // [Person, Person]
Các Object mặc định có sẵn trong JavaScript cũng được xây dựng theo cách tương tự như trên. Ví dụ, Prototype của các Object được tạo với cú pháp New Object() hoặc {} là Object.prototype, các Array được tạo với cú pháp New Array() hoặc [] là Array.prototype và tương tự như thế cho các Object khác như RegExp hay Date. Object.prototype được kế thừa bởi mọi Object và bản thân nó không có Prototype (nói cách khác, prototype của nó là null).
Thực tế thì chúng ta không thể truy cập được Prototype của một Object và cũng không cần thiết phải dùng đến nó, tuy nhiên, chẳng hạn như trong Chrome, nó cho phép chúng ta truy cập vào Prototype của một Object thông qua một property "giả" là __proto__.
Prototype chain
Cơ chế Prototype Chain rất đơn giản: khi chúng ta truy cập vào một Property của một Object, JavaScript Engine sẽ tìm Property đó bên trong chính Object, nếu không có nó sẽ tìm lên trên Prototype của Object và cứ tiếp tục như thế cho đến khi gặp Object.prototype thì dừng và cho ra kết quả (undefined nếu không tìm thấy).
Ví dụ:
var obj1 = { a: 1 };
var obj2 = Object.create(obj1);
obj2.b = 2;
console.log(obj1.a); // 1
console.log(obj2.a); // 1
console.log(obj2.b); // 2
console.log(obj2.c); // undefined
Trong ví dụ trên, Object.create() sẽ tạo một Object mới Obj2 với Prototype là obj1. Và như đã thấy, mặc dù Obj2 không có Property a, nhưng chúng ta vẫn có thể truy cập nó nhờ vào cơ chế Prototype Chain.
Các cách thiết lập Prototype trong Javascript
Hiện nay để thiết lập Prototype trong Javascript lập trình viên sẽ sử dụng Constructor hoặc Object.create. Bạn có thể tham khảo hướng dẫn sau đây để thử nghiệm cho công việc của mình.
1. Cách 1: Sử dụng Constructor
Constructor là hàm tạo đối tượng được sử dụng khá phổ biến để thiết lập Prototype. Tất cả các hàm trong JavaScript đều có thuộc tính được gọi là Prototype. Theo quy nước trong thuộc tính có tên Proto thì khi gọi một hàm như một constructor thuộc tính này sẽ được đặt làm Prototype của object mới được tạo.
Điều này có nghĩa là nếu người dùng đặt prototype của một Constructor thì tất cả các Object được tạo đều có thể đảm bảo cung cấp cho Prototype đó.
2. Cách 2: Sử dụng Object.create
Sử dụng Object.create là tính năng đặc biệt của JavaScript nhờ sự linh hoạt và mạnh mẽ trong việc tái sử dụng code cũng như việc liên kết các Object với nhau. JavaScript trong các phiên bản cũ ES5 trở về trước không trang bị khái niệm Class. Đây chính là lý do nó không thể mở rộng ứng dụng cũng như khả năng kế thừa theo ngôn ngữ OPP. Do vậy người dùng cần thiết lập theo cơ chế Prototype-based để thiết lập prototype với Object.create.
Trước tiên lập trình viên cần tạo một hàm trước khi tạo Object.create. Sau đó sẽ tiến hành thêm vào hàm vừa tạo các thuộc tính và phương thức chứa thuộc tính Prototype.
Dựa theo yêu cầu cũng như mong muốn của người dùng Instance sẽ tạo ra các hàm có chứa phương thức, thuộc tính cần tạo. Prototype là công nghệ duy nhất có phương thức kế thừa giúp người dùng dễ dàng mở rộng ngôn ngữ OPP trong JavaScript.
Một số ví dụ về cách sử dụng Prototype cơ bản trong Javascript
Với Prototype người dùng có thể dễ dàng xác định các phương thức cho tất cả các trường hợp của một Object. Phương thức này được áp dụng cho Prototype chỉ được lưu trữ trong bộ nhớ một lần nhưng một Instance bất kỳ của Object đều có quyền truy cập.
Dưới đây là một số ví dụ cụ thể về cách sử dụng Prototype thông thường trong Javascript bạn có thể tham khảo.
Ví dụ 1:
function Pet(name, species){ this.name = name; this.species = species; } function view(){ return this.name + " is a " + this.species + "!"; } Pet.prototype.view = view; var pet1 = new Pet('Alexis', 'Cat'); alert(pet1.view()); //Outputs "Alexis is a Cat!"
Ở ví dụ trong hàm trên mọi người có thể đảm bảo rằng chỉ cần sử dụng Prototype khi đính kèm phương thức xem thì tất cả các Object Pet đều có quyền truy cập. Ngoài ra các bạn cũng có thể tạo ra nhiều hiệu ứng hơn bằng cách sử dụng phương pháp Prototype.
Ví dụ 2:
function Pet(name, species){ this.name = name; this.species = species; } function view(){ return this.name + " is a " + this.species + "!"; } Pet.prototype.view = view; function Cat(name){ Pet.call(this, name, "Cat"); } Cat.prototype = new Pet(); Cat.prototype.bark = function(){ alert("Woof!"); }
Trong hàm này các bạn đã thiết lập object Cat và gọi hàm Pet bằng phương thức call (). Phương thức này cho phép gọi một hàm cụ thể bên trong một đối tượng bằng cách truyền vào đối tượng người dùng muốn chạy hàm. Sau đó mọi người cấp cho Object Cat một phương thức là bark. Khi đó chỉ có các Object Cat mới có quyền truy cập vào.
var pet1 = new Pet('Trudy', 'Dog'); var pet2 = new Cat('Alexis'); alert(pet2.view()); // Outputs "Alexis is a Cat!" pet2.bark(); // Outputs "Meow!" pet1.bark(); // Error
Trước khi gọi pet2.view() bạn cần kiểm tra đối tượng Cat và Pet đã có phương thức xem nào hay chưa. Vì ngôn ngữ này hoạt động theo một chuỗi là Cat kế thừa Pet và Pet kế thừa từ Object.prototype.
Object.prototype.whoAmI = function(){ alert("I am an object!"); } pet1.whoAmI(); //Outputs 'I am a doctor!' pet2.whoAmI(); //Outputs 'I am a doctor!'
Ví dụ 3:
function Belongings(firstName, lastName) { this.firstName = firstName, this.lastName = lastName, this.fullName = function() { return this.firstName + " " + this.lastName; } }
Bây giờ chúng ta tiến hành khởi tạo 2 object person1 và persion2 sử dụng Belongings constructor bằng hàm sau:
var person1 = new Belongings("Kien", "Nguyen"); var person2 = new Belongings("Khai", "Nguyen");
Ví dụ 4:
var bangai = { name: 'Nguyen Thi Mo' } var mebangai = { name: 'me ban gai', pay: function() { console.log('Da mua tui bang tien bo me'); } }; Object.setPrototypeOf(bangai, medaigai); bangai.pay(); //Da mua tui bang tien bo me
Một số lưu ý cần biết để sử dụng Prototype hiệu quả
Muốn sử dụng Prototype thì các bạn cần thành thạo JavaScript và ngược lại. Do vậy khi ứng dụng ngôn ngữ này các bạn cần lưu ý đến một số vấn đề sau:
- Cần có vốn tiếng Anh phong phú vì phần lớn tài liệu trong Prototype đều viết bằng tiếng Anh.
- Hàm trong JavaScript được gọi là một Object và nó có thuộc tính Prototype. Nếu bạn chỉnh thuộc tính Prototype thì Object sẽ mang giá trị rất khác.
- Trong JavaScript các Object có khái niệm là Prototype Attribute sẽ trỏ đến Prototype Object mà chúng kế thừa. Để truy cập vào Prototype Object thì bạn có thể sử dụng các thuộc tính _proto_.
Kết
Mình xin tạm dừng bài viết tại đây vì có lẽ đã khá dài. Trên đây mình đã cố gắng trình bày về Prototype theo cách dễ hiểu. Hi vọng qua bài viết này sẽ giúp bạn hiểu hơn về khái niệm Prototype trong JavaScript.
Theo Bizfly Cloud chia sẻ