💢 Object 💢

DefineProperty và DefineProperties trong javascript

Object.defineProperty()Object.defineProperties() xác định một hoặc nhiều thuộc tính mới trực tiếp trên một đối tượng.
js_masterJavascript
javascript-offjs.jpg

Chào các bạn


Trong bài viết này mình sẻ hướng dẫn bạn kỹ thuật sửa keyvalue của đối tượng.

Thật ra nó cũng không có gì khó cả. Khi các bạn biết càng nhiều kỹ thuật thì sẽ rất tiện dụng cho áp dụng sau này.

Object.defineProperty()

Phương pháp tỉnh Object.defineProperty() xác định một thuộc tính mới trực tiếp trên một đối tượng hoặc sửa đổi thuộc tính hiện có trên một đối tượng và trả về đối tượng.

Cú pháp

1Object.defineProperty(object, propertyKey, attributes);
Phương phápMô tảTrả về
Object.defineProperty()object Một đối tượng nguồn để sửa đổiobject
propertyKey Một chuổi key của đối tượng đó
attributes Cờ và thuộc tính

Ví dụ:

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5let userNew = Object.defineProperty(user,  "name", {
6    value: "offjs.com" // Chúng ta đổi name thanh offjs.com
7});
8
9console.log(userNew); // { name: "offjs.com" }
10console.log(user === userNew); // true

Ở ví dụ trên chúng ta sửa đổi key name trong đối tượng có biến user thành giá trị "offjs.com"

Giá trị trả về ở trên chính là đối tượng nguồn.

Nó tương đương như thế này.

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5user.name = "offjs.com";
6console.log(user); // { name: "offjs.com" }

Nhưng nó đẳng cấp hơn nhiều. Không chỉ đơn giản như vậy. Mà còn nhiều thứ khác nữa. Chúng ta cùng đi tiếp nhé.

value

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5// Thêm thuộc tính age có giá trị 100
6Object.defineProperty(user, "age", {
7    value: 100
8});
9
10console.log(user); // {name: 'Hồ Quang Trí', age: 100}

Như ví dụ trên mình thêm thuộc tính age có giá trị 100 vào đối tượng có tên biến user.

  • value
    • Nếu không gán thì mặc định undefined được sử dụng

Khi chúng ta thêm giá trị như vậy thì điều gì sẽ xảy ra. Chúng ta thử log tất cả các giá trị đó trong vòng lặp for in nhé.

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5// Thêm thuộc tính age có giá trị 100
6Object.defineProperty(user, "age", {
7    value: 100
8});
9
10for(let key in user) {
11    console.log(user[key]); // Hồ Quang Trí
12}

Ở ví dụ trên mình đả thêm thuộc tính age có giá trị 100 vào đối tượng có biến là user. Nhưng ở đây giá trị 100 đó không xuất hiện trong vòng lặp.

enumerable

Để giá trị 100 xuất hiện trong vòng lặp thì chúng ta cùng nhau sửa attributes của age lại.

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5// Thêm thuộc tính age có giá trị 100
6Object.defineProperty(user, "age", {
7    value: 100,
8    enumerable: true, // Thay đổi cờ của nó
9});
10
11for(let key in user) {
12    console.log(user[key]); // Hồ Quang Trí, 100
13}

Bây giờ giá trị 100 đã xuất hiện trong vòng lặp

  • enumerable
    • false Không xuất hiện trong vòng lặp. Mặc định
    • true Xuất hiện trong vòng lặp

Bây giờ chúng ta thử thay đổi giá trị của age thành 89 thì xem điều gì sẽ xảy ra nhé.

1let user = {
2    name: "Hồ Quang Trí"
3};
4
5// Thêm thuộc tính age có giá trị 100
6Object.defineProperty(user, "age", {
7    value: 100,
8});
9
10user.age = 89; // Thay đổi giá trị của age
11
12console.log(user); // {name: 'Hồ Quang Trí', age: 100}

Như các bạn có thể thấy giá trị của age vẫn không thay đổi. Nó vẫn là 100 tại sao??

Nếu chúng ta thêm "use strict" vào đầu tập lệnh thì sẽ văng lỗi ra nhé các bạn

1"use strict"; // Sử dụng nghiêm ngặt 
2 
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7// Thêm thuộc tính age có giá trị 100
8Object.defineProperty(user, "age", {
9    value: 100,
10});
11
12user.age = 89; // Uncaught TypeError: Cannot assign to read only property 'age' of object

Vậy cách khắc phục thế nào.

writable

1"use strict";
2let user = {
3    name: "Hồ Quang Trí",
4};
5
6// Thêm thuộc tính age có giá trị 100
7Object.defineProperty(user, "age", {
8    value: 100,
9    writable: true // Có thể thay đổi giá trị
10});
11
12user.age = 89; // Thay đổi giá trị của age
13
14console.log(user); // {name: 'Hồ Quang Trí', age: 89}

Bây giờ giá trị cũng đả được thay đổi. Và cũng không báo lỗi khi chúng ta sử dụng chỉ thị nghiêm ngặt use strict.

  • writable
    • false Không thể thay đổi giá trị
    • true Có thể thay đổi giá trị

Vậy bây giờ chúng ta thử xóa thuộc tính age đi và xem điều gì sẻ xảy ra.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7// Thêm thuộc tính age có giá trị 100
8Object.defineProperty(user, "age", {
9    value: 100,
10});
11
12delete user.age; // Uncaught TypeError: Cannot delete property 'age' of object

