Di konsol, saya mendapatkan abc meskipun pengaturan {writable:false}. Bisakah Anda menjelaskan cara kerja mengubah metadata?

let portfolio = {
  myFirstName: "Bob",
  myLastName: "Alice",
  myAge: 26,
  aboutMe: function() {
    return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
  }
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
Object.defineProperty(portfolio, "myFirstName", { value: "abc" });
console.log(portfolio.myFirstName);
5
Darkhan10 7 Januari 2021, 14:49

3 jawaban

Jawaban Terbaik

writable: false hanya berpengaruh pada Object.defineProperty jika configurable juga disetel ke false. Lihat langkah 7 dari ValidateAndApplyPropertyDescriptor algoritme :

Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
  If current.[[Configurable]] is false and current.[[Writable]] is false, then
    If Desc.[[Writable]] is present and Desc.[[Writable]] is true, return false.
    If Desc.[[Value]] is present and SameValue(Desc.[[Value]], current.[[Value]]) is false, return false.
    Return true.

Itu mungkin karena selama properti dapat dikonfigurasi, tidak ada yang menghentikan Anda untuk mengubah nilai writable kembali ke true, mis.

Object.defineProperty(
  portfolio,
  "myFirstName",
  {value: "abc", writable: true}
);

Perhatikan bahwa setiap properti yang dideklarasikan sebagai bagian dari literal objek secara otomatis memiliki {writable: true, configurable: true, enumerable: true}.

Contoh

Tidak dapat menetapkan karena writable dan configurable keduanya false:

var obj = {};
Object.defineProperty(obj, 'test', {
  value: 42,
  configurable: false,
  writable: false,
  enumerable: true,
});
console.log(obj);
Object.defineProperty(obj, 'test', {value: 21});
console.log(obj);

Dapat menetapkan nilai karena writable atau configurable adalah true:

var obj = {};
Object.defineProperty(obj, 'test', {
  value: 42,
  configurable: true,
  writable: false,
  enumerable: true
});
console.log(obj);
Object.defineProperty(obj, 'test', {value: 21});
console.log(obj);


var obj = {};
Object.defineProperty(obj, 'test', {
  value: 42,
  configurable: false,
  writable: true,
  enumerable: true
});
console.log(obj);
Object.defineProperty(obj, 'test', {value: 21});
console.log(obj);

Terakhir, jika writable dan configurable keduanya false tetapi jika nilai baru sama dengan nilai saat ini, tidak ada kesalahan yang akan terjadi karena tidak ada perubahan yang dilakukan pada properti:

var obj = {};
Object.defineProperty(obj, 'test', {
  value: 42,
  configurable: false,
  writable: false,
  enumerable: true,
});
console.log(obj);
Object.defineProperty(obj, 'test', {value: 42});
console.log(obj);

Menyetel writable: false akan berfungsi seperti yang diharapkan untuk tugas normal (foo.bar = 42) karena tugas tersebut melewati OrdinarySetWithOwnDescriptor yang memeriksa nilai writable dari deskriptor properti yang ada terlebih dahulu.

5
Felix Kling 7 Januari 2021, 12:26

Di baris ke-2 Anda Object.defineProperty(portfolio, "myFirstName", { value: "abc" }); Anda mendefinisikan properti lagi.

Anda tidak memberikan nilai. Anda membuang properti lama dan menggantinya dengan yang baru. (Secara teknis salah, ini melewati banyak langkah untuk mengevaluasi dan menerapkan nilai pada properti properti, tetapi untuk pemahaman sederhana, saya yakin ini cukup sebagai pemahaman, karena terasa seperti yang baru dalam skenario ini. Harap baca tautan jika Anda ingin mendapatkan kebenaran yang kompleks)

Untuk menetapkan nilai baru, gunakan portfolio.myFirstName = "value here" dan Anda melihatnya dilindungi dari penulisan.

let portfolio = {
  myFirstName: "Bob",
  myLastName: "Alice",
  myAge: 26,
  aboutMe: function() {
    return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
  }
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
portfolio.myFirstName = "Alice";
console.log(portfolio.myFirstName);

Untuk mencegah solusinya, panggil Object.freeze() pada objek setelah memodifikasi propertinya. Ini juga akan memiliki efek samping lain seperti tidak dapat mengedit nilai properti lain.

let portfolio = {
  myFirstName: "Bob",
  myLastName: "Alice",
  myAge: 26,
  aboutMe: function() {
    return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
  }
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
Object.freeze(portfolio);
Object.defineProperty(portfolio, "myFirstName", {value:"abc"});
console.log(portfolio.myFirstName);
8
Tschallacka 7 Januari 2021, 12:04

Anda sedang mengatasi pembatasan akses itu untuk mengatur properti secara keras. Itu hanya berdampak pada mutator portfolio.myFirstName.

Anda benar-benar tidak dapat memblokir akses ke defineProperty seperti itu. Itu terlalu rendah. Itu mungkin hal yang baik, karena dapat diandalkan.

1
tadman 7 Januari 2021, 11:53