+6

Toán tử new trong Javascript

Bốn quy tắc

Cách đơn giản nhất để hiểu toán tử new là hiểu xem nó làm những gì. Khi bạn sử dụng new, 4 thứ sau xảy ra:

  • Nó tạo ra một empty object mới
  • Nó bind this vào object mới đc tạo
  • Nó thêm một property tên là proto vào object mới đc tạo đó, property này trỏ đến constructor của prototype của object của function
  • Nó thêm return this vào cuối của function, do đó object mới được tạo đc return từ function

Thế là sao?

Nếu bạn ko hiểu mấy quy tắc trên thì cũng ko sao cả. Chúng ta sẽ đi dần dần. Đầu tiên tạo một constructor function tên là Student. Function này sẽ nhận 2 param là name và age. Nó sẽ set 2 thuộc tính đó vào giá trị của this.

function Student(name, age) {
  this.name = name;
  this.age = age;
}

Xong, giờ thử invoke function này với toán tử new xem. Truyền cho nó 2 tham số là 'John' và 26 xem.

var first = new Student('John', 26);

Vậy chuyện gì xảy ra nếu ta chạy đoạn code trên?

  1. Một object mới đc tạo ra, object first.
  2. This sẽ đc bind vào first, vậy nên mọi references đến this đều trỏ vào first.
  3. proto được thêm vào. Do đó first.proto sẽ trỏ vào Student.prototype.
  4. Sau cùng, object first mới đc tạo đó sẽ đc return thành biến first của ta. A new object is created — the first object. Thử test bằng console.log xem sao:
console.log(first.name);
// John
console.log(first.age);
// 26

Ngon lành rồi, giờ thì đào sâu vào keyword proto nào.

Prototypes

Tất cả object của Javascript đều có một prototype. Tất cả object đều thừa kế method và properties từ prototype của chúng. Giờ test thử vài ví dụ nào.

function Student(name, age) {
  this.name = name;
  this.age = age;
}

Để chứng tỏ rằng mỗi object đều có prototype, ta thử:

Student.prototype;
// Object {...}

Một object đc trả về. Giờ thì thử tạo một student mới xem:

var second = new Student('Jeff', 50);

Chúng ta đã sử dụng constructor của Student để tạo thêm một student thứ hai tên là Jeff. Và vì ta sử dụng toán tử new, proto property sẽ được thêm vào object thứ hai này. Nó sẽ trỏ vào constructor của object cha. Thử xem chúng có bằng nhau ko:

second.__proto__ === Student.prototype;
// true

Cuối cùng, Student.prototype.constructor sẽ trỏ đến constructor của Student:

Student.prototype.constructor;
//  function Student(name, age) {
//    this.name = name;
//    this.age = age;
//  }

Vì nó khá lằng nhằng nên hình này sẽ giúp bạn dễ hiểu hơn:

Như bạn thấy, constructor của Student (và tất cả constructor của các function khác nữa) có một property là .prototype. Cái prototype này có một object trong nó tên là .constructor, và nó trỏ lại constructor của function. Khi ta sử dụng toán tử new để tạo object mới, mỗi object đều có proto được liên kết ngược lại đến Student.prototype. Điều đó có gì quan trọng? Nó quan trọng vì nó liên quan đến kế thừa. Prototype object được chia sẻ mới tất cả object mà được tạo bởi constructor của function đó. Điều đó có nghĩa là ta có thể thêm function và properties vào prototype đó và tất cả các object đều dùng được. Thử thêm một ví dụ nữa để sáng tỏ điều này:

Student.prototype.sayInfo = function(){
  console.log(this.name + ' is ' + this.age + ' years old');
}

Ta vừa thêm một function vào prototype của Student. Bất kì student nào được tạo đều có thêm function .sayInfo này, thử xem sao:

second.sayInfo();
// Jeff is 50 years old

Thử tạo thêm một student mới xem sao:

var third = new Student('Tracy', 15);
third.sayInfo();
// Tracy is 15 years old

Kế thừa cũng chính là lý do vì sao ta có thể sử dụng function kiểu .toString(). Nghĩ lại thì, bạn chưa bao h viết function toString(), nhưng bạn vẫn dùng nó rất nhiều phải ko? Bởi vì hàm này, và cả nhiều hàm khác nữa là những hàm được viết sẵn trong prototype của Object. Tất cả các object ta tạo ra, về bản chất đều là delegate của prototype của Object mà thôi. Và tất nhiên, ta cũng có thể override mấy hàm đó bằng cách:

var name = {
  toString: function(){
    console.log('Not a good idea');
  }
};
name.toString();
// Not a good idea

Đầu tiên object của ta sẽ check xem nó có hàm tên là toString(), rồi sau đó mới thử check prototype. Nhưng vì nó có hàm này nên nó chạy luôn mà ko dùng hàm toString của prototype.

Nguồn: https://codeburst.io/javascript-for-beginners-the-new-operator-cee35beb669e


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.