JavaScript không phải là ngôn ngữ hướng đối tượng dựa trên lớp. Nhưng nó vẫn có cách sử dụng lập trình hướng đối tượng (OOP).
Trong hướng dẫn này, tôi sẽ giải thích OOP và chỉ cho bạn cách sử dụng nó.
Theo Wikipedia, lập trình dựa trên lớp là
một phong cách lập trình hướng đối tượng (OOP) trong đó kế thừa xảy ra thông qua việc xác định các lớp đối tượng, thay vì kế thừa chỉ xảy ra thông qua các đối tượng
Mô hình phổ biến nhất của OOP là dựa trên lớp.
Nhưng như tôi đã đề cập, JavaScript không phải là ngôn ngữ dựa trên phân loại – nó là ngôn ngữ dựa trên nguyên mẫu.
Theo tài liệu của Mozilla:
Một ngôn ngữ dựa trên nguyên mẫu có khái niệm về một đối tượng nguyên mẫu, một đối tượng được sử dụng làm mẫu để từ đó lấy các thuộc tính ban đầu cho một đối tượng mới.
Hãy xem mã này:
let names = {
fname: "Dillion",
lname: "Megida"
}
console.log(names.fname);
console.log(names.hasOwnProperty("mname"));
// Expected Output
// Dillion
// false
biến đối tượng names
chỉ có hai thuộc tính – fname
và lname
. Không có phương pháp nào cả.
Vì vậy, nơi nào hasOwnProperty
đến từ?
Vâng, nó đến từ Object
nguyên mẫu.
Hãy thử ghi nội dung của biến vào bảng điều khiển:
console.log(names);
Khi bạn mở rộng kết quả trong bảng điều khiển, bạn sẽ nhận được điều này:

Lưu ý tài sản cuối cùng – __proto__
? Hãy thử mở rộng nó:

Bạn sẽ thấy một tập hợp các thuộc tính bên dưới Object
người xây dựng. Tất cả các tài sản này đến từ toàn cầu Object
nguyên mẫu. Nếu bạn nhìn kỹ, bạn cũng sẽ nhận thấy ẩn của chúng tôi hasOwnProperty
.
Nói cách khác, tất cả các đối tượng đều có quyền truy cập vào Object
nguyên mẫu của. Họ không sở hữu các thuộc tính này, nhưng được cấp quyền truy cập vào các thuộc tính trong nguyên mẫu.
Các __proto__
tài sản
Điều này trỏ đến đối tượng được sử dụng làm nguyên mẫu.
Đây là thuộc tính trên mọi đối tượng cho phép nó truy cập vào Object prototype
tài sản.
Mọi đối tượng đều có thuộc tính này theo mặc định, thuộc tính này đề cập đến Object Protoype
trừ khi được cấu hình theo cách khác (nghĩa là khi đối tượng __proto__
được trỏ đến một nguyên mẫu khác).
sửa đổi __proto__
tài sản
Thuộc tính này có thể được sửa đổi bằng cách tuyên bố rõ ràng rằng nó nên tham chiếu đến một nguyên mẫu khác. Các phương pháp sau đây được sử dụng để đạt được điều này:
Object.create()
function DogObject(name, age) {
let dog = Object.create(constructorObject);
dog.name = name;
dog.age = age;
return dog;
}
let constructorObject = {
speak: function(){
return "I am a dog"
}
}
let bingo = DogObject("Bingo", 54);
console.log(bingo);
Trong bảng điều khiển, đây là những gì bạn có:

chú ý __proto__
tài sản và speak
phương pháp?
Object.create
sử dụng đối số được truyền cho nó để trở thành nguyên mẫu.
new
từ khóa
function DogObject(name, age) {
this.name = name;
this.age = age;
}
DogObject.prototype.speak = function() {
return "I am a dog";
}
let john = new DogObject("John", 45);
john
‘S __proto__
tài sản được hướng đến DogObject
nguyên mẫu của. Nhưng hãy nhớ, DogObject
nguyên mẫu của là một đối tượng (cặp khóa và giá trị), do đó nó cũng có một __proto__
tài sản đề cập đến toàn cầu Object
nguyên mẫu.
Kỹ thuật này được gọi là CHUỖI NGUYÊN NHÂN.
Lưu ý rằng: các new
cách tiếp cận từ khóa làm điều tương tự như Object.create()
nhưng chỉ làm cho nó dễ dàng hơn vì nó tự động làm một số việc cho bạn.
Và vì thế…
Mọi đối tượng trong Javascript đều có quyền truy cập vào Object
nguyên mẫu của theo mặc định. Nếu được định cấu hình để sử dụng nguyên mẫu khác, hãy nói prototype2
sau đó prototype2
cũng sẽ có quyền truy cập vào nguyên mẫu của Đối tượng theo mặc định, v.v.
Kết hợp đối tượng + chức năng
bạn có thể bối rối bởi thực tế là DogObject
là một hàm (function DogObject(){}
) và nó có các thuộc tính được truy cập bằng một ký hiệu dấu chấm. Điều này được gọi là một chức năng kết hợp đối tượng.
Khi các hàm được khai báo, mặc định chúng được gán rất nhiều thuộc tính kèm theo. Hãy nhớ rằng hàm cũng là đối tượng trong kiểu dữ liệu JavaScript.
Bây giờ, cả lớp
JavaScript đã giới thiệu class
từ khóa trong ECMAScript 2015. Nó làm cho JavaScript giống như một ngôn ngữ OOP. Nhưng nó chỉ là đường tổng hợp đối với kỹ thuật tạo mẫu hiện có. Nó tiếp tục tạo mẫu trong nền nhưng làm cho phần thân bên ngoài trông giống như OOP. Bây giờ chúng ta sẽ xem làm thế nào điều đó có thể xảy ra.
Ví dụ sau đây là cách sử dụng chung của một class
trong JavaScript:
class Animals {
constructor(name, specie) {
this.name = name;
this.specie = specie;
}
sing() {
return `${this.name} can sing`;
}
dance() {
return `${this.name} can dance`;
}
}
let bingo = new Animals("Bingo", "Hairy");
console.log(bingo);
Đây là kết quả trong bảng điều khiển:

