Series JavaScript sida – Object trong JavaScript

Như đã chia sẻ ở bài viết trước, trong năm 2016 mình sẽ dành thời gian trau dồi kĩ năng front-end, do đó số lượng các bài viết về front-end trên blog sẽ nhiều hơn một chút.  Sau series C# hay ho được nhiều người đón nhận, năm nay blog sẽ có thêm series Javascript sida. Lý do là: càng học sẽ càng thấy C# nó hay ho, trong khi đó càng học lại càng thấy Javascript nó sida, bạn nào không tin cứ theo dõi series sẽ biết.

Bạn nào theo dõi blog lâu cũng biết mình có một số tình cảm khá phức tạp cả yêu lẫn ghét dành cho javascript. Về bản thân ngôn ngữ, cá nhân mình thấy nó là một ngôn ngữ trời đánh, khá sida, làm bao nhiêu lần mình phải thốt lên đ.m hay WTF khi học.

Javascript vốn được thiết kế một cách tạm bợ thô sơ, dùng để validate ở client side (Bạn nào tò mò muốn biết thêm về lịch sử của js có thể đọc thêm cuốn Professional JavaScript for Web Developers). Song chẳng hiểu duyên trời đưa đẩy thế nào, JavaScript cùng với PHP lại trở thành hai ngôn ngữ được sử dụng ở khắp mọi nơi, dù hứng chịu biết bao gạch đá.

c19be8898d6f097228295a6408ef3911c896257b035a120922865af69b92e4d4

Tuy ghét thì ghét, đã theo nghiệp web developer thì trước sau gì cũng phải làm việc hằng ngày với js. Bản thân js tuy xấu, nhưng nó lại đi kèm vô số thư viện/framework cực kì hay vào hữu ích (jQuery, AngularJS, …), nhờ NodeJS nó còn lấn sân qua luôn cả back-end. Do đó học và thuần thục JS chẳng bao giờ thiệt cả.

Nhận ra vốn kiến thức về js của mình còn đôi chỗ lủng củng và thiếu sót, trong series Javascript sida mình sẽ viết bài chia sẻ về một số khái niệm từ đơn giản đến phức tạp trong js, vừa củng cố kiến thức của mình, vừa giúp ích cho các bạn. Ở bài đầu tiên, mình sẽ giới thiệu kiến thức cơ bản nhất trong JavaScript: object.

Object là khỉ gì?

