Object.freeze () เทียบกับ const


146

Object.freeze()ดูเหมือนเป็นวิธีการอำนวยความสะดวกในการเปลี่ยนผ่านที่จะใช้constใน ES6

มีบางกรณีที่ทั้งสองเข้ามาแทนที่ในโค้ดหรือมีวิธีที่ดีกว่าในการทำงานกับข้อมูลที่ไม่เปลี่ยนรูปหรือไม่?

ฉันควรใช้Object.freeze()จนถึงช่วงเวลาที่เบราว์เซอร์ทั้งหมดที่ฉันทำงานร่วมกับการสนับสนุนconstแล้วเปลี่ยนไปใช้constแทนหรือไม่?


2
ฉันเคยใช้babeljsในกระบวนการสร้างของฉันดังนั้นฉันจึงสามารถเพิกเฉยต่อปัญหาความเข้ากันได้เช่นนี้
ผู้ใช้จ่าย

25
ไม่ - พวกเขาทำสิ่งที่แตกต่างกัน const ป้องกันการกำหนดใหม่ (เช่นคุณไม่สามารถ const x = 1; x = 2); การแช่แข็งป้องกันการกลายพันธุ์ (เช่นคุณไม่สามารถ Object.freeze (x); xa = 2);
joews

ไม่แน่ใจว่ามันสมเหตุสมผลหรือไม่ที่จะตั้งคำถามใหม่นี้หรือเพียงแค่ตอบคำถามที่นี่ แต่ฉันก็อยากรู้เหมือนกันว่า Symbols และ Object.freeze มีความแตกต่างกันมากหรือไม่? ผมรู้สึกว่าพวกเขามีความสัมพันธ์ยัง (คือสัญลักษณ์ที่ได้รับการประเมินเป็นแช่แข็งจากObject.isFrozenแต่พวกเขายังมีตัวเองดั้งเดิมชนิดข้อมูลของพวกเขา ... )
aug

2
การกลายพันธุ์ถูกป้องกันเฉพาะในระดับแรกดังนั้นคุณจึงไม่สามารถ Object.freeze (x); xa = 2 แต่คุณสามารถ Object.freeze (x); xab = 2 ดูjsfiddle.net/antimojv/op6ea91w/8 สำหรับการตรึงไลบรารีเฉพาะกิจอย่างสมบูรณ์
Antimo

คำตอบ:


251

constและObject.freezeเป็นสองสิ่งที่แตกต่างกันอย่างสิ้นเชิง

constใช้กับการผูก ("ตัวแปร") มันสร้างการผูกที่ไม่เปลี่ยนรูปกล่าวคือคุณไม่สามารถกำหนดค่าใหม่ให้กับการผูกได้

Object.freezeทำงานบนค่าและโดยเฉพาะอย่างยิ่งค่าวัตถุ มันทำให้วัตถุไม่เปลี่ยนรูปกล่าวคือคุณไม่สามารถเปลี่ยนคุณสมบัติของมันได้


3
โดยทั่วไปconstเป็นใหม่var; เป็นเพียงการบล็อกขอบเขตและป้องกันการมอบหมายใหม่ คุณสามารถใช้ได้letแต่จำเป็นจริงๆก็ต่อเมื่อคุณกำลังจะเปลี่ยนค่าที่ตัวแปรชี้ไปซึ่งเหมาะสมสำหรับตัวแปรควบคุม / วนซ้ำและประเภทง่ายๆเช่นตัวเลขและสตริง แต่ไม่ใช่สำหรับการใช้งานวัตถุส่วนใหญ่ (รวมถึง อาร์เรย์) หากคุณต้องการวัตถุ / อาร์เรย์ที่ไม่สามารถเปลี่ยนแปลงเนื้อหาได้นอกจากการประกาศด้วยแล้วconstคุณควรเรียกObject.freeze()ใช้ด้วย
Mark Reed

4
constไม่ได้เป็นใหม่var, letเป็นใหม่var
Facundo Colombier

88

ใน ES5 Object.freezeไม่สามารถใช้งานได้กับ primitives ซึ่งอาจมีการประกาศโดยใช้constมากกว่าวัตถุ คุณสามารถตรึง primitives ใน ES6 ได้ แต่คุณยังรองรับconstไฟล์.

ในทางกลับกันที่constใช้ในการประกาศวัตถุไม่ได้ "หยุด" คุณเพียงแค่ไม่สามารถประกาศวัตถุทั้งหมดใหม่ได้ แต่คุณสามารถปรับเปลี่ยนคีย์ได้อย่างอิสระ ในทางกลับกันคุณสามารถประกาศวัตถุที่ถูกแช่แข็งใหม่ได้

Object.freeze ยังตื้นดังนั้นคุณต้องใช้ซ้ำกับวัตถุที่ซ้อนกันเพื่อป้องกัน

var ob1 = {
   foo : 1,
    bar : {
        value : 2   
    }
};
Object.freeze( ob1 );

const ob2 = {
   foo : 1,
    bar : {
        value : 2   
    }
}

ob1.foo = 4;  // (frozen) ob1.foo not modified
ob2.foo = 4;  // (const) ob2.foo modified

ob1.bar.value = 4;  // (frozen) modified, because ob1.bar is nested
ob2.bar.value = 4;  // (const) modified

ob1.bar = 4;  // (frozen) not modified, bar is a key of obj1
ob2.bar = 4;  // (const) modified

ob1 = {};  // (frozen) ob1 redeclared
ob2 = {}; // (const) ob2 not redeclared

คำอธิบายนี้เคลียร์คำถามมากมายของฉันได้ในครั้งเดียว! เกี่ยวกับob1.bar.value = 4; // (frozen) modified, because ob1.bar is nested: เป็นเพราะขอบเขตของวิธีการหรือไม่?
YCode

15

สรุป:

constและObject.freeze()ตอบสนองวัตถุประสงค์ที่แตกต่างกันโดยสิ้นเชิง

  • constมีไว้สำหรับการประกาศตัวแปรที่ต้องมอบหมายทันทีและไม่สามารถกำหนดใหม่ได้ ตัวแปรที่ประกาศโดยconstจะถูกกำหนดขอบเขตบล็อกและไม่ใช่ฟังก์ชันที่กำหนดขอบเขตเหมือนตัวแปรที่ประกาศด้วยvar
  • Object.freeze()เป็นวิธีการที่ยอมรับวัตถุและส่งคืนวัตถุเดียวกัน ตอนนี้อ็อบเจ็กต์ไม่สามารถลบคุณสมบัติใด ๆ หรือเพิ่มคุณสมบัติใหม่ได้

ตัวอย่างconst:

ตัวอย่างที่ 1: ไม่สามารถกำหนดใหม่ได้ const

const foo = 5;

foo = 6;

รหัสต่อไปนี้แสดงข้อผิดพลาดเนื่องจากเราพยายามกำหนดตัวแปร foo ที่ถูกประกาศด้วยconstคีย์เวิร์ดอีกครั้งเราไม่สามารถกำหนดใหม่ได้

ตัวอย่างที่ 2: โครงสร้างข้อมูลที่กำหนดให้constสามารถกลายพันธุ์ได้

const object = {
  prop1: 1,
  prop2: 2 
}

object.prop1 = 5;   // object is still mutable!
object.prop3 = 3;   // object is still mutable!

console.log(object);  // object is mutated

ในตัวอย่างนี้เราประกาศตัวแปรโดยใช้constคีย์เวิร์ดและกำหนดอ็อบเจกต์ให้ แม้ว่าเราจะไม่สามารถกำหนดให้กับตัวแปรที่เรียกว่าอ็อบเจกต์นี้ได้ แต่เราสามารถเปลี่ยนอ็อบเจกต์ได้เอง หากเราเปลี่ยนคุณสมบัติที่มีอยู่หรือเพิ่มคุณสมบัติใหม่สิ่งนี้จะมีผล การปิดใช้งานการเปลี่ยนแปลงใด ๆ Object.freeze()ต่อความต้องการวัตถุเรา

ตัวอย่างObject.freeze():

ตัวอย่างที่ 1: ไม่สามารถกลายพันธุ์วัตถุที่ถูกแช่แข็งได้

object1 = {
  prop1: 1,
  prop2: 2
}

object2 = Object.freeze(object1);

console.log(object1 === object2); // both objects are refer to the same instance

object2.prop3 = 3; // no new property can be added, won't work

delete object2.prop1; // no property can be deleted, won't work

console.log(object2); // object unchanged

ในตัวอย่างนี้เมื่อเราเรียกObject.freeze()และให้object1เป็นอาร์กิวเมนต์ฟังก์ชันจะส่งคืนอ็อบเจ็กต์ซึ่งตอนนี้ 'ถูกตรึง' หากเราเปรียบเทียบการอ้างอิงของวัตถุใหม่กับวัตถุเก่าโดยใช้ตัว===ดำเนินการเราสามารถสังเกตได้ว่าพวกเขาอ้างถึงวัตถุเดียวกัน นอกจากนี้เมื่อเราพยายามเพิ่มหรือลบคุณสมบัติใด ๆ เราจะเห็นว่าสิ่งนี้ไม่มีผลใด ๆ (จะทำให้เกิดข้อผิดพลาดในโหมดเข้มงวด)

