+7

Prototype trong JavaScript

Ở thời kì thịnh hành ES6, Babel,... những từ khóa như Class, constructors, static,... đều đã có trong JS nhưng thực sự OOP trong JS nó có thực sự giống như các ngôn ngữ OOP khác như Java hay PHP không?

Bài viết này, ta sẽ quay về thời ES5 trở về trước, lúc đó Prototype đang xưng hùng xưng bá...

Tuy nhiên để câu chuyện trở nên mượt mà hơn, trước tiên, hãy nói chuyện về thằng Object.

Nothing is true, Everything is Object

Trong JS, mọi thứ đều xoay quanh Object.

Có những kiểu Number, String, Boolean,... thậm chí cũng có thể chuyển sang dạng Object (confused)

Class ư, ví dụ viết một Class bằng cú pháp ES6 nhé:

class Employee {
    setName (name) {
        this.name = name;
    }
    getName () {
        return this.name;
    }
    setAge (age) {
        this.age = age;
    }
    getAge () {
        return this.age;
    }
};

Cú pháp rất rõ ràng và chuẩn OOP đúng không? Nhưng thực ra bản chất của nó vẫn chỉ chỉ là một Object =))

var employee = {
    name: null,
    age: null,
    setName: function (name) {
        this.name = name;
    },
    getName: function () {
        return this.name;
    },
    setAge: function (age) {
        this.age = age;
    },
    getAge: function () {
        return this.age;
    }
};

Ở đây điều mình muốn nói đến chính là JS cũng được coi là một ngôn ngữ OOP, tuy nhiên thay vì OOP dạng Class-based như JAVA hay PHP (Sử dụng Class là khuôn mẫu cho các ObjectClass có thể kế thừa từ Class khác), thì JS được coi là ngôn ngữ OOP dạng Prototype-based (Prototype là khuôn mẫu cho các ObjectPrototype có thể kế thừa từ Prototype khác).

Ơ tự nhiên đang Object lại có Prototype lạ lạ @@ Vậy Prototype là gì (??)

Prototype

Mỗi Object trong JS là một tập hợp các thuộc tính (property) và trong số những thuộc tính đó có chứa 1 thằng được gọi là Prototype.

Và không có gì thay đổi, Prototype đó cũng là một Object (facepalm) vì vậy nó cũng có Prototype... Người ta gọi đó là một chuỗi Prototype (Prototype chain). Chuỗi này là hữu hạn, cuối cùng của chuỗi Prototype đó là trùm cuối Object.Prototype.

var viblo = {};

__proto__ ở trong hình chính là proptotype.

Đây có thể coi như 1 cách trình duyệt public ra để bạn truy cập vào Prototype của Object.

Kế thừa qua Prototype

Bài viết này đang hướng ngược lại thời kì trước đây, khi ES6 chưa xuất hiện hay những thư viện cồng kềnh chưa được sử dụng. Vì vậy việc kế thừa qua Prototype là một vấn đề quan trọng khi nói JS là ngôn ngữ OOP.

Có thể hiểu Prototype của Object chính là khuôn mẫu, hay là sư phụ của Object cho dễ hiểu.

Mỗi khi gọi đến một thuộc tính của thằng Object để nhờ làm việc,JS sẽ tìm trong Object xem có không, nếu không thì tìm đến thằng sư phụ.
Đấy là lí do mà có thể sử dụng những hàm như hasOwnProperty để kiểm tra xem thuộc tính đó có tồn tại trong Object hay không vì thằng sư tổ Object.prototype đã có rồi.

var viblo = {};

viblo.hasOwnProperty('abc'); // false

Nếu thằng sư phụ hay sư tổ mà cũng không thể thực hiện được, lúc này việc cần làm là dạy cho 1 sư nào đó cách thực hiện để tất cả những đệ tử tầng dưới có thể làm theo =)) Ví dụ sư phụ chưa biết bay, ta sẽ cho sư phụ học bay, và các đệ tử tầng dưới được kế thừa lại những tinh hoa từ sư phụ:

// Sử dụng Object literal
var sensei = {
    fly: function () {
        console.log('Can Fly');
    }
};

var senpai = {
    __proto__: sensei
};

var kohai = {
    __proto__: senpai
};

senpai.fly(); // Can Fly
kohai.fly(); // Can Fly

Hoặc:

//  Sử dụng Constructor Function
var Sensei = function () {
    this.fly = function () {
        console.log('Can Fly');
    };
    
    return this;
};

var Senpai = function () { 
    // 
};

Senpai.prototype = new Sensei();

var kohai = new Senpai();

kohai.fly(); // Can Fly

Khi tạo Object bằng cách gọi new Senpai() thì prototype của kohaiSenpai.prototype. Và nếu muốn thêm function cho các Object đệ tử thì chỉ cần thêm 1 lần vào prototype là được.

 Sensei.prototype.fight = function () {
     console.log('Can Fight');
 }
 
 var kohai = new Sensei();
 kohai.fight(); // Can Fight

Tuy nhiên nếu tự dưng có thằng đệ tử do được bố mẹ năn nỉ xin cho học nhưng thấy nó tư chất si đa không muốn dạy cho một thân bản lãnh thì lúc đấy đành bí mật phong bế nó trước vậy =))

var phevat = Object.create(null);

Sensei.prototype.taichi = function() {
  console.log('Can Taichi');
}

phevat.taichi(); // TypeError: phevat.taichi is not a function

Ý nghĩa của Prototype

Từ phiên bản ES5 trở về trước, JS không hề có khái niệm Class, vấn đề này mình có đá qua vài lần ở trên kia rồi, vậy nên việc kế thừa giống các ngôn ngữ OOP khác trong JS cũng không thể thực hiện được như bình thường. Và Prototype là người hùng giúp ta có thể thực hiện được việc kế thừa. Vậy nên mới nói việc kế thừa của JS là Prototype-based, còn trong các ngôn ngữ OOP khác là Class-based.

Kết luận

Tất cả những kiến thức trên thực ra áp dụng vào thời điểm này có vẻ hơi ít vì sự mạnh mẽ của ES6 và Babel, tuy nhiên mình thực sự mong qua bài viết này khi sử dụng OOP trong JS bạn sẽ hiểu thêm được phần nào cách hoạt động và sự hơi liên quan với OOP trong các ngôn ngữ khác. Cám ơn đã theo dõi!

Tham khảo:

https://viblo.asia/p/object-oriented-programming-in-javascript-its-really-about-object-DXOGRZdBGdZ

https://viblo.asia/p/javascript-prototype-ByEZk9Wx5Q0

https://toidicodedao.com/2016/02/02/series-javascript-sida-po-ro-to-tai-prototype-la-cai-gi/

https://kipalog.com/posts/prototype-la-khi-gi-


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí