深拷贝与浅拷贝
浅拷贝:
浅拷贝,通俗来说,就是把一个对象obj1的属性值直接拷贝给另一个对象。不管这个值是普通的数据类型,还是引用类型。
实现方法:
1.使用Object.assign方法
let obj1 = {...};
let obj2 = Object.assign({},obj1);
2.使用扩展运算符
let obj1 = { ... };
let obj2 = { ...obj1 };
3.手写拷贝函数
function getShallowClone(obj1){
if(!obj1 || typeof obj1 !== 'object'){
return ;
} //传入的参数必须是对象
let obj2 = Array.isArray(obj1) ? [] : {};
//判断传入的是数组还是对象,确定拷贝副本的数据类型
for(let key in obj1){
if(obj1.hasOwnProperty(key)){
obj2[key] = obj1[key]; //遍历obj1的key,并且把value直接赋值给Obj2
}
}
return obj2; //返回副本
}
拷贝对象的属性与源属性共享相同的引用。当更改源对象或拷贝的副本时,可能导致对应的对象也发生更改。
如果对象obj1是obj2的浅拷贝,obj1!==obj2成立。两个对象的属性有相同的名称且顺序相同、属性值相等、原型链相等。
对拷贝的副本的顶层属性的重新赋值不会影响源对象;对拷贝副本的嵌套对象的重新赋值会影响源对象(也就是说,拷贝副本和源对象有相同的引用,如果是修改拷贝副本顶层属性,相当于把顶层属性存储的内容直接改变,因此不会影响源对象。但如果是对嵌套对象,也就是对引用的内容进行操作,由于两者的引用相同,这种修改会影响到源对象)。
在JS中,标准的内置对象赋值操作都是浅拷贝。比如数组的concat方法、slice方法、from方法、Object.assign方法。
JS函数传参就是浅拷贝。
深拷贝
指拷贝副本和源对象的属性不共享相同的引用。当更改源对象或拷贝副本时,不会导致对方数据的变化。
对于两个对象obj1和obj2,如果obj2是obj1的深拷贝,则:obj1和obj2的属性具有相同的名称和相同的顺序、他们的属性值和原型链是结构等价的。obj1!==obj2成立。
深拷贝的实现:
1.通过JSON.stringify和JSON.parse
let obj2 = JSON.parse(JSON.stringify(obj1));
2.手写深拷贝函数
function getDeepClone(obj1){
if(obj1 || typeof obj1 !== 'object'){
return ;
}
let obj2 = Array.isArray(obj1) ? [] : {};
for(let key in obj1){
if(obj1.hasOwnProperty(key)){
obj2[key] = typeof obj1[key] === 'object' ? getDeepClone(obj1[key]) : obj1[key];
}
}
return obj2;
}
CSS实现垂直水平居中
以下方法一般也可以应用在水平或垂直居中中,只要单独设置水平的居中,和垂直的居中就可以了,思路都是一样的。
1.定位+负边距
思路:外部父元素是定位元素relative或absolute,内部子元素的定位是absolute,子元素相对父元素定位,偏移top 50%、left 50%,再通过margin-top: 负的子元素高的一半、margin-left:负的子元素宽的一半,把子元素调整到中间。
适用场景:需要知道子元素的宽和高。
代码:
<body>
<div class="outer">
<div class="inner">
</div>
</div>
<style>
.outer{
position: absolute;
height: 800px;
width: 1200px;
background-color: blueviolet;
}
.inner{
position: absolute;
left: 50%;
top: 50%;
width: 100px;
margin-left: -50px;
height: 200px;
margin-top: -100px;
background-color: aquamarine;
}
</style>
</body>
2.设置定位 + transform
思路:父元素设置定位,position是absolute或relative,子元素设置absolute,top 50% left 50%,通过transform移动到正中间。
代码:
<body>
<div class="outer">
<div class="inner">
</div>
</div>
<style>
.outer{
position: absolute;
height: 800px;
width: 1200px;
background-color: blueviolet;
}
.inner{
position: absolute;
left: 50%;
top: 50%;
width: 100px;
height: 200px;
transform: translate(-50%, -50%);
background-color: aquamarine;
}
</style>
</body>
3.设置 定位+ margin:auto
思路:父元素是定位元素absolute或relative,子元素的position设置为absolute,相对父元素定位,然后四个定位都是0,margin:auto。
代码:
<body>
<div class="outer">
<div class="inner">
</div>
</div>
<style>
.outer{
position: absolute;
height: 800px;
width: 1200px;
background-color: blueviolet;
}
.inner{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 100px;
height: 200px;
background-color: aquamarine;
}
</style>
</body>
4.使用flex布局
思路:让外部父元素的display是flex,内部子元素成为flex item,然后设置子元素沿着主轴和副轴居中。
代码:
<body>
<div class="outer">
<div class="inner">
</div>
</div>
<style>
.outer{
display: flex;
align-items: center;
justify-content: center;
height: 800px;
width: 1200px;
background-color: blueviolet;
}
.inner{
width: 100px;
height: 200px;
background-color: aquamarine;
}
</style>
</body>
5.设置display table-cell
思路:把外部父元素设置display:table-cell,以及vertical-align、text-align居中。内部子元素设置display:inline-block。
代码:
<body>
<div class="outer">
<div class="inner">
</div>
</div>
<style>
.outer{
display: table-cell;
vertical-align: middle;
text-align: center;
height: 800px;
width: 1200px;
background-color: blueviolet;
}
.inner{
display: inline-block;
width: 100px;
height: 200px;
background-color: aquamarine;
}
</style>
</body>