Các bạn có thể thấy lỗi bây giờ đã văng ra. Nếu chúng ta không sử dụng use strict thì sẽ không có gì xảy ra ở đây cả. Vậy cách sửa thì như thế nào.

configurable

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7// Thêm thuộc tính age có giá trị 100
8Object.defineProperty(user, "age", {
9    value: 100,
10    configurable: true
11});
12
13delete user.age; // xóa age
14
15console.log(user); // {name: 'Hồ Quang Trí'}

Ngay bây giờ thuộc tính age đã xóa như dự định

  • configurable
    • false Không thể xóa
    • true Có thể xóa

get

Một getter chức năng lấy ra giá trị.

Chỉ có thể có một get hoặc một value. Chúng không thể đi cùng nhau.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7Object.defineProperty(user, "age", { // Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
8    value: 100,
9    get () {
10        return 89
11    }
12});

Như các bạn có thể thấy. Lỗi đã văng ra. Cách khắc phục là chúng ta chỉ được chọn một trong hai nhé các bạn.

set

Một setter chức năng dùng để gán giá trị.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7Object.defineProperty(user, "age", {
8    set (value) {
9        this._age = value;
10    },
11    get () {
12        return this._age
13    }
14});
15
16user.age = 89; // gán giá trị
17
18console.log(user.age); // 89
19console.log(user._age);// 89
20console.log(user);     // {name: 'Hồ Quang Trí', _age: 89}
  • _age Thuộc tính nội bộ. Mặc dù chúng ta cũng co thể đọc được giá trị từ nó.Nhưng đó là ngoại lệ.

Khi chúng ta đọc user.age nó sẽ đi vào get và trả về từ this._age.

Khi chúng ta đọc user._age nó sẽ lấy giá trị trực tiếp từ this._age và sẻ không đi vào get.

Get và Set mạnh mẽ hơn Value

Giả sử chúng ta muốn tuổi của chúng ta là số lớn hơn 0 và bé hơn 100.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7Object.defineProperty(user, "age", {
8    set (value) {
9        if(value < 0  || value > 100 ) {
10            throw new Error("Ném lỗi"); // Uncaught Error: Ném lỗi
11        } 
12        this._age = value;
13    },
14    get () {
15        return this._age
16    }
17});
18
19user.age = -89; // gán giá trị âm

Đơn nhiên chúng ta cũng có thể viết chức năng để kiểm tra cho value. Nhưng ở đây mình tận dụng setter chức năng để kiểm tra.

Thêm nhiều tài sản.

Chúng ta có thể thêm nhiều tài sản và giá trị cho đối tượng bằng cách.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7Object.defineProperty(user, "age", {
8    value: 89,
9    enumerable: true,
10    configurable: true,
11    writable: true
12});
13
14Object.defineProperty(user, "phone", {
15    value: ["0353210168"],
16    enumerable: true,
17    configurable: true,
18    writable: true
19});
20
21// ...
22
23console.log(user); // {name: 'Hồ Quang Trí', age: 89, phone: ["0353210168"]}

Và cứ cứ như vậy nếu càng có nhiều.

Hoặc chúng ta có thể dùng

Object.defineProperties()

Phương pháp tỉnh Object.defineProperties dùng để thêm nhiều thuộc tính và tài sản vào đối tượng nguồn.

1"use strict";
2
3let user = {
4    name: "Hồ Quang Trí",
5};
6
7Object.defineProperties(user, {
8    age: {
9        value: 89,
10        enumerable: true,
11        configurable: true,
12        writable: true,
13    },
14    phone: {
15        value: ["0353210168"],
16        enumerable: true,
17        configurable: true,
18        writable: true,
19    },
20});
21
22console.log(user); // {name: 'Hồ Quang Trí', age: 89, phone: ["0353210168"]}

Trong thực tế thì chúng ta cũng hiếm khi nào động đến mấy cái này lắm. Nó có nhiều điều hay. Nhưng chúng ta thường chỉ làm việc và lấy dữ liệu từ cơ sở dử liệu là chính.

Tổng kết

Trong bài viết này mình đả nói đến về cách sữa đổi và thêm một hoặc nhiều tài sản vào object.

  • đối tượng
  • string
  • chuổi
  • số
  • chức năng
  • defineProperty
  • defineProperties

OFFJS.COM - Blog học tập giải trí - 🐲

Chia sẻ nhiều kiến thức thú vị trong lập trình cũng như cuộc sống.

Giới thiệu


Trang web này mình sẽ nói về kiến thức lập trình và cuộc sống mà các bạn mới học hay đang dự định học. Có một bước đi đầu đời vững chắc.

Hồ Quang Trí.jpg

Đi kèm với đó là những lý thuyết và các dòng code minh họa. Để các bạn dễ hình dung.

Đơn nhiên cũng không dễ dàng ngày một ngày hai mà học hết được.

Học Tập Là Một Con Đường Dài Vô Tận

Nó sẽ nuốt các bạn vô số thời gian nhưng bù lại khi đã biết thì mọi thứ thật là tuyệt.

1console.log("Hồ Quang Trí");

Nếu có ai nói bạn học lập trình trong vòng 3 đến 6 tháng thì mình xin nói thật không bao giờ có chuyện đó nhé.

Chúc các bạn thành công.

Chân trang

phone-toan-phat.png

0353210168

address-toan-phat.png

Việt Nam