深拷贝,浅拷贝 set map symbol 模块化
1.深拷贝和浅拷贝
1.1 深拷贝
定义:拷贝一个对象时,如果属性是复杂数据类型,则拷贝的只是该数据的内存地址。
字面定义:就是将一个对象完全拷贝,并开辟一个新的地址,将拷贝内容放到这个新的地址中,而这个拷贝的对象里面的内容变化不影响原来的对象。
(从字面上的意思理解,是指很深的拷贝,到底有多深呢?深到不仅拷贝值,而且还独立开辟了一个空间。我的理解是:拷贝的过程中,独立地开辟了一个空间,这个对象指向这个地址,与原来的对象互不干扰)
注意:要想达到深复制就需要用递归
1.2 浅拷贝
定义:拷贝一个对象时,如果属性是复杂数据类型,则创建一个新的对象,指向新的对象的内存地址。
字面定义:例如:像是一个人有两个名字,内容是一样的,但名字不一样,当其中的一个名字内容发生变化的时候,其另一个也会发生变化。
(从字面上的意思理解,是指比较浅的拷贝,它与原来的变量仍然指向同一个地址,两者之间相互影响,即其中一个改变会影响另一个的改变。浅拷贝也被称为引用拷贝,引用的意思就是取了个别名,例如张三是大名,狗蛋是他的引用,即为小名,张三变了,狗蛋自然也变了,因为他们本质上就是指同一个人)
深拷贝与浅拷贝的区别
在于是否真正获取一个对象的复制实体,而不是引用。
1.3 案例
<script>
var obj = {
a: 1,
arr: [1, 2],
nation: '中国',
birthplaces: ['北京', '上海', '广州']
};
var obj2 = {
name: '杨'
};
obj2 = deepCopy(obj, obj2);
console.log(obj2);
console.log(obj2.birthplaces == obj.birthplaces);
//深复制,要想达到深复制就需要用递归
// 将o对象中的属性复制给c
function deepCopy(o, c) {
// 判断c是不是一个undefined或者null
var c = c || {};
//遍历对象
for (var i in o) {
//判断该属性是不是对象(复杂数据类型)
if (typeof o[i] === 'object') {
//再判断是不是数组。Array.isArray instanceOf
if (o[i].constructor === Array) {
//这是数组
c[i] = [];
} else {
//这是对象
c[i] = {};
}
//递归
deepCopy(o[i], c[i]);
} else {
c[i] = o[i];
}
}
return c;
}
</script>
2. set()
描述: 类似于数组。 set的值都是唯一的。 但是不能使用索引来获取元素。
结构:值:值
定义: new Set(); 创建一个空的set。
new Set(arr); 创建一个有值的set。
常用属性和方法:add()、delete()、has()、clear()
遍历的方法:forEach (for of)
注意:可以用于数组去重
准备:
var arr = [1, 2, 2, 3];
var ss = new Set(arr);
console.log(ss); //结果:1,2,3 结果不能有重复的值,可以用于数组去重
2.1 用于数组的去重
原因:set的值都是唯一的,里面没有重复的值
// 1. 数组去重
var arr1 = [...ss]
console.log(arr1);//结果:[1,2,3]
2.2 增加元素add()
ss.add(4);
console.log(ss); //结果:1,2,3,4
//增加多个元素
ss.add(5).add(6); //链式,因为set返回值是自身
console.log(ss);
2.3 删除元素 delete()
ss.delete(6);
console.log(ss); //结果:1,2,3,4,5A
2.4 遍历元素
// 4.遍历元素 使用forEach 和 for of不能使用for循环,因为set没有索引是 值:值
ss.forEach((item, index) => {
console.log(item); //结果:1,2,3,4,5
console.log('index的值' + index); //结果:1,2,3,4,5
console.log(index == item); //true
});
console.log('-----------------');
for (let cc of ss) {
console.log(cc);
}
2.5 判断有没有一个值 has()
返回的是布尔值,有这个值返回true,否则返回的是false
var res = ss.has(4); //结果:有的话返回true 没有返回false
console.log(res);A
2.6 清空 clear()
ss.clear();
console.log(ss); //里面的size是0
2.7 size
// size 查看ss中size中的值
console.log(ss.size);
3. map()
结构:键:值
与object的区别:
-
object对象的结构也是键值的形式,只不过object的键只能是字符串
-
map的键和值可以是任意类型
注意: map可以有重复的值,但是不能有重复的键。
定义: new Map();
方法:set(key,values)、get(key)、delete()、clear
遍历的方法:
- forEach
回调函数的第一个参数为 键值对中的值
回调函数的第二个参数为 键值对中的键
-
for of
-
属性:size:键值对的个数
准备:
let map = new Map();
let obj = {name:"潜伏",act:"孙红雷"}
let obj2 = {title:"谍战",info:"谍战剧是以间谍及地下秘密活动为主题、包含卧底、特务、情报交换、悬疑、爱情、暴力刑讯等元素的一类影视剧"}
3.1 增加元素 set()
map.set("肖申克的救赎","剧情")
map.set("潜伏","恐怖");
map.set(obj,obj2);
map.set("九品芝麻官","喜剧")
map.set("西虹市首富","喜剧")
3.2 获取值 get()
let v = map.get("九品芝麻官")
console.log(v);
3.3 删除 delete()
map.delete("潜伏");
console.log(map);
3.4 清空 clear()
console.log(map);
console.log(map.get(obj));
3.5 方法
map.forEach((v,k)=>{
console.log("v=>"+v);
console.log("k=>"+k);
})
for (const item of map) {
//item 是 一个数组,有两个元素。保存了键值对中的键和值。
console.log(item[0]);
console.log(item[1]);
}
4. symbol()
定义: Symbol(); 不带new
作用:
-
避免对象的属性名冲突
-
消除魔术字符串( 魔术字符串:指程序中与代码耦合性非常高的字符串。)
let a = Symbol(); let b = Symbol(); console.log(a == b); //false
4.1 例子
// A同学 人物金钱: money
let m = Symbol();
let p = {
name:"史塔克",
[m]:2000000000
}
console.log(p);
//B 同学 人物攻击力
let s = Symbol();
p[s]= 100;
4.2 消除魔术字符串
//创建一个角色
function createRole(type){
if (type == race.evles) {
console.log("创建了一个精灵");
} else if (type == race.human) {
console.log("创建了一个人类");
} else if (type == race.orcish) {
console.log("创建了一个兽人");
}
}
var race = {
evles:Symbol(),
human:Symbol(),
orcish:Symbol()
}
createRole(race.orcish);
4.3 规则
// 我们创建一个symbol变量时,默认情况下打印出来始终都是symbol。 多个symbol变量之间难以区分,所以可以在创建时,添加一个字符串对其进行描述. Symbol("描述字符")
let a = Symbol("金额");
let b = Symbol("攻击力");
//如果两个symbol的描述字符相等,并不代表他们两个相等。
let c = Symbol("攻击力");
console.log(a);
console.log(b);
console.log(c == b);
4.4 遍历
// symbol类型的属性是无法被 for in for of 等方法访问的。
// ES6提供了一个专门访问symbol属性的方法。
// let res = Object.getOwnPropertySymbols(对象)
// res是一个数组,包含了该对象所有属性名中symbol值。
// ES6新增的方法,可以遍历出对象所有的常规属性名和symbol属性名。
//Reflect.ownKeys(p);
let age = Symbol("年龄");
let k = Symbol("技能")
let p = {
name: "隔壁老王",
[age]: 40,
[k]: function () {
console.log("修水管");
}
}
//第二种方法
let res = Reflect.ownKeys(p);
console.log(res);
5. 模块化
JS最开始是没有模块化的概念的。 Java C++
模块化:将一个大型项目按照功能点进行划分。变成一个一个独立的模块。
优点:
1.模块可以独立开发,提高开发效率
2.模块可以复用。
作用:
1.私有化属性
2.避免变量名的冲突
ES5使用闭包+执行函数实现模块化
var 模块名 = (function(){
return {
要导出的变量
}
})()