Object.seal 和 Object.freeze
Object defineProperty
writable :如果为 false,则无法修改该属性,它在严格模式下引发错误,默认为 false 。 可配置 : 如果为 false,则这会使对象的属性不可枚举、不可写、不可删除和不可配置,默认为 false 。 get : 当尝试访问该属性时提前调用的函数,默认为 undefined。 set : 当尝试为属性设置某个值时提前调用的函数,默认为 undefined。
下面来看一些简单的代码:
可枚举
const obj = {};
Object.defineProperty(obj, 'a', {
value: 100,
enumerable: false,
});
for (const key in obj) {
console.log(key);
}
// 未定义
Object.keys(obj);
// []
2
3
4
5
6
7
8
9
10
11
可写
const obj = {};
Object.defineProperty(obj, 'a', {
value: 100,
writable: false,
});
obj.a = 200;
obj.a === 100; // 真的
(() => {
'use strict';
obj.a = 100;
// 严格模式下的类型错误
})();
2
3
4
5
6
7
8
9
10
11
12
可配置
const obj = {};
Object.defineProperty(obj, 'a', {
value: 100,
configurable: false,
});
// 1. non-enumerable
for (const key in obj) {
console.dir(key);
}
// undefined
Object.keys(obj);
// [
// 2. non-writable
(() => {
'use strict';
obj.a = 200;
// TypeError in the strict mode
})();
// 3. non-deletable
delete obj.a;
obj.a === 100; // true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
但是,当 writable 或 enumerable 为 true 时,将忽略 configure:false 。
Object.Seal
在 JavaScript 中,Object.seal 也和 密封 做同样的事情。Object.seal 使传递给它的对象的所有属性都不可配置,可用于阻止向对象添加新的属性和删除属性,但允许更改和更新现有属性。,来看下面的例子:
const obj = { author: 'DevPoint' };
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
author: {
value: 'DevPoint',
writable: true,
enumerable: true,
configurable: true
}
}
*/
Object.seal(obj);
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
author: {
value: 'DevPoint',
writable: true,
enumerable: true,
configurable: false
}
}
*/
obj.author = '111';
console.log(obj.author); // 111
delete obj.author;
console.log(obj.author); // 111
obj.city = 'Shenzhen';
console.log(obj.city); // undefined
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
上面代码定义了一个对象 obj 有一个属性 author ,其中的值为 DevPoint,初始的描述属性如下:
{
"author": {
"value": "DevPoint",
"writable": true,
"enumerable": true,
"configurable": true
}
}
2
3
4
5
6
7
8
然后用 Object.seal 密封了对象,再次查看哪些描述符发生了变化,哪些没有,从结果看只有可配置的更改为 false。
{
"author": {
"value": "DevPoint",
"writable": true,
"enumerable": true,
"configurable": false
}
}
2
3
4
5
6
7
8
obj.author = '111';
尽管 Object.seal 后的可配置现在为 false,但还是通过代码改变其属性值为 天行无忌 ,正如之前所解释的,将可配置设置为 false 会使属性不可写,但是如果 writable 明确为 true ,则它不起作用。当创建一个对象并设置一个新属性时,它默认为 writable:true 。
delete obj.author;
Object.seal 会使每个属性都不可配置,从而防止被删除。从上面的代码看,对对象执行 Object.seal 后,delete obj.author; 将变得无效。
obj.city = 'Shenzhen';
当 Object.seal 或 Object.freeze 被调用时,执行后的对象将变成不可扩展的对象,这意味着不能从中删除任何属性,也不能向其中添加任何属性。
Object.freeze
const obj = { author: 'DevPoint' };
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
author: {
value: 'DevPoint',
writable: true,
enumerable: true,
configurable: true
}
}
*/
Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
author: {
value: 'DevPoint',
writable: false,
enumerable: true,
configurable: false
}
}
*/
obj.author = '天行无忌';
console.log(obj.author); // DevPoint
delete obj.author;
console.log(obj.author); // DevPoint
obj.city = 'Shenzhen';
console.log(obj.city); // undefined
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
从上面代码结果看,与 Object.seal 的区别在于 writable 在执行 Object.freeze 后属性值也变为 false 。因此后续代码对其属性进行更新都无效。同样与 Object.seal 一样,Object.freeze 也使对象不可配置,这使得对象的每个属性都不可删除。
共同点
- 执行后的对象变得不可扩展,这意味着对象将无法添加新属性。
- 执行后的对象中的每个元素都变得不可配置,这意味着无法删除属性。 --> 不允许增删
- 如果在“使用严格”模式下调用操作,则两种方法都可能引发错误,例如在严格模式下执行 obj.author = "111" 会出现错误。
不同
Object.freeze 不允许对属性进行修改
不足
它们都只是对对象的第一层有效。可以参考以下方法进行递归操作:
const obj = { author: 'DevPoint', detail: { view: 100 } };
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/
const deepFreeze = (object) => {
const propNames = Object.getOwnPropertyNames(object);
for (const name of propNames) {
const value = object[name];
if (value && typeof value === 'object') {
deepFreeze(value);
}
}
return Object.freeze(object);
};
const freezeObj = deepFreeze(obj);
console.log(Object.getOwnPropertyDescriptors(freezeObj.detail));
/*
{
view: { value: 100, writable: false, enumerable: true, configurable: false }
}
*/
obj.detail.view = 500;
console.log(obj.detail.view); // 100
delete obj.detail.view;
console.log(obj.detail); // {view:100}
obj.detail.hits = 666;
console.log(obj.detail.hits); // undefined
story
title 故事名字
cover 封面
en-title 英文故事名字
pictures 图片地址列表
story 故事内容
en-story 英文故事内容
author 作者
like: 点赞数量
stars: 收藏数量
id
Comment 表: 评论表
id: 评论唯一标识
user_id: 用户唯一标识,对应 User 表的 id
story_id: 故事唯一标识,对应 Story 表的 id
content: 评论内容
create_time: 创建时间
update_time: 更新时间
user
id
avatar 头像
phone 手机号
name 用户名
family_id:家庭 id
family
id
name 家庭名称
users: 家庭成员
Collection 表: 存储用户的收藏合集
id: 合集唯一标识
creator: 用户唯一标识,对应 User 表的 id
name: 合集名称
cover: 合集封面
create_time: 创建时间
update_time: 更新时间
storys: 故事列表id
UserStoryHistory 表: 存储用户阅读故事的历史记录
id: 唯一标识
user_id: 用户唯一标识,对应 User 表的 id
story_id: 故事唯一标识,对应 Story 表的 id
story_title: 故事标题
story_cover: 故事封面
story_en_title: 故事英文标题
read_time: 阅读时间
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
const obj = { author: 'DevPoint', detail: { view: 100 } };
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/
const deepSeal = (object) => {
const propNames = Object.getOwnPropertyNames(object);
for (const name of propNames) {
const value = object[name];
if (value && typeof value === 'object') {
deepSeal(value);
}
}
return Object.seal(object);
};
const freezeObj = deepSeal(obj);
console.log(Object.getOwnPropertyDescriptors(freezeObj.detail));
/*
{
view: { value: 100, writable: true, enumerable: true, configurable: false }
}
*/
obj.detail.view = 500;
console.log(obj.detail.view); // 500
delete obj.detail.view;
console.log(obj.detail); // {view:500}
obj.detail.hits = 666;
console.log(obj.detail.hits); // undefined
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32