Trong bài viết trước chúng ta đã xem xét các đối tượng trong JavaScript, bài viết này sẽ nói về những cú pháp căn bản của chúng và sẽ được tiếp xúc lại với một số đặc tính đã được biết đến trước đây, thật ra nhiều đặc tính bạn đã xử lý trước đó với các đối tượng thực.
Điều kiện tiên quyết: Có khả năng sử dụng máy tính căn bản, hiểu biết cơ bản về HTML và CSS, đã làm quen với các khái niệm căn bản trong JavaScript (Xem lại các First Step và Building block).
Mục tiêu: Hiểu các lý thuyết căn bản về lập trình hướng đối tượng nói chung và trong JavaScript nói riêng (trong JavaScript, “hầu hết mọi thứ đều là các đối tượng”), và cách thức để bắt đầu làm việc với các đối tượng trong JavaScript.
Căn bản về đối tượng
Một đối tượng là một tập hợp có liên quan với nhau giữa dữ liệu và\hoặc các chức năng (việc này thường được thể hiện với các biến và hàm – chúng được gọi là các thuộc tính và phương thức khi được đưa và trong các đối tượng.) Hãy làm việc với một ví dụ để thấy rõ được điều này.
Đầu tiên bạn hãy sao chép tệp oojs.html. Tệp này chứa phần tử (thẻ) <script> để viết mã JavaScript, và thẻ <input> để chúng ta nhập các hướng dẫn mẫu khi trang được hiển thị, một vài biến được khai báo và một hàm để hiển thị trong thẻ <p> bất cứ mã nào được nhập vào <input>. Chúng ta sẽ sử dụng cách này để khám phá các chú pháp căn bản của đối tượng.
Giống như nhiều thứ trong JavaScript, tạo một đối tượng thường bắt đầu bằng việc định nghĩa và khởi tạo một biến. Thử nhập dòng lệnh JavaScript sau vào trong tệp của bạn, sau đó lưu lại và tải lại trang trên trình duyệt:
[sourcecode language=”javascript”]
var person = {};
[/sourcecode]
Nếu bạn nhập person vào trong ô nhập văn bản (<input>) và bấm nút, bạn sẽ có kết quả như sau:
[sourcecode language=”javascript”]
[object Object]
[/sourcecode]
Chúc mừng bạn, bạn vừa tạo ra đối tượng đầu tiên đấy. Tốt rồi! Nhưng đó chỉ là một đối tượng rỗng, do đó chúng ta không thể làm được gì thêm với nó. Hãy cập nhật đối tượng của chúng ta như sau:
[sourcecode language=”javascript”]
var person = {
name: [‘Bob’, ‘Smith’],
age: 32,
gender: ‘male’,
interests: [‘music’, ‘skiing’],
bio: function() {
alert(this.name[0] + ‘ ‘ + this.name[1] + ‘ is ‘ + this.age + ‘ years old. He likes ‘ + this.interests[0] + ‘ and ‘ + this.interests[1] + ‘.’);
},
greeting: function() {
alert(‘Hi! I\’m ‘ + this.name[0] + ‘.’);
}
};
[/sourcecode]
Sau đó lưu tệp tin và tải lại trang trên trình duyệt, thử nhập gi đó vào giống như dưới đây vào ô văn bản trên trang:
[sourcecode language=”javascript”]
person.name[0]
person.age
person.interests[1]
person.bio()
person.greeting()
[/sourcecode]
Giờ bạn đã có một chút dữ liệu và chức năng cho đối tượng của mình, chúng ta giờ đã có thể truy xuất chúng qua một vài cú pháp khá đơn giản!
Lưu ý: Nếu bạn đáng có vấn đề với công việc này, hãy thử so sáng mã của bạn với mã của chúng tôi ở trong tệp oojs-finished.html (hoặc quan sát nó chạy trực tiếp tại đây). Một lỗi phổ biến khi bạn bắt đầu với các đối tượng là đặt dấu phẩy ở cuối dòng lệnh – điều này sẽ gây ra lỗi.
Thế chuyện gì đang diễn ra ở đây vậy? À, một đối tượng được tạo ra từ nhiều thành phần, mỗi thành phần đều có tên (VD name và age như ở trên), và giá trị (VD [‘Bob’, ‘Smith’] và 32). Mỗi cặp tên/giá trị phải phân tách nhau bởi một dấu phẩy, và cặp tên/giá trị phân cách bởi dấu hai chấm (“:”). Cú pháp như sau:
[sourcecode language=”javascript”]
var objectName = {
member1Name: member1Value,
member2Name: member2Value,
member3Name: member3Value
}
[/sourcecode]
Mỗi thành phần thuộc đối tượng có thể có bất kỳ giá trị gì – với đối tượng person ở trên chúng ta có giá trị của các thuộc tính (thành phần) của đối tượng này là một chuỗi, một số, hai mảng và hai hàm. Bốn thành phần đầu là các thành phần dữ liệu, và được gọi là các thuộc tính (property) của đối tượng. Hai thành phần sau là các hàm, nó cho phép đối tượng thao tác với các thành phần dữ liệu (thuộc tính) và được gọi là các phương thức (method).
Một đối tượng như vậy được gọi là Hằng Đối tượng (object literal) – chúng ta đã định nghĩa các thành phần, nội dung của đối tượng ngay khi tạo ra nó. Điều này trái ngược với việc khởi tạo ra các đối tượng từ các lớp (class), cách mà chúng ta sẽ tìm hiểu sau.
Đây là các thông thường được sử dụng để tạo ra một hằng đối tượng khi bạn muốn chuyển giao một loạt các thành phần dữ liệu có cấu trúc và có quan hệ với nhau theo một ngữ cảnh nào đó, ví dụ như gửi một yêu cầu tới server để đưa vào trong một cơ sở dữ liệu. Việc gửi một đối tượng sẽ hiệu quả hơn nhiều so với việc gửi các thành phần độc lập, và nó cũng dễ dàng hơn việc sử dụng mảng, khi bạn muốn định nghĩa các thành phần độc lập bằng các tên gọi.
Ký hiệu chấm (dấu “.”)
Ở trên, bạn đã sử dụng dấu chấm (“.”) để truy xuất các thuộc tính và phương thức của đối tượng. Tên của đối tượng (person) giống như một namespace (không gian tên) – phải được viết trước dấu chấm để có thể truy xuất vào bất cứ thành phần nào được bao gói (encapsulated) bên trong đối tượng. Sau dấu chấm là tên của thành phần bạn muốn truy xuất – đơn giản có thể là tên một thuộc tính, một thành phần tử của một thuộc tính dạng mảng, hoặc gọi đến một trong số các phương thức của đối tượng, VD:
[sourcecode language=”javascript”]
person.age
person.interests[1]
person.bio()
[/sourcecode]
Sub-namespaces (không gian tên phụ)
Bạn có thể khởi tạo giá trị cho một thành phần của một đối tượng khác. Ví dụ, thử thay đổi tên thành phần của đối tượng từ
[sourcecode language=”javascript”]
name: [‘Bob’, ‘Smith’],
[/sourcecode]
thành
[sourcecode language=”javascript”]
name : {
first: ‘Bob’,
last: ‘Smith’
},
[/sourcecode]
Để làm việc này chúng ta tạo ra một sub-namespace (không gian tên phụ). Điều này nghe có vẻ phức tạp, nhưng thực tế không như vậy – để truy xuất các thành phần đó bạn chỉ cần bổ sung thêm một dấu chấm (“.”) sau đó. Ví dụ:
[sourcecode language=”javascript”]
person.name.first
person.name.last
[/sourcecode]
Lưu ý: Với việc này bạn cần thay đổi mã trong phương thức của đối tượng person, tất cả những chỗ đang viết là
[sourcecode language=”javascript”]
name[0]
name[1]
[/sourcecode]
được thay bằng
[sourcecode language=”javascript”]
name.first
name.last
[/sourcecode]
Nếu không phương thức của đối tượng sẽ không hoạt động được nữa.
Cặp ngoặc vuông (“[]”)
Để truy xuất các thuộc tính của đối tượng bạn có thể dụng cặp ngoặc vuông (“[]”) thay cho dấu chấm (“.”):
[sourcecode language=”javascript”]
person.age
person.name.first
[/sourcecode]
Bạn có thể dùng
[sourcecode language=”javascript”]
person[‘age’]
person[‘name’][‘first’]
[/sourcecode]
Đây là cách khá giống với cách bạn dùng truy xuất các phần tử của một mảng, và căn bản nó là như vậy – thay vì sử dụng chỉ số để truy xuất phần tử giống như mảng, với cách này bạn sử dụng tên để thao tác với giá trị của mỗi thành phần. Bạn sẽ chẳng ngạc nhiên khi các đối tượng đó đôi khi được gọi là associative array (mảng kết hợp) – chúng ánh xạ (map) các chuỗi với các giá trị giống như cách mảng ánh xạ các con số với các giá trị.
Thiết lập các thành phần của đối tượng
Từ đầu tới giờ chúng ta chỉ thảo luận về cách lấy ra (getting) các thành phần của đối tượng – bạn cũng có thể thiết lập (set), cập nhật giá trị cho các thành phần đó bằng cách viết tên thành phần (thuộc tính, phương thức) bạn muốn thiết lập sau dấu chấm hoặc cặp ngoặc vuông, VD:
[sourcecode language=”javascript”]
person.age = 45;
person[‘name’][‘last’] = ‘Cratchit’;
[/sourcecode]
Thử viết các dòng mã trên và sau đó lấy ra giá trị của các thuộc tính để quan sát sự thay đổi của chúng:
[sourcecode language=”javascript”]
person.age
person[‘name’][‘last’]
[/sourcecode]
Thiết lập các thành phần cho đối tượng không chỉ dừng lại ở việc cập nhật giá trị cho các thuộc tính, phương thức đã tồn tại mà bạn còn có thể tạo ra các thành phần mới cho đối tượng. Hãy thử các dòng lệnh sau:
[sourcecode language=”javascript”]
person[‘eyes’] = ‘hazel’;
person.farewell = function() { alert("Bye everybody!"); }
[/sourcecode]
Bạn có thể kiểm tra các thành phần vừa thêm mới này (một thuộc tính và một phương thức):
[sourcecode language=”javascript”]
person[‘eyes’]
person.farewell()
[/sourcecode]
Một lợi ích khác của cặp ngoặc vuông là nó không chỉ được sử dụng cho việc thiết lập linh động các giá trị của thành phần trong đối tượng mà còn thiết lập linh động cho tên của các thành phần. Giả sử chúng ta muốn người dùng có thể lưu trữ các loại giá trị tùy chọn cho dữ liệu người của họ, bằng cách viết tên và giá trị của thành phần vào hai ô văn bản? Chúng ta có thể nhận được những giá trị đó như thế này:
[sourcecode language=”javascript”]
var myDataName = nameInput.value;
var myDataValue = nameValue.value;
[/sourcecode]
chúng ta có thể thêm thành phần mới này với tên và giá trị cho đối tượng person như sau:
[sourcecode language=”javascript”]
person[myDataName] = myDataValue;
[/sourcecode]
Để kiểm tra việc này bạn hãy bổ sung các dòng mã sau, lưu ý là phải sau (bên ngoài) cặp ngoặc nhọn dùng để định nghĩa đối tượng person:
[sourcecode language=”javascript”]
var myDataName = ‘height’;
var myDataValue = ‘1.75m’;
person[myDataName] = myDataValue;
[/sourcecode]
Bây giờ hãy lưu tệp tin và tải lại trên trình duyệt và nhập nội dung sau vào ô văn bản:
[sourcecode language=”javascript”]
person.height
[/sourcecode]
Bổ sung một thuộc tính cho đối tượng sử dụng phương pháp trên không thể dùng với dấu chấm, nó chỉ chấp nhận một chuỗi tên thành phần, không sử dụng biến để chỉ định tên
Từ khóa “this” dùng để làm gì?
Bạn có thể chú ý đến một số thứ hơi lạ trong các phương thức của chúng ta. Hãy xem thử VD sau:
[sourcecode language=”javascript”]
greeting: function() {
alert(‘Hi! I\’m ‘ + this.name.first + ‘.’);
}
[/sourcecode]
Bạn có thể băn khoăn từ khóa “this” dùng để làm gì. Từ khóa this dùng để tham chiếu đến đối tượng hiện hành – vì vậy trong trường hợp này từ khóa this tham chiều đến đối tượng person. Vậy tại sao không dùng person để thay thế? Bạn có thể thấy trong bài viết “Hướng đối tượng trong JavaScript cho những người mới bắt đầu” khi chúng ta tạo các contructor (hàm tạo), v.v., từ khóa this là rất hữu ích – hãy luôn đảm bảo rằng các giá trị được sử dụng khi ngữ cảnh của một thành viên thay đổi (VD hai đối tượng person khác nhau có thể có tên khác nhau, nhưng muốn sử dụng tên của chính mình khi nói lời chào).r own name when saying their greeting).
Hãy quan sát những gì được mô tả ở trên với hai đối tượng người (person) dưới đây:
[sourcecode language=”javascript”]
var person1 = {
name: ‘Chris’,
greeting: function() {
alert(‘Hi! I\’m ‘ + this.name + ‘.’);
}
}
var person2 = {
name: ‘Brian’,
greeting: function() {
alert(‘Hi! I\’m ‘ + this.name + ‘.’);
}
}
[/sourcecode]
Trong ví dụ trên, lệnh person1.greeting() sẽ cho kết quả “Hi! I’m Chris.”; person2.greeting() thì cho kết quả là “Hi! I’m Brian.”, thậm chí mã trong phương thức của chúng là giống nhau. Như đã trình bày trước đây, từ khóa this chỉ định tới đối tượng chứa mã đó – điều này không quá hữu ích khi bạn tự định nghĩa các hằng đối tượng, nhưng nó thực sự có ích khi bạn tạo các đối tượng động (ví dụ sử dụng với các constructor). Bạn sẽ thấy rõ hơn điều này ở bài viết sau.
Sử dụng các đối tượng sẵn có
Khi bạn theo dõi các ví dụ trên bạn có thể đang nghĩ đến việc sử dụng ký hiệu (toán tử) chấm (dấu chấm) là khá quen thuộc. Đó là bởi vì bạn đã sử dụng ký hiệu này trong suốt khóa học! Mỗi khi chúng ta làm việc với các ví dụ sử dụng API được xây dựng sẵn cho trình duyệt hoặc JavaScript, chúng ta đã sử dụng các đối tượng, vì các đặc tính này được xây dựng có cùng cấu trúc đối tượng như những gì chúng ta đã thấy ở trên, tuy vậy chúng phức tạp hơn so với những ví dụ mà chúng ta đã thực hiện.
Vì vậy khi bạn sử dụng các phương thức để xử lý chuỗi như:
[sourcecode language=”javascript”]
myString.split(‘,’);
[/sourcecode]
Bạn đã sử dụng một phương thức được xây dựng sẵn cho một đối tượng được tạo ra từ lớp String. Mỗi khi bạn tạo ra một chuỗi, chuỗi đó sẽ tự động được tạo ra dưới dạng một thể hiện (đối tượng) của lớp String, và do đó nó có sẵn những phương thức/thuộc tính dành cho đối tượng loại này.
Khi bạn truy xuất DOM (document object model – mô hình đối tượng tài liệu) giống như sau:
[sourcecode language=”javascript”]
var myDiv = document.createElement(‘div’);
var myVideo = document.querySelector(‘video’);
[/sourcecode]
Bạn đã sử dụng những phương thức sẵn có của các đối tượng thuộc lớp Document. Với mỗi trang web được tải về, một thể hiện (đối tượng) Document được tạo ra, có tên gọi là document, đối tượng này thể hiện toàn bộ cấu trúc, nội dung và các đặc tính khác của trang web, VD như URL của nó. Nhắc lại, điều này có nghĩa là đối tượng document có sẵn một số thuộc tính và phương thức.
Điều này là tương tự khi bạn sử dụng các đối tượng/API khác được xây dựng sẵn – VD như Array, Math, v.v..
Lưu ý rằng các Đối tượng/API dựng sẵn không phải luôn được tạo ra một cách tự động. Như VD sau về Notifications API – cho phép các trình duyệt hiện đại thực thi các thông báo (notification) – đòi hỏi bạn phải tạo ra một đối tượng mới sử dụng constructor để thực hiện một thông báo (notification) mà bạn muốn. Hãy thử viết các dòng mã sau vào màn hình lệnh (console) của JavaScript:
[sourcecode language=”javascript”]
var myNotification = new Notification(‘Hello!’);
[/sourcecode]
Chúng ta sẽ tìm hiểu các constructor trong bài viết sau.
Lưu ý: Sẽ hữu ích khi bạn nghĩ về cách mà các đối tượng giao tiếp khi truyền các thông điệp – khi một đối tượng muốn đối tượng khác thực hiện một số hành động nó thường gửi một thông điệp đến đối tượng khác dựa trên các phương thức của nó, và đợi một hồi đáp, điều này chúng ta biết đến giống như một giá trị trả về.
Tổng kết
Chúc mừng bạn, bạn đã đọc hết bài viết đầu tiên của chúng tôi về các đối tượng JS – bây giờ bạn cần có một ý tưởng hay để làm việc với các đối tượng trong JavaScript – bao gồm việc bạn tạo ra các đối tượng của riêng mình. Bạn cũng nên nhận ra việc sử dụng các đối tượng là một cấu trúc hữu ích để lưu trữ các dữ liệu và chức năng có liên quan với nhau – nếu bạn cố gắng kiểm soát tất cả các thuộc tính và phương pháp trong đối tượng bằng các biến và chức năng riêng biệt thì sẽ không hiệu quả và gây rắc rối cũng như bạn sẽ gặp nguy cơ xung đột với các biến và hàm có cùng tên. Các đối tượng cho phép chúng ta lưu giữ thông tin một cách an toàn, được “khóa” lại trong kho của riêng nó để tránh xa các nguy hiểm bên ngoài.
Trong bài viết sau chúng ta sẽ tìm hiểu các phương pháp lập trình hướng đối tượng (OOP), và các kỹ thuật có thể được sử dụng trong JavaScript.
Dịch: CodeGym | Nguồn : https://developer.mozilla.org