5.React知识点集合

可变对象

把对象a赋值给对象b,更改对象b的属性值,被引用的对象a也随之改变,这就是可变对象。

var a = {name: '张三', age: 18},
    b = a;
b.name = '李四';
a.name; // "李四"

为啥会这样呢?其他字符串和数值怎么不会变?要搞懂这个问题,我们必须了解下其内部的存储逻辑。

JavaScript有7种基本数据类型:number、string、boolean、null、undefined、object 以及 ES6 新增的symbol除了 object 为引用类型,其他都是基本类型。基本类型将值存在栈中,而 object 存在栈中的是地址值而不是本身的内容值,该地址值指向堆里的一块区域,该区域存的才是本身的内容值。

var value = 1,
    obj = {name: '张三', age: 18},
    value2 = value,
    obj2 = obj;

image

可以看到对于基本类型 number,其存值是栈里单独存一块,即使赋值也是copy一份再单独赋值,所以两者改变互不影响。但对于引用类型的 object,虽然也是在栈里单独存一块并copy值赋值,但是其存的是地址值,由于copy的地址值相同,所以最后两个obj指向的内容区域也相同,所以修改会同步。当修改 obj.name 改的是堆内存里面的 name,改完后, obj2.name 拿着同样的地址值去找堆内存对应区域,此时 obj2 看到的是已经改后的 name,于是返回改后的 name

var obj = {name: '张三', age: 18},
    obj2 = {name: '张三', age: 18};
obj2.name = '李四';
obj.name; // “张三"

上面这个例子,改了 obj2.nameobj.name 却不受影响,这又是为啥呢?我们来看看内存图。

image

从内存图可以看到,当创建一个新的引用类型变量时,会生成一个新的地址值,由于objobj2 地址不同指向的区域不同,所以修改之后互不影响。

array、function 等也都属于 object,也都是引用类型,所以修改数组的时候,原理和上面的一样。所以为了使两个引用类型互不影响,一般我们不直接将旧的 obj 赋值给新的 obj,而是生成新的引用类型变量,然后将原先对象的属性值一个个复制填充到新的引用类型变量里,这就是所谓的深拷贝。

不可变对象

既然对象可能会被其他拥有同样引用地址的对象同步改变,那么除了上述说的深拷贝一个新对象之外,有没有办法让原对象也不可改写?有的,JavaScript 确实提供了一些原生的方法来将可变对象变成不可变对象,通过控制对象属性的增删改来实现,由弱到强依次分为三种:Object.preventExtensions(不可扩展)、Object.seal(密封)、Object.freeze(冻结)。

1. 不可扩展

Object.preventExtensions() 可以使一个对象不可再添加新的属性,参数为目标对象,返回修改后的对象。

var obj = Object.preventExtensions({});

// 直接定义新的属性会报错
Object.defineProperty(obj, 'content', {
  value: 'hello'
}); // TypeError: Cannot define property:p, object is not extensible.

// 非严格模式下通过点符号添加不会报错,但会静默失败,原对象仍然没有 content 属性
obj.content = 'hello';
obj.content; // undefined

对应的,Object.isExtensible() 可以判断一个对象是否可扩展,即是否可以添加新的属性。参数是目标对象,返回布尔值, true 代表可扩展,false 不可扩展。

var obj = new Object();
Object.isExtensible(obj); // true
Object.preventExtensions(obj);
Object.isExtensible(obj); // false

2. 密封

Object.seal() 可以使一个对象无法添加新属性的同时,也无法删除旧属性。参数是目标对象,返回修改后的对象。

其本质是通过修改属性的 configurablefalse 来实现的。在属性描述对象里讲到,configurablefalse 时,其他配置不可改变,writable 只能 truefalse,且属性无法被删除。而由于只要 writableconfigurable 其中之一为 true,则 value 可改,所以密封之后的对象还是可以改属性值的。

var obj = {content: 'hello'};
Object.getOwnPropertyDescriptor(obj, 'content');
// Object {
//   value: "hello",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }
Object.seal(obj);
Object.getOwnPropertyDescriptor(obj, 'content'); // seal 后 configurable 变为 false
// Object {
//   value: "hello",
//   writable: true,
//   enumerable: true,
//   configurable: false
// }

对应的,Object.isSealed() 可以检测一个对象是否密封,即是否可以增删属性。参数是目标对象,返回布尔值,true 代表被密封不可增删属性,false 代表没被密封可增删属性。

var obj = new Object();
Object.isExtensible(obj); // true
Object.isSealed(obj); // false
Object.seal(obj);
Object.isExtensible(obj); // false,注意 seal 后对象的 isExtensible() 也随之改变
Object.isSealed(obj); // true

3. 冻结

Object.freeze() 可以使对象一个对象不能再添加新属性,也不可以删除旧属性,且不能修改属性的值。参数是目标对象,返回修改后的对象。

var obj = Object.freeze({name: 'example'});

// 直接定义新的属性会报错
Object.defineProperty(obj, 'content', {
  value: 'hello'
}); // TypeError: Cannot define property:p, object is not extensible.

// 非严格模式下通过点符号添加不会报错,但会静默失败,原对象仍然没有 content 属性
obj.content = 'hello';
obj.content; // undefined

delete obj.name; // 删除失败,返回 false

obj.name = 'hello';
obj.name; // 仍然是 "example"

对应的,Object.isFrozen() 可以检测一个对象是否冻结,即是否可以增删改。参数是目标对象,返回布尔值,true 表示已经冻结不可再增删改,false 反之。

var obj = new Object();
Object.isExtensible(obj); // true
Object.isSealed(obj); // false
Object.isFrozen(obj); // false
Object.freeze(obj);
Object.isExtensible(obj); // false,注意 freeze 后对象的 isExtensible() 也随之改变
Object.isSealed(obj); // true,注意 freeze 后对象的 isSealed() 也随之改变
Object.isFrozen(obj); // true

4. 注意要点

无论是不可扩展,密封,还是冻结,都是浅层控制的,即只控制对象本身属性的增删改。如果对象属性是一个引用类型,比如数组 subArr 或对象 subObj等,虽然subArr、subObj 的不可被删改,但subArr、subObj属性仍然可增删改。

var obj = Object.freeze({
  content: {name: 'example'}
});
obj.content = new Object();
obj.content; // {name: "example"},content 本身不可改
obj.content.name = 'test';
obj.content; // {name: "test"},但 content 的属性仍可改,因为冻结的是 obj 而不是 obj.content

由于每个对象都有一个属性 __proto__,该属性的值是该对象的原型对象,也是引用类型,由于冻结是浅层的所以原型对象并不会被连着冻结,仍然可以通过给对象的原型对象加属性达到给当前对象新增属性的效果。所以如果想进一步冻结还需要把原型对象也冻结上。

var obj = Object.freeze({});
obj.content = 'hello';
obj.content; // undefined,增加失败

var proto = Object.getPrototypeOf(obj);
proto.content = 'hello';
obj.content; // "hello",增加成功

Object.freeze(proto);
proto.name = 'example';
obj.name; // undefined,冻结原型之后增加失败

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,351评论 0 5
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,512评论 6 13
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,519评论 0 6
  • 第一章 错误处理: 错误: 程序运行过程中,导致程序无法正常执行的现象(即bug) 现象: 程序一旦出错,默认会报...
    fastwe阅读 1,033评论 0 1
  • 一、可变对象 js有7种基本数据类型:number、string、boolean、null、undefine、ob...
    白小狐哒阅读 910评论 0 0