JavaScript之对象(二)
看红宝书+查资料,重新梳理JavaScript的知识。
合并对象 Object.assign()
Object.assign()
可以用来将原对象的属性合并到目标对象上,而且这个方法还会返回合并后的目标对象。它会使用源对象上的[[Get]]
取得属性的值,然后使用目标对象上的[[Set]]
设置属性的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let target = { name : 'clz' };let source = { age : 21 };let result = null ; result = Object .assign (target, source);console .log ('target: ' , target);console .log ('source: ' , source);console .log ('result: ' , result);console .log (target === result);
合并对象是浅克隆 合并对象是浅克隆。所以如果合并的属性是对象,那么修改源对象会修改到目标对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let target = { name : 'clz' };let source = { job : { salary : 1 } };Object .assign (target, source); source.job .salary = 999 console .log ('target: ' , target)console .log ('source' , source)
多个源对象合并 上面的例子中,Object.assign
只接收了两个参数,第一个参数是目标对象,第二个参数是源对象。但是呢,其实它并不只是能够接收两个参数,可以接收多个参数,第一个参数是目标对象,其他的都是源对象,都会合并到目标对象上
1 2 3 4 5 6 7 8 9 10 let target = {};let source1 = { name : 'clz' };let source2 = { age : 19 };Object .assign (target, source1, source2);console .log (target);
既然存在多个源对象合并,那么问题来了,如果多个源对象具有相同的属性时,会怎样呢?
多个源对象具有相同的属性时,会使用最后的那个属性值。实际过程就是从左往右合并对象,可以通过在目标对象上添加 set
函数观察过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 let target, source1, source2, source3; target = { set job (newValue ) { console .log (newValue) } }; source1 = { job : { salary : 20 , }, }; source2 = { job : "WebMaster" , }; source3 = { job : "Coder" , };Object .assign (target, source1, source2, source3);
相等判定Object.is()
ES6 之前的相等判断
1 2 3 4 5 6 console .log (+0 === -0 ); console .log (+0 === 0 ); console .log (-0 === 0 ); console .log (NaN === NaN ); console .log (isNaN (NaN ));
问题所在:
+0、0会等于-0
NaN
不等于NaN
,验证 NaN
的相等性需要换方法:使用isNaN
函数
ES6 新增Object.is()
,和 ===
很像,但是能更好的应对特殊情况。从下面的例子可以看出,===
本来的功能它有,还能很好的应对上面说的问题。
1 2 3 4 5 6 7 8 9 console .log (Object .is ({}, {})); console .log (Object .is ("2" , 2 )); console .log (Object .is (2 , 2 )); console .log (Object .is (+0 , -0 )); console .log (Object .is (+0 , 0 )); console .log (Object .is (-0 , 0 )); console .log (Object .is (NaN , NaN ));
属性 属性名简写 常用
当属性名和变量名相同时,我们可以使用简写。因为它会自动去找同名变量。如果找不到,则会报错。
1 2 3 4 5 6 7 const age = 21 ;const person = { age, };console .log (person);
方法算是特殊的属性,也能简写。实际上,简写版本很常见
1 2 3 4 5 6 7 8 9 10 let person = { listen ( ) { console .log ("Euterpe" ); }, }; person.listen ();
可计算属性 引入可计算属性之前
我们现在有两个变量: nameKey
和 ageKey
。想要让它的值作为对象的属性名。
1 2 3 4 5 6 7 8 const nameKey = "name" ;const ageKey = "age" ;let person = { nameKey : 'clz' , ageKey : 21 }console .log (person)
发现,结果和我们想象中的不太一样。
这个时候,如果想要实现我们想要的效果,只能够使用下标的形式,因为只有下标形式才会去找变量的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 const nameKey = "name" ;const ageKey = "age" ;let person = {}; person[nameKey] = "clz" ; person[ageKey] = 21 ;console .log (person);
引入可计算属性之后,可以直接在对象字面量中直接动态命名属性 。
1 2 3 4 5 6 7 8 const nameKey = "name" ;const ageKey = "age" ;let person = { [nameKey]: "clz" , [ageKey]: 21 , };console .log (person);
简写方法名可以和可计算属性搭配使用
1 2 3 4 5 6 7 8 const methodKey = "listen" ;let person = { [methodKey]() { console .log ("Euterpe" ); }, }; person.listen ();
对象解构 常用 ,通过 {a} = obj
的形式,从 obj
中取出属性a的值,赋值给左边的a。
1 2 3 4 5 6 7 8 let person = { name : "clz" , age : 21 , };const { name, age } = person;console .log (name, age);
对象解构支持重命名, {value: newValue} = obj
,不过此时, name
并不会有值。
1 2 3 const { name : myname, age : myage } = person;console .log (myname, myage);
如果解构赋值的属性不存在,那么该变量的值就是undefined
1 2 3 const { job } = person;console .log (job);
解构赋值支持定义默认值。
1 2 3 const { myjob = "Coder" } = person;console .log (myjob);
对象解构会把原始值当成对象。**null
和undefined
不能被解构,之前的 解构赋值的属性不存在,那么该变量的值就是undefined
**对 null
和 undefined
不成立,会直接报错,如Cannot destructure property '_' of 'null' as it is null.
先声明后解构赋值 1 2 3 4 5 6 7 8 const person = { name : 'clz' , age : 21 }let name, age { name, age } = person
那么,是不是不能先声明,后解构复制呢? 答案是可以的,只不过,此时赋值表达式需要包含在一对括号里
1 2 3 4 5 6 7 8 9 10 const person = { name : "clz" , age : 21 , };let name, age; ({ name, age } = person);console .log (name, age);
不只是小括号可以,使用中括号也可以,不过使用花括号就会报错了,因为解构赋值就是用的花括号
解构赋值支持嵌套结构 同理,第一层不会有结果,可以打印job
测试
1 2 3 4 5 6 7 8 9 10 let person = { job : { salary : 112 , }, };const { job : { salary }, } = person;console .log (salary);
部分解构 部分解构:如果一个解构表达式多个赋值,开始的赋值成功,而中间的赋值出错的话,解构赋值开始的部分还是能完成,只是中间报错的部分以及后面的部分不能完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const person = { name : "clz" , age : 21 , };let personName;let personFoo;let personAge;try { ({ name : personName, bar : personFoo.bar , age : personAge, } = person); } catch (e) { console .log (e); }console .log (personName, personAge, personFoo);
参数上下文匹配 在函数参数中也可以进行解构赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let person = { name : "clz" , age : 27 , };function mytest1 (a, { name, age }, b ) { console .log (a); console .log (name, age); console .log (b); }function mytest2 ({ name: myName, age: myAge } ) { console .log (myName, myAge); }mytest1 (1 , person, 2 );console .log ("%c%s" , "color:red;font-size:24px;" , "============" );mytest2 (person);