目录
数组的扩展
forEach遍历
//第一个参数为函数
//函数的第一个参数 是遍历的当前元素
//函数的第二个参数 当前元素的下标
//函数的第三个元素 数组本身。
//第二个参数为:函数中this指向。
arr.forEach(function(item,index,arr){
},obj);
小练习:将数组中的参数写入页面中(重点是看forEach中第二个参数(函数中this指向。)
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
<script>
var arr = [
"千与千寻",
"肖申克的救赎",
"谁先爱上他的",
"哈尔的移动城堡",
"海上钢琴师"
]
var lis = document.querySelectorAll("li")
arr.forEach(function (item, index, self) {
// console.log("电影名:"+item+",下标为:"+index);
this[index].innerHTML = item;
},lis);
</script>
map方法
map 映射含义,用法与forEach基本类似。
可以在函数中定义返回值。返回是一个数组。
var arr = [
{name:"千与千寻",score:"8.6"},
{name:"肖申克的救赎",score:"9.6"},
{name:"谁先爱上他的",score:"8.3"},
{name:"哈尔的移动城堡",score:"8.9"},
{name:"海上钢琴师",score:"9.0"}
]
var arr2 = arr.map(function(item){
return item.score;
//等价于 return item["score"];
});
console.log(arr2);// 能够得到这里面的每一个值 "8.6", "9.6", "8.3", "8.9", "9.0"
数组 中 map方法与forEach遍历的比较,
<script>
var array = ["wo", "shi", "zhao"];
array.forEach(function (item, index, arr) {
console.log(item + " " + index);
//console.log(arr);
});
array.map(function (item, index, arr) {
console.log(item + " " + index);
//console.log(arr);
});
</script>
Array.form()
Array.form
方法可以将类似数组的对象转为真正的数组。比如:DOM获取的伪数组,arguments对象。
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
<script>
let lis = document.querySelectorAll("li");
console.log( lis);//输出的是li 的一个伪数组
var arr = Array.from(lis);//转换为真正数组
console.log( arr);//这时获取到的li是一个真正的数组
//用typeof检测时发现都为对象 是因为数组也是对象
</script>
小练习:将arguments的参数(是一个伪数组)排序
<!-- <script>
//获取arguments的参数是一个伪数组
function sort() {
var args = Array.from(arguments);//转换成了一个真正的数组,
return args.sort();//这样就能使用数组的排序方法sort()
}
console.log(sort(6, 3, 5));
</script> -->
这里在对比一下
<!-- <script>
let likeArr = {
length: 3,//这个设置要有,否则输出一个空数组
"0": "hello",
"1": "word",
"2": "你好"
}
console.log(likeArr);//{0: "hello", 1: "word", 2: "你好", length: 3}
let arry = Array.from(likeArr);
console.log(arry);
//上下这两种输出都是一个真正的数组,结构样式一样
var arr = ["hello", "word", "你好"];
console.log(arr);
</script> -->
Array.of()
Array.of
方法将一组值,转换为数组。
<script>
let arr = Array.of( 3);
console.log(arr);//这时只有一个参数,就输出数组,数组里只有一个参数
let arr2 = new Array(3);//传统数组方法当数组里面只有一个参数时,输出的不是这个数组的内容,而是设置这个数组的长度
console.log(arr2);//输出 length: 3
//========================================================
let arr3 = new Array(1,2,3);
console.log(arr3);//输出数组 [1, 2, 3]
//Array.of方法
let arr4 = Array.of(1,2,3);
console.log(arr4);//输出数组 [1, 2, 3]
</script>
copyWithin()
将指定位置的内容复制到其他位置(复制会覆盖原有的内容)然后返回当前数组。
<script>
//target:必需,从该位置进行覆盖
//start:可选,从该位置开始读取数据,默认为0。如果为负数,表示倒数。
//end:可选 到该位置结束读取数据,默认为数组的长度。如果为负数,表示倒数、
var arr=[0,1,2,3,4]
// var arr1= arr.copyWithin(1);
// console.log(arr1);//[0, 0, 1, 2, 3]
// var arr2= arr.copyWithin(1,3);
// console.log(arr2);//[0, 3, 4, 3, 4]
// var arr3= arr.copyWithin(1,2,3);
// console.log(arr3);//[0, 2, 2, 3, 4]
// var arr4= arr.copyWithin(1,-2,4);
// console.log(arr4);[0, 3, 2, 3, 4]
这几种情况不能同时释放观察,因为同时释放原来的数组值就被改变,复制会覆盖原有的内容
</script>
find()和findIndex()
find方法,找到第一个符合条件的数组元素。
arr.find(function(item,indedx,arr){
//条件判断
})
小练习:(下面没有输出-9,因为它不是第一次出现)
<script>
var arr = [1, 6, -10, -9].find(function (item) {
return item < 0;
})
// ES6箭头函数写法
// var arr = [1, 6, -10, -9].find(item => item < 0)
console.log(arr);//-10
</script>
findIndex,找到第一个符合条件的数组元素的下标。
var arr = [1, 6, -10, -9].findIndex(item => item < 0)
console.log(arr);//2
keys(),values(),entries()配合for…of循环
这三个方法主要用于数组的遍历。配合for…of循环。
keys():对键名的遍历
values():对键值的遍历
entries():对键值对的遍历。
格式:
//item 指遍历的当前元素
//arr 指遍历的数组
for (const item of arr) {
console.log(item);
}
var arr = ["a","b"]
for (const item of arr.keys()) {
console.log(item);
}
// 0 1
for (const item of arr.values()) {
console.log(item);
}
// a b
for (const item of arr.entries()) {
console.log(item);
}
//[0,"a"] [1,"b"]
includes()
该方法可以判断数组是否包含指定的值。
格式
//arr:数组
//value:判断该数组中是否包含该值
//target:从数组的指定位置开始查找。
arr.includes(value,target)
返回值:布尔值 true为包含,false 不包含
console.log( [1,2,3].includes(2)); //true
console.log( [1,2,3].includes("2")); //false
console.log([1,2,3].includes(2,1));//true
console.log([1,2,3].includes(2,2));//false
小练习:
var arr = [1,2,3]
var index = arr.indexOf(2);//利用的是indexOf()方法找不到值返回-1
if(index !== -1){
console.log("该值已包含");
}else{
console.log("该值不包含");
}
显示该值已包含
var arr = [1,2,3]
var index = arr.indexOf(2);
includes方法与indexOf()方法的区别
- indexOf返回的是下标。 includes返回的是布尔值
- indexOf用来判断是否包含不够语义化,不够直观。
- indexOf 对于
NaN
是有误判的。
<script>这样写就没有了误判
var arr = [1, 2, 3,NaN]
// var index = arr.indexOf(NaN);//该值不包含(可是明明有)
var index = arr.includes(NaN);
if (index) {
console.log("该值已包含");
} else {
console.log("该值不包含");
}
</script>
对象的拓展
一、对象的属性和方法简介写法:
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
属性名和属性值一样时,可以只写一个(语法自动补足)
// 方法:es6
const o = {
method() {
return "Hello!";
}
};
// 等同于原来
const o = {
method: function() {
return "Hello!";
}
};
打印对象用简洁表示法需要加大括号
let user = {
name: 'test'
};
let foo = {
bar: 'baz'
};
console.log(user, foo)//原来写法
// {name: "test"} {bar: "baz"}
console.log({user, foo})//es6写法
// {user: {name: "test"}, foo: {bar: "baz"}}
更多es6详细接地气记载访问
https://www.cnblogs.com/marvintang1001/p/11809665.html
1.对象属性的简洁表示法
ES6可以在对象的大括号中,直接写入变量 和函数,作为对象的属性和方法。如果属性名与变量名相同,则可以简写,只写属性名即可。
var name = "赫本"
var obj = {name}//相当于 var obj = {name:name}
console.log(obj.name); //赫本
<script>
function fn(a, b) {
return {
a,
b
};
/*等价于 return {
a: a,
b: b
};*/
}
var obj = fn("hello", "word");
console.log(obj); //{a: "hello", b: "word"}
</script>
方法的简写
在对象中,可以对方法进行简写
<script>
let obj = {
fn() {
console.log("今晚九点,海岛集合。");
}
}
//相等于
/* let obj = {
fn: function() {
console.log("今晚九点,海岛集合。");
}
}*/
obj.fn();
</script>
简写只适用于普通函数方法,构造函数不能简写。
2.属性名表达式
拆分的功能,如果是对象,则将对象中的所有属性遍历出来,如果是数组,则将所有的元素遍历出来
<!-- <script>
let a = {
x: 1,
y: 2
}
let b = {
...a
}
console.log(b);// {x: 1, y: 2}
</script> -->
<script>
let arr = [10, 20, 30];
let c = {
...arr
}
console.log(c["0"]);//10
</script>
对象的扩展方法
Object.assign()用于对对象的合并
格式
//第一个参数后面的所有参数,合并到第一个参数中。
Object.assign(target,obj1,obj2)
<script>
第一个参数后面的所有参数,合并到第一个参数中。
const target = { name: '奥黛丽·赫本' }
const obj1 = { age: '20' }
Object.assign(target, obj1);
console.log(target);//输出一个改变后的对象 {age: "20" name: "奥黛丽·赫本"}
</script>
同名属性
<script>
let target = { name: '奥黛丽·赫本' }
let obj1 = {name: '张三' }
Object.assign(target, obj1);
console.log(target);//{name: '张三'}
//遇到同名属性,则后面的参数对象中的属性会将前面的属性覆盖。
</script>
用在数组上
用在数组上时,会将数组视为对象。
<script>
//Object.assign() 用在数组上时,会将数组视为对象。
var arr1 = [10, 20, 30];
/*等价于 var arr1 = {"0":"a", "1":"b", "2":30}*/
var arr2 = ["a", "b"];
/*等价于 var arr2 = { 0: "a", 1: "b"}*/
Object.assign(arr1, arr2);
console.log(arr1);//a,b,30
</script>
浅拷贝
浅拷贝:完成拷贝后可能存在彼此之间操作互相影响的就是浅拷贝
深拷贝:完成拷贝后彼此之间操作绝不会有互相影响的就是深拷贝
对基本类型变量,浅拷贝是对值的拷贝,(会影响被拷贝的值)没有深拷贝的概念。
对引用类型来说,浅拷贝是对对象地址的拷贝,并没有开辟新的栈,复制的结果是两个对象指向同一个栈的地址,彼此之间的操作会互相影响,
<script>
//#### 浅拷贝只拷贝复合数据的内存地址。拷贝后的变量仍然指向原本的对象。
const target = {
name: "奥黛丽·赫本",
sex: "女",
son: {
name: "卢卡·多蒂",
age: "40"
}
};
let obj1 = {
name: "奥黛丽",
age: "20",
son: {
name: "卢卡·多蒂",
age: "40"
}
}
Object.assign(target, obj1);
console.log(target);
/*合并后的对象输出的为 {age: "20"
name: "奥黛丽"
sex: "女"
son: {name: "卢卡·多蒂", age: 39}}
我们看到加上来的对象替换了原来名字相同的对象 这里age: 就该为40,只不过 这样的演示不了(下面的40是对的)
*/
console.log(target.son.age);//40
/* 因为这个我们明白,原来的值没有被改变,他们得到的这个对象是这个对象的内存地址,
改变的也是也是这个对象的内存地址的内容,没有真正的改变这个对象的内容
*/
obj1.son.age = 39;//作用 改变里面的值
console.log(target.son.age);//39 值改变了,是对内存地址的改变,不是对堆中数据的改变
</script>
深拷贝
深拷贝则是开辟新的栈,拷贝后的对象与原来的对象是完全隔离,互不影响
assign对象(合并对象)扩展方法就是浅拷贝
。也就是说,如果被合并的对象中有一个属性为对象,那么target对象拷贝得到的是这个对象的内存地址。
<script>
let obj1 = {
name: 'tom',
age: 18,
sex: '男',
children: {
name: '张三',
age: 200
}
}
let obj2 = {
sleep: '睡觉'
}
// 合并对象
// let res = Object.assign(target, [obj1, obj2, ....]);
let res = Object.assign({}, obj1)
// console.log(res);
console.log(obj1, obj2);
obj1.name = 'zhangsan';
console.log(obj1, obj2);
</script>
合并对象 也能够实现对象的拷贝 深拷贝是狭义(只能拷贝一层); 不能实现真正的深拷贝(对象嵌套的形式)
js 的深拷贝 经典的算法 递归算法实现
总要有一个出口
var obj1 = {
children: {
age: 200
}
}
function deepObj(obj) {
let newObj = {}声明一个变量用来储存拷贝之后的内容
for (let key in obj) {
if (obj[key] instanceof Object) {//实例obj在不在Object构造函数中
newObj[key] = deepObj(obj[key])
} else {
newObj[key] = obj[key]
}
}
return newObj
}
let res = deepObj(obj1)
obj1.children.age = 3400;
console.log(res); //age变为3400
console.log(obj1); //age仍为200
<script>
var obj = { //原数据,包含字符串、对象、函数、数组等不同的类型
name: "test",
main: {
a: 1,
b: 2
},
}
function copy(obj) {
let newobj = null; //声明一个变量用来储存拷贝之后的内容
//判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可,
//由于null不可以循环但类型又是object,所以这个需要对null进行判断
if (typeof (obj) == 'object' && obj !== null) {
//声明一个变量用以储存拷贝出来的值,根据参数的具体数据类型声明不同的类型来储存
newobj = obj instanceof Array ? [] : {};
//循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
for (var i in obj) {
newobj[i] = copy(obj[i])
}
} else {
newobj = obj
}
return newobj; //函数必须有返回值,否则结构为undefined
}
var obj2 = copy(obj)
obj2.name = '修改成功'
obj2.main.a = 100;
console.log(obj, obj2)
</script>
这样就完成了深拷贝,拷贝后的对象与原来的对象是完全隔离
浅拷贝的实现方式:
1、Object.assign()
2、lodash 里面的 _.clone
3、...扩展运算符
4、 Array.prototype.concat
5、 Array.prototype.slice
深拷贝的实现方式
1、 JSON.parse(JSON.stringify())
2、递归操作
3、cloneDeep
4、Jquery.extend()