Ai từng học qua môn Lập trình hướng đối tượng đều biết đến các khái niệm Class và Object (Có thể xem lại ở đây: http://www.qhonline.info/php-nang-cao/57/lap-trinh-huong-doi-tuong-co-ban-ve-nhung-khai-niem.html). Tuy nhiên, trong JavaScript không có Class mà chỉ có Object, do đó sẽ khiến một số bạn cảm thấy khó hiểu (Đấy, mình đã nói bao nhiêu lần là js nó sida rồi mà).

Trong các ngôn ngữ OOP như C++, Java, C#, … Có thể tạm hiểu Class chính là cái khung, còn Object là vật thể tạo ra dựa vào cái khung đó. Js không có class, ta có thể khởi tạo 1 object mà không cần xác định class của nó, có thể hiểu toàn bộ object đều có class chung là Object.

Ta có thể hiểu một object là một tập hợp các trường dữ liệu (property) và các hàm (method). Như ví dụ dưới đây, object Student có 2 trường là firstName và lastName, có hàm showName


var person = {
firstName: 'Hoang',
lastName: 'Pham',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};

view raw

personObj.js

hosted with ❤ by GitHub

Introduction-to-Object-Oriented-Programming

Khởi tạo object thế éo nào

Trong một số ngôn ngữ khác, để khởi tạo object, ta dùng từ khóa new + tên class. Tuy nhiên, do trong JavaScript không có khái niệm class, ta có thể tạo object theo 1 trong 2 cách sau. Cách khởi tạo object bằng Object Literal thường được sử dụng nhiều hơn.


// Cách 1 : Object literal
// Khai báo toàn bộ các trường và hàm
var person = {
firstName: 'Hoang',
lastName: 'Pham',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
// Cách 2 : Object constructor
var psn = new Object();
psn.firstName = 'Hoang';
psn.lastName = 'Pham';
psn.showName = function() {
console.log(this.firstName + ' ' + this.lastName);
};

view raw

objCreating.js

hosted with ❤ by GitHub

Với các ứng dụng đơn giản, ta có thể tạm dùng 2 cách này. Tuy nhiên, với một số bài toán phức tạp hơn, nếu dùng object literal mỗi lần khởi tạo object sẽ khiến code dài và trùng lặp (Lần nào cũng phải khai báo lại các property và method). Để giải quyết vấn đề này, người ta sử dụng một pattern gọi là Constructor pattern. Một function sẽ đóng vai trò constructor để khởi tạo object (Cách này na ná khai báo class trong các ngôn ngữ khác).


function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.showName = function() {
console.log(this.firstName + ' ' + this.lastName);
};
}
// Khi muốn tạo object person chỉ cần gọi constructor
var psn1 = new Person('Hoang', 'Pham');
var psn2 = new Person('Hoang', 'Nguyen');

view raw

constructor.js

hosted with ❤ by GitHub

Một cách khác cũng hay được sử dụng đó là dùng prototype (Mình sẽ nói kĩ hơn về prototype trong những bài sau), nhưng mình thấy đa phần người ta sử dụng Constructor pattern nhiều hơn.


function Person() {}
Person.prototype.firstName = 'Hoang';
Person.prototype.lastName = 'Pham';
Person.prototype.showName = function() {
console.log(this.firstName + ' ' + this.lastName);
};
// Object được tạo sẽ có sẵn các trường firstName, lastName
// và hàm showName
var psn1 = new Person();
console.log(psn1.firstName); //Hoang
psn1.showName; //Hoang Pham

view raw

prototype.js

hosted with ❤ by GitHub

Nghịch ngợm với object

1. Truy xuất một trường/hàm của object

Để truy xuất một trường/hàm của object, ta có thể dùng dấu . (dot notation) và dấu [] (bracket notation). Dot notation thường được sử dụng nhiều hơn, nhưng bracket notation có thể làm được nhiều trò hay hơn.


var person = {
firstName: 'Hoang',
lastName: 'Pham',
50: 'Hi', // Property có tên là số, không dùng dotNotation được
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
console.log(person.firstName); // Hoang
console.log(person['firstName']); // Hoang
console.log(person.50); // Bị lỗi
console.log(person['50']); // Hi
console.log(person.showName()); // Hoang Pham
console.log(person['showName']()); // Hoang Pham

view raw

notation.js

hosted with ❤ by GitHub

Để duyệt qua toàn bộ các trường của một object, ta chỉ cần dùng hàm for đơn giản


var person = {
firstName: 'Hoang',
lastName: 'Pham',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
for(var prop in person) {
console.log(prop); // firstName, lastName, showName
}

view raw

sampleFor.js

hosted with ❤ by GitHub

2. Thêm/Xóa một trường/hàm của object

Với các ngôn ngữ static typing như C#, Java, một object được khởi tạo dựa trên class, do đó chúng luôn có các trường và hàm cố định. Tuy nhiên, do JavaScript là ngôn ngữ dynamic typing, ta có thể dễ dàng thêm/xóa các trường trong code


var person = {
firstName: 'Hoang',
lastName: 'Pham',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
delete person.lastName; // Xóa trường lastName
person.lName = 'Just adding'; // Thêm trường lName
console.log(person.lastName); // undefined
console.log(person.lName); // Just adding

3. Serialize và deserialize

Để giao tiếp với server, JavaScript thường submit dữ liệu dưới dạng pair-value (thông qua form) hoặc JSON. Do đó, javascript hỗ trợ sẵn việc chuyển object sang chuỗi JSON và ngược lại


var person = {
firstName: 'Hoang',
lastName: 'Pham',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
// Serialize sẽ làm mất method, chỉ giữ các property
JSON.stringify(person); // '{"firstName":"Hoang","lastName":"Pham"}'
var jsonString = '{"firstName":"Hoang","lastName":"Pham"}';
var psn = JSON.parse(jsonString); // Chuyển string thành object
console.log(psn.firstName); // Hoang
console.log(psn.lastName); // Pham

view raw

serialize.js

hosted with ❤ by GitHub

json-mini-logo

Qua bài viết này, các bạn đã có cái nhìn tổng quát về object trong JavaScript. Do sự sida của nó, việc hiện thực các đặc tính của OOP như inheritance, encapsulation, polymophism trong js khá rắc rối và phức tạp. Các bạn hãy đón xem trong bài viết sau về OOP trong JavaScript nhé.

Bạn nào từng học Java có thể xem thử bài này: https://codeaholicguy.wordpress.com/2015/12/22/javascript-object-duoi-con-mat-cua-java-developer/. Bài viết có tham khảo từ nguồn tiếng Anh tại: http://javascriptissexy.com/javascript-objects-in-detail/.

19 thoughts on “Series JavaScript sida – Object trong JavaScript”

      1. Em thấy có nhiều cách nhưng không biết cách nào có performance tốt khi clone nhiều object.
        Ngoài ra khi clone có 1 thuộc tính kiểu dữ liệu object mà em muốn clone reference thì làm thế nào

        Like

  1. Đôi khi làm với JavaScript, trường hợp Object thì đôi khi sẽ ức chế khi nó pass-by-reference là chủ yếu. Vd:

    var a = [{x: 1}, {x: 2}];
    var b = a;
    b[0].x = 9

    console.log(a[0].x); // 9

    Nên sẽ có một vài chiêu để khi clone, chuyển sang pass-by-value. Tham khảo ví dụ dưới đây. Mình mới thử cách 1 và 2. Cách 1 thì có trường hợp nó không clone được. Cách 2 thì giải quyết được cách 1 nhưng chưa biết khi nào sẽ lỗi 😀

    http://heyjavascript.com/4-creative-ways-to-clone-objects/

    Like

  2. Các bác có kinh nghiệm về web cho em hỏi?
    Em muốn học Jquery em có phải học JavaScrip trước không ạ?
    Em cảm ơn các bác nhiều 🙂

    Like

  3. Hi bác, đọc bài viết của bác em lại liên tưởng ngay đến TypeScript. Món này có vẻ đang hot, trong TypeScript thì có class và khởi tạo object theo class, cũng như static type giống như C#, ngoài ra cũng có hỗ trợ intelliSense khi dùng IDE là VS2013 :D. Không biết bác có nghiên cứu món này chưa, hóng bài về TypeScript của bác 😀

    Like

  4. Bài viết hay quá. Mình cũng điên đầu về sự khác biệt giữa cái object và class. Cứ thấy thằng JS này nó không đồng nhất với các ngôn ngữ khác, nhưng chưa nói rõ ra đc 😀

    Like

  5. Mấy nay đang học back end bằng node js nên xem lại bài này thấy thấm thấm hơn tý. Nhưng mà e muốn hỏi là sử dụng prototype để tạo class thì các instance mới ra đều cố định. Nếu ko làm cố định thì mình cho parameters vào. Mà cho vào rồi thì nó khác j constructor pattern đâu anh?

    Like

  6. Theo như mình tìm hiểu thì trong ES6 có khái niệm class,cũng có thể tạo lớp con bằng extend mà nhỉ?

    Like

Leave a comment