ตัวอย่างที่ 2: ออบเจ็กต์ที่มีการอ้างอิงจะไม่ถูกตรึงอย่างสมบูรณ์

const object = {
  prop1: 1,
  nestedObj: {
    nestedProp1: 1,
    nestedProp2: 2,
  } 
}


const frozen = Object.freeze(object);

frozen.prop1 = 5; // won't have any effect
frozen.nestedObj.nestedProp1 = 5; //will update because the nestedObject isn't frozen

console.log(frozen);

ตัวอย่างนี้แสดงให้เห็นว่าคุณสมบัติของวัตถุที่ซ้อนกัน (และอื่น ๆ ตามโครงสร้างข้อมูลอ้างอิง) ยังคงเปลี่ยนแปลงได้ ดังนั้นจึงObject.freeze()ไม่ 'ตรึง' วัตถุอย่างสมบูรณ์เมื่อมีคุณสมบัติที่เป็นข้อมูลอ้างอิง (เช่น Arrays, Objects)


12
var obj = {
  a: 1,
  b: 2
};
Object.freeze(obj);
obj.newField = 3; // You can't assign new field , or change current fields

ตัวอย่างข้างต้นทำให้วัตถุของคุณไม่เปลี่ยนรูปอย่างสมบูรณ์

ให้ดูตัวอย่างต่อไปนี้

const obj = {
  a: 1,
  b: 2
};
obj.a = 13; // You can change a field
obj.newField = 3; // You can assign new field.

จะไม่ให้ข้อผิดพลาดใด ๆ

แต่ถ้าลองแบบนั้น

const obj = {
      a: 1,
      b: 2
    };
obj = {
 t:4
};

มันจะแสดงข้อผิดพลาดเช่น "obj is read-only"

กรณีการใช้งานอื่น

const obj = {a:1};
var obj = 3;

มันจะโยน Duplicate declaration "obj"

ตามคำอธิบายของmozilla docs const ด้วย

การประกาศ const สร้างการอ้างอิงแบบอ่านอย่างเดียวสำหรับค่า ไม่ได้หมายความว่าค่าที่เก็บไว้จะไม่เปลี่ยนรูปแต่อย่างเดียวไม่สามารถกำหนดตัวระบุตัวแปรใหม่ได้

ตัวอย่างนี้สร้างขึ้นตามคุณสมบัติของ babeljs ES6


6

ให้เป็นเรื่องง่าย

พวกเขาแตกต่าง. ตรวจสอบความคิดเห็นเกี่ยวกับรหัสซึ่งจะอธิบายแต่ละกรณี

Const- เป็นตัวแปรขอบเขตบล็อกเช่นletซึ่งค่าใดไม่สามารถกำหนดใหม่ได้ประกาศอีกครั้ง

นั่นหมายความว่า

{
 const val = 10;  // you can not access it outside this block, block scope variable

}

console.log(val); // undefined because it is block scope 

const constvalue = 1;
constvalue = 2; // will give error as we are re-assigning the value;
const obj = { a:1 , b:2};

obj.a = 3;
obj.c = 4;
console.log(obj); // obj = {a:3,b:2,c:4} we are not assigning the value of identifier we can 
                  // change the object properties, const applied only on value, not with properties
obj = {x:1};     // error you are re-assigning the value of constant obj 
obj.a = 2 ;     // you can add, delete element of object

ความเข้าใจทั้งหมดคือ const เป็นขอบเขตบล็อกและค่าของมันจะไม่ถูกกำหนดใหม่

Object.freeze: คุณสมบัติของออบเจ็กต์รูทไม่สามารถเปลี่ยนแปลงได้นอกจากนี้เรายังไม่สามารถเพิ่มและลบคุณสมบัติเพิ่มเติมได้ แต่เราสามารถกำหนดอ็อบเจ็กต์ทั้งหมดใหม่ได้อีกครั้ง

var x = Object.freeze({data:1,
    name:{
    firstname:"hero", lastname:"nolast"
    }
});

x.data = 12;  // the object properties can not be change but in const you can do
x.firstname ="adasd"; // you can not add new properties to object but in const you can do

x.name.firstname = "dashdjkha"; // The nested value are changeable 

//The thing you can do in Object.freeze but not in const

x = { a: 1};  // you can reassign the object when it is Object.freeze but const its not allowed

// สิ่งหนึ่งที่เหมือนกันในทั้งสองอย่างคือวัตถุที่ซ้อนกันสามารถเปลี่ยนแปลงได้

const obj1 = {nested :{a:10}};
var obj2 =  Object.freeze({nested :{a:10}});

obj1.nested.a = 20; // both statement works
obj2.nested.a = 20;

ขอบคุณ.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.