Tổng hợp về hướng đối tượng của Javascript
Nguồn: http://ruby-rails.hatenadiary.com/entry/20150311/1426062668 Người dịch: Phạm Cẩm Anh Tác giả là người đã có kinh nghiệm làm các ngôn ngữ hướng đối tượng như Java và PhP từ trước. Bài viết này tác giả muốn giới thiệu đến cho những người chưa hiểu rõ Javascript về hướng đối tượng đặc biệt ...
Nguồn: http://ruby-rails.hatenadiary.com/entry/20150311/1426062668
Người dịch: Phạm Cẩm Anh
Tác giả là người đã có kinh nghiệm làm các ngôn ngữ hướng đối tượng như Java và PhP từ trước. Bài viết này tác giả muốn giới thiệu đến cho những người chưa hiểu rõ Javascript về hướng đối tượng đặc biệt của Javascript.
1. Tạo object
Có thể dùng cặp dấu {} để tạo object.
Ngoài ra cũng có thể dùng toán tử new để tạo một object xác định.
// Cách 1: Tạo object instance bằng {} var obj = {}; // Cách 2: tạo instance bằng new var obj = new Object(); // Object instance var person = new Person(); // Person instance
2. Định nghĩa và gán thuộc tính
Nếu ta set giá trị property cho object, ta có thể set giá trị và định nghĩa property.
var obj = {}; // Nếu property chưa được định nghĩa, sẽ trả về undefined console.log(obj.prop); // => undefined // Khi set giá trị cho property, cũng đồng thời định nghĩa property obj.prop = 1; console.log(obj.prop); // => 1 Khi tạo object, ta có thể thiết lập, định nghĩa property // Có thể định nghĩa, thiết lập property var obj2 = { prop: 1, prop2: 'foo' }; console.log(obj2.prop); // => 1 console.log(obj2.prop2); // => 'foo'
3. Xóa property
Có thể xóa property dùng toán tử delete Sau khi xóa property, nếu dùng property này, sẽ trả về undefined giống như khi property chưa được định nghĩa.
var obj = {}; obj.prop = 1; // Xóa property delete obj.prop; // Khi tham chiếu property, trả về undefined console.log(obj.prop); // => undefined
Đừng xóa property bằng bằng cách gán property bằng undefined vì nếu làm thế thì khi sử dụng vòng lặp for list ra danh sách cá property, sẽ có cả property được set là undefined. Vì thế hãy dùng toán tử delete để xóa property.
4. Accessor property (getter/ setter)
Có thể định nghĩa accessor property bằng hàm get và set
var circle = { radius : 1, // Bán kính get diameter() { return this.radius * 2; }, // Gọi ra đường kính từ bán kính set diameter(value) { this.radius = value / 2; } // Trả ra bán kính từ đường kính }; circle.diameter = 5; // Gọi set diameter console.log(circle.radius); // => 2.5 console.log(circle.diameter); // => 5 (Gọi get diameter)
5. Định nghĩa class
Có thể định nghĩa class của Javascript bằng bằng định nghĩa property trong constructor
// Đinh nghĩa Person class (constructor) var Person = function(name, age) { this.name = name; this.age = age; } // Tạo Person instance var satoshi = new Person('Satoshi', 28); console.log(satoshi.name); // => 'Satoshi' console.log(satoshi.age); // => 28 console.log(satoshi instanceof Person) // => true (satoshi là instance của class Person)
6. Constructor argument
Với Javascript có thể lược bỏ đối số khi gọi hàm. Vì constructor cũng là hàm nên có thể lược bỏ đối số của constructor. Nhưng khi đó, constructor có đối số bị lược bỏ được gọi ra để tạo instance thì sẽ có lỗi property chưa được định nghĩa (undefined).
Có 2 cách giải quyết:
-
Khởi tạo giá trị xác định cho property
-
Ngắt chương trình tạo ra lỗi
Khởi tạo giá trị xác định cho property
var Person = function(name, age) { // Khởi tạo giá trị xác định this.name = name || 'No name'; this.age = age || 20; } // Khi không xác định đối số cho constructor, giá trị khởi tạo được sử dụng var satoshi = new Person(); console.log(satoshi.name); // => 'No name' console.log(satoshi.age); // => 20 // Khi xác định đối số cho constructor, giá tị này được sử dụng var satoshi = new Person('サトシ', 28); console.log(satoshi.name); // => 'サトシ' console.log(satoshi.age); // => 28
Ngắt chương trình tạo ra lỗi
var Person = function(name, age) { // Kiểm tra đối số if (name == undefined) { throw new Error("Please define argument 'name'"); } if (age == undefined) { throw new Error("Please define argument 'age'"); } this.name = name; this.age = age; } // Khi không xác định đối số của constructor, lỗi sẽ xuất hiện var satoshi = new Person(); // => Error: Please define argument 'name'
7. Định nghĩa instance method
Có 2 cách định nghĩa method cho object trong Javascript:
- Gán function cho property
- Sử dụng object đặc chủng prototype
Gán function cho property
var Person = function(name, age) { this.name = name; this.age = age; // Gán function cho property this.greet = function() { console.log('Hello, ' + this.name); } } var satoshi = new Person('サトシ', 20); // Có thể gọi method ra satoshi.greet(); // => 'Hello, サトシ'
Vấn đề của phương pháp này là khi tạo instance bằng cách new Person(...), method greet() cũng được tạo ra nên khi tạo instance, sẽ lãng phí bộ nhớ. Để khắc phục điều này, có thể dùng object đặc chủng là prototype như dưới đây.
Sử dụng object đặc chủng prototype
var Person = function(name, age) { this.name = name; this.age = age; } // Gán method cho tất cả các object property của class Person.prototype.greet = function() { console.log('Hello, ' + this.name); } var satoshi = new Person('サトシ', 20); // Có thể gọi method ra satoshi.greet(); // => 'Hello, サトシ'
Nếu làm thế thì tất cả các instance Person khi tham chiếu đến Person.prototype.greet() nên sẽ không lãng phí bộ nhớ.
Thứ tự xử lý tbên trong Javascript là khi greet() method được gọi ra, đầu tiên sẽ tìm kiếm property được định nghĩa trong Person instance, nếu không tìm thấy sẽ tìm kiếm trong Person.prototype, khi tìm thấy sẽ chạy method greet()
8. Định nghĩa class property và class method
Class method của Javascript có thể được định nghĩa tương tự như định nghĩa class property.
var Person = function(name, age) { this.name = name; this.age = age; } // Định nghĩa class property (hằng số) // Biến lưu giá trị dưới bao nhiêu tuổi thì được gọi là trẻ young Person.YOUNG_LIMIT_AGE = 20; // Đinh nghĩa class method // Nếu là young thì trả về true, ngược lại thì trả về false Person.isYoung = function(age) { if (age <= Person.YOUNG_LIMIT_AGE) { return true; } return false; } // Gọi ra class propety console.log(Person.YOUNG_LIMIT_AGE); // => 20 // Gọi ra class method console.log(Person.isYoung(10)); // => true console.log(Person.isYoung(30)); // => false
Hằng số thường được định nghĩa bởi chữ viết hoa nhưng không có quy định không thể thay đổi như trong Ruby.
9. Kế thừa class
Trong Javascript không có cấu trúc để kế thừa, thực hiện kế thừa bằng cách sau:
- Kế thừa property: goi method apply
- Kế thừa method: sử dụng object prototype
Việc kế thừa class trong Javascript rất phức tạp, với code nhỏ thì không dùng, với code lớn thì dùng các library để kế thừa.
Kế thừa property: goi method apply Trong constructor của sub class, nếu gọi method apply của super class, sub class có thể kế thừa property của super class.
// Person class var Person = function(name, ageavascript) { this.name = name; this.age = age; } // Employee kế thừa Person var Employee = function(name, age, jobTitle) { this.jobTitle = jobTitle; // Gọi constructor của super class Person.apply(this, [name, age]); } var satoshi = new Employee('サトシ', 28, 'QA'); console.log(satoshi.name); // => 'サトシ' console.log(satoshi.age); // => 28 console.log(satoshi.jobTitle); // => 'QA' console.log(satoshi instanceof Employee); // => true
Kế thừa method: sử dụng object prototype
Có thể sử dụng prototype chain của object prototype để kế thừa
// Định nghĩa Person class var Person = function(name, age) { this.name = name; this.age = age; } // Định nghĩa method Person#greet() Person.prototype.greet = function() { console.log('Hello, ' + this.name); } // Đinh nghĩa class Employee kế thừa Person var Employee = function(name, age, jobTitle) { this.jobTitle = jobTitle; // Kế thừa property của Person Person.apply(this, [name, age]); } // Set Person instance bằng prototype chain // Khi gọi method Employee instance, tìm kiếm xem method có trong trong method Person.prototype không Employee.prototype = Object.create(Person.prototype); // Ở phía trên constructor property trở thành Person nên ở đây set lại là Employee Employee.prototype.constructor = Employee; var satoshi = new Employee('サトシ', 28, 'QA'); satoshi.greet(); // => 'Hello, サトシ' console.log(satoshi.constructor); // => Employee constructor ( function(name, age, jobTitle) { ... } )
10. Kế thừa class property và class method
Về cơ bản, trong Javascript không thực hiện kế thừa class property và class method. Ở đây, Sub class sử dụng class property và class method của super class nên nếu kế thừa, các định nghĩa property cần copy xuống sub class nên sẽ bị lặp code.