Perbedaan antara pembekuan dan segel

164

Saya baru saja mendengar tentang metode JavaScript freezedan seal, yang dapat digunakan untuk membuat Objek apa pun tidak berubah.

Berikut adalah contoh singkat cara menggunakannya:

var o1 = {}, o2 = {};
Object.freeze(o2);

o1["a"] = "worked";
o2["a"] = "worked";

alert(o1["a"]);   //prints "worked"
alert(o2["a"]);   //prints "undefined"

Apa perbedaan antara freezedan seal? Bisakah mereka meningkatkan kinerja?

maja
sumber
6
Hanya catatan untuk siapa pun yang melihat pertanyaan ini, jawaban yang diterima secara faktual salah. @ tungd jawabannya benar.
Bjorn
2
Catatan lain, ada juga Object.preventExtensionstambahan Object.sealdan Object.freeze. Object.preventExtensionshanya mencegah item baru agar tidak ditambahkan ke objek. Anda dapat menghapus, mengonfigurasi, dan mengubah nilai properti pada objek yang ekstensibilitasnya dimatikan Object.preventExtensions.
Bjorn

Jawaban:

193

Object.seal

  • Ini mencegah menambah dan / atau menghapus properti dari objek yang disegel; menggunakan deleteakan mengembalikan false
  • Itu membuat setiap properti yang ada tidak dapat dikonfigurasi : mereka tidak dapat dikonversi dari 'deskriptor data' ke 'deskriptor accessor' (dan sebaliknya), dan tidak ada atribut deskriptor accessor yang dapat dimodifikasi sama sekali (sedangkan deskriptor data dapat mengubah writableatribut mereka , dan valueatribut mereka jika writeableitu benar).
  • Dapat melempar TypeErrorketika mencoba mengubah nilai objek yang disegel itu sendiri (paling umum dalam mode ketat )

Object.freeze

  • Apa yang Object.sealdilakukan, ditambah:
  • Ini mencegah memodifikasi setiap properti yang ada

Tidak ada yang memengaruhi objek 'mendalam' / cucu. Misalnya, jika objdibekukan, obj.eltidak dapat dipindahkan, tetapi nilai obj.eldapat dimodifikasi, misalnya obj.el.iddapat diubah.


Kinerja:

Menyegel atau membekukan suatu objek dapat mempengaruhi kecepatan enumerasinya, tergantung pada browser:

  • Firefox: kinerja enumerasi tidak terpengaruh
  • IE: dampak kinerja enumerasi dapat diabaikan
  • Chrome: kinerja enumerasi lebih cepat dengan objek yang disegel atau dibekukan
  • Safari: objek bersegel atau beku menghitung 92% lebih lambat (per 2014)

Pengujian: Benda bersegel , Benda beku .

Niccolò Campolungo
sumber
2
Bisakah Anda bicarakan mengapa kami menggunakan metode ini? Hanya karena kita bisa?
Alan Dong
3
Di masa depan saya pikir mereka akan banyak digunakan (jika dioptimalkan dengan benar) ketika mengembangkan perpustakaan / kerangka kerja. Mereka memungkinkan Anda untuk mencegah pengguna (bahkan tidak sengaja) memecah kode Anda (dan, seperti yang dinyatakan dalam jawaban, optimasi harus mengarah pada peningkatan kecepatan yang luar biasa). Tapi ini spekulasi murni :)
Niccolò Campolungo
2
Jawaban ini memiliki banyak kesalahan faktual. Untuk satu, sealjuga membuat properti yang ada tidak dapat dikonfigurasi, lihat jsfiddle.net/btipling/6m743whn Nomor 2, Anda masih dapat mengedit, yaitu mengubah nilai properti yang ada pada objek yang disegel.
Bjorn
8
FWIW, objek yang dibekukan dan disegel sekarang lebih cepat daripada bagian yang tidak beku dan tidak disegel di Chrome Canary v43.0.2317.0.
llambda
2
@AlanDong Agak terlambat datang, tetapi inilah mengapa Anda ingin mengunci suatu objek. Salah satu fitur JavaScript adalah Anda dapat menambahkan properti kapan saja Anda suka; Anda juga dapat melakukan ini secara tidak sengaja dengan salah ketik. Banyak siswa saya telah mencoba untuk menambahkan event handler yang dipanggil onClickatau onlickdan bertanya-tanya mengapa itu tidak berhasil. Jika JavaScript membuat kesalahan, maka itu satu hal yang salah. Kedua, ini memungkinkan Anda untuk menerapkan properti konstan pada objek yang mencegah perubahan. Ini sangat berguna pada objek methjods.
Manngo
119

Saya menulis proyek uji yang membandingkan 3 metode ini:

  • Object.freeze()
  • Object.seal()
  • Object.preventExtensions()

Tes unit saya mencakup kasus CRUD:

  • [C] tambahkan properti baru
  • [R] baca properti yang ada
  • [U] memodifikasi properti yang ada
  • [D] menghapus properti yang ada

Hasil:

masukkan deskripsi gambar di sini