Các __proto__
tài liệu tham khảo Animals
nguyên mẫu (từ đó tham chiếu đến Object
nguyên mẫu).
Từ đó, chúng ta có thể thấy rằng hàm tạo xác định các tính năng chính trong khi mọi thứ bên ngoài hàm tạo (sing()
và dance()
) là các tính năng thưởng (nguyên mẫu).
Trong nền, sử dụng new
cách tiếp cận từ khóa, ở trên dịch là:
function Animals(name, specie) {
this.name = name;
this.specie = specie;
}
Animals.prototype.sing = function(){
return `${this.name} can sing`;
}
Animals.prototype.dance = function() {
return `${this.name} can dance`;
}
let Bingo = new Animals("Bingo", "Hairy");
phân lớp
Đây là một tính năng trong OOP trong đó một lớp kế thừa các tính năng từ lớp cha nhưng sở hữu các tính năng bổ sung mà lớp cha không có.
Ví dụ, ý tưởng ở đây là bạn muốn tạo một những con mèo lớp. Thay vì tạo lớp từ đầu – nêu rõ Tên, lứa tuổi và loài thuộc tính một lần nữa, bạn sẽ kế thừa những thuộc tính đó từ cha mẹ loài vật lớp.
Cái này những con mèo lớp sau đó có thể có các thuộc tính bổ sung như màu râu.
Hãy xem cách các lớp con được thực hiện với class
.
Ở đây, chúng ta cần một cha mẹ mà lớp con kế thừa từ đó. Kiểm tra đoạn mã sau:
class Animals {
constructor(name, age) {
this.name = name;
this.age = age;
}
sing() {
return `${this.name} can sing`;
}
dance() {
return `${this.name} can dance`;
}
}
class Cats extends Animals {
constructor(name, age, whiskerColor) {
super(name, age);
this.whiskerColor = whiskerColor;
}
whiskers() {
return `I have ${this.whiskerColor} whiskers`;
}
}
let clara = new Cats("Clara", 33, "indigo");
Với những điều trên, chúng tôi nhận được các kết quả đầu ra sau:
console.log(clara.sing());
console.log(clara.whiskers());
// Expected Output
// "Clara can sing"
// "I have indigo whiskers"
Khi bạn đăng nội dung của clara ra trong bảng điều khiển, chúng ta có:

Bạn sẽ nhận thấy rằng clara
có một __proto__
thuộc tính tham chiếu hàm tạo Cats
và có quyền truy cập vào whiskers()
phương pháp. Cái này __proto__
tài sản cũng có một __proto__
thuộc tính tham chiếu hàm tạo Animals
nhờ đó có được quyền truy cập vào sing()
và dance()
. name
và age
là những thuộc tính tồn tại trên mọi đối tượng được tạo từ this.
Sử dụng Object.create
phương pháp tiếp cận, ở trên chuyển thành:
function Animals(name, age) {
let newAnimal = Object.create(animalConstructor);
newAnimal.name = name;
newAnimal.age = age;
return newAnimal;
}
let animalConstructor = {
sing: function() {
return `${this.name} can sing`;
},
dance: function() {
return `${this.name} can dance`;
}
}
function Cats(name, age, whiskerColor) {
let newCat = Animals(name, age);
Object.setPrototypeOf(newCat, catConstructor);
newCat.whiskerColor = whiskerColor;
return newCat;
}
let catConstructor = {
whiskers() {
return `I have ${this.whiskerColor} whiskers`;
}
}
Object.setPrototypeOf(catConstructor, animalConstructor);
const clara = Cats("Clara", 33, "purple");
clara.sing();
clara.whiskers();
// Expected Output
// "Clara can sing"
// "I have purple whiskers"
Object.setPrototypeOf
là một phương thức có hai đối số – đối tượng (đối số thứ nhất) và nguyên mẫu mong muốn (đối số thứ hai).
Từ những điều trên, các Animals
hàm trả về một đối tượng với animalConstructor
như nguyên mẫu. Các Cats
hàm trả về một đối tượng với catConstructor
như nó là nguyên mẫu. catConstructor
mặt khác, được đưa ra một nguyên mẫu của animalConstructor
.
Do đó, động vật bình thường chỉ có quyền truy cập vào animalConstructor
nhưng mèo có quyền truy cập vào catConstructor
và animalConstructor
.
kết thúc
JavaScript tận dụng bản chất nguyên mẫu của nó để chào đón các nhà phát triển OOP đến với hệ sinh thái của nó. Nó cũng cung cấp những cách dễ dàng để tạo nguyên mẫu và sắp xếp dữ liệu liên quan.
Các ngôn ngữ OOP thực sự không thực hiện tạo mẫu trong nền – chỉ cần lưu ý điều đó.
Xin chân thành cảm ơn khóa học của Will Sentance về Frontend Masters – JavaScript: The Hard Part of Object Oriented JavaScript. Tôi đã học được mọi thứ bạn thấy trong bài viết này (cộng với một chút nghiên cứu bổ sung) từ khóa học của anh ấy. Bạn nên kiểm tra xem nó ra.
Bạn có thể đánh tôi trên Twitter tại iamdillion cho bất kỳ câu hỏi hoặc đóng góp.
Cảm ơn vì đã đọc : )