piecioshka
sumber
2
Ini brilian. Apakah UPDATE mempertimbangkan memodifikasi akun (melalui defineProperty) atribut deskriptor misalnya dapat dikonfigurasi, enumerable, dapat ditulis?
Drenai
Saya selalu berpikir bahwa objek DOM harus disegel (setelah polyfill, tentu saja). Itu akan membantu untuk mencegah banyak kesalahan ketik.
Manngo
@Manngo Anda dapat menyegel objek DOM Anda. Cukup buat DEBUGMODEvariabel dan atur true. Lalu, lakukan if (DEBUGMODE) { ... }. Dalam ..., taruh fungsionalitas Anda untuk memastikan semua objek DOM selalu tersegel. Kemudian, ketika Anda siap untuk mendistribusikan skrip halaman web Anda, ubah DEBUGMODEmenjadi false, jalankan skrip Anda melalui kompilator penutupan, dan distribusikan. Sesederhana itu.
Jack Giffin
@JackGiffin Terima kasih atas komentarnya. Saya hanya mengatakan bahwa saya selalu berpikir itu akan menjadi ide yang bagus. Saya memiliki banyak siswa yang akhirnya mengetik sesuatu seperti element.onlick=somethingdan menjadi frustrasi karena tidak berhasil, tetapi secara teknis tidak ada kesalahan.
Manngo
2
@Lonely Maka itu tidak akan mengeja CRUD. Anda harus puas dengan sesuatu seperti RUDE;)
Manngo
84

Anda selalu dapat mencari ini di MDN. Pendeknya:

  • Membekukan : membuat objek tidak berubah, yang berarti tidak ada perubahan pada properti yang ditentukan diizinkan, kecuali mereka adalah objek.
  • Seal : mencegah penambahan properti, namun properti yang didefinisikan masih dapat diubah.
tungd
sumber
1
Object.seal()juga sepertinya membekukan properti prototipe: \
K ..
10

Object.freeze()membuat objek beku, yang berarti mengambil objek yang ada dan pada dasarnya memanggilnya Object.seal(), tetapi juga menandai semua properti "pengakses data" sebagai writable:false, sehingga nilainya tidak dapat diubah. - Kyle Simpson, Anda Tidak Tahu JS - Ini & Objek Prototipe

shmuli
sumber
4

Saya melihat perbedaan antara Freeze dan Seal di ECMAScript 5 dan membuat skrip untuk menjelaskan perbedaan. Frozen menciptakan objek yang tidak berubah termasuk data dan struktur. Seal mencegah perubahan pada antarmuka yang diberi nama - tidak ada tambahan, hapus - tetapi Anda dapat mengubah objek dan mendefinisikan ulang arti antarmuka-nya.

function run()
{
    var myObject = function() 
    { 
        this.test = "testing"; 
    }

    //***************************SETUP****************************

    var frozenObj = new myObject();
    var sealedObj = new myObject();

    var allFrozen = Object.freeze(frozenObj);
    var allSealed = Object.seal(sealedObj);
    alert("frozenObj of myObject type now frozen - Property test= " + frozenObj.test);
    alert("sealedObj of myObject type now frozen - Property test= " + sealedObj.test);

    //***************************FROZEN****************************

    frozenObj.addedProperty = "added Property"; //ignores add
    alert("Frozen addedProperty= " + frozenObj.addedProperty);
    delete frozenObj.test; //ignores delete
    alert("Frozen so deleted property still exists= " + frozenObj.test);
    frozenObj.test = "Howdy"; //ignores update
    alert("Frozen ignores update to value= " + frozenObj.test);
    frozenObj.test = function() { return "function"; } //ignores
    alert("Frozen so ignores redefinition of value= " + frozenObj.test);

    alert("Is frozen " + Object.isFrozen(frozenObj));
    alert("Is sealed " + Object.isSealed(frozenObj));
    alert("Is extensible " + Object.isExtensible(frozenObj));

    alert("Cannot unfreeze");
    alert("result of freeze same as the original object: " + (frozenObj === allFrozen).toString());

    alert("Date.now = " + Date.now());

    //***************************SEALED****************************

    sealedObj.addedProperty = "added Property"; //ignores add
    alert("Sealed addedProperty= " + sealedObj.addedProperty);
    sealedObj.test = "Howdy"; //allows update
    alert("Sealed allows update to value unlike frozen= " + sealedObj.test);
    sealedObj.test = function() { return "function"; } //allows
    alert("Sealed allows redefinition of value unlike frozen= " + sealedObj.test);
    delete sealedObj.test; //ignores delete
    alert("Sealed so deleted property still exists= " + sealedObj.test);
    alert("Is frozen " + Object.isFrozen(sealedObj));
    alert("Is sealed " + Object.isSealed(sealedObj));
    alert("Is extensible " + Object.isExtensible(sealedObj));

    alert("Cannot unseal");
    alert("result of seal same as the original object: " + (sealedObj === allSealed).toString());

    alert("Date.now = " + Date.now());
}
Jaycee
sumber
3

Saya tahu saya mungkin sedikit terlambat tetapi

  • Kesamaan: keduanya digunakan untuk membuat objek yang tidak dapat diperluas .
  • Perbedaan: Dalam membekukan atribut yang dapat dikonfigurasi, enumerable dan dapat ditulis objek diatur ke false. di mana seperti dalam atribut Tertulis yang dapat disetel diatur ke truedan atribut lainnya salah.
Faisal Naseer
sumber
6
Ini tidak sepenuhnya benar. Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true.
Leon Adler
2

Anda sekarang dapat memaksa properti objek tunggal untuk dibekukan alih-alih membekukan seluruh objek. Anda dapat mencapai ini dengan Object.definePropertydengan writable: falsesebagai parameter.

var obj = {
    "first": 1,
    "second": 2,
    "third": 3
};
Object.defineProperty(obj, "first", {
    writable: false,
    value: 99
});

Dalam contoh ini, obj.firstsekarang nilainya dikunci ke 99.

jaggedsoft
sumber
0

Saya telah membuat tabel sederhana untuk membandingkan fungsi-fungsi di bawah ini dan menjelaskan perbedaan antara fungsi-fungsi ini.

  • Object.freeze ()
  • Object.seal ()
  • Object.preventExtensions ()

tabel yang menjelaskan perbedaan antara ketiga metode di atas

Shwetabh Shekhar
sumber