ES6学习(一)

var、let、const

作用域范围

直接看代码,比较明显、

for(let i=0;i<10;i++){
	console.log(i); //0,1,2,3,4,5,6,7,8,9;
}
console.log(i);//ReferenceError: i is not defined

for(var j=0;j<10;i++){
	console.log(j); //0,1,2,3,4,5,6,7,8,9;
}
console.log(j);//10

上面是letvar的一个小区别;由于var是全局变量

for(let i=0;i<10;i++){
  setTimeout(() => {
	console.log(i); //0,1,2,3,4,5,6,7,8,9;
	  }, 0); 
}
for(var j=0;j<10;i++){
  setTimeout(() => {
   console.log(j);//10
  }, 0); 
}

上面是letvar的一个小区别;由于var是全局变量

不存在变量提升

letconst必须先定义再使用,var可以先使用,再定义。

暂时性死区

归根结底还是因为不能存在变量提示导致的问题(可以这样理解)。

const sayHello = ()=>{
	words="hello JavaScript!"
	let words;//Cannot access 'words' before initialization
	console.log("words:",words);//上一步报错,就停止,不会运行console.log();了
};
// var 就不存在这样的问题
const sayHello = ()=>{
	words="hello JavaScript!"
	var words;
  console.log("words:",words);//words: hello JavaScript!
}

不允许重复定义

指的是同一作用域中,不允许重复定义一个变量名称

let name="张三";
const sayName=()=>{
	let name ="李四";
	console.log("name:",name);
}
sayName();//name:李四
console.log("name:",name);//name:张三
// 下面是错误的
const sayName=()=>{
	let name ="李四";
	let name="张三";
	console.log("name:",name);
}
sayName();// err

const 介绍

  1. const 声明时候就需要赋值,不能先声明再赋值。
  2. const 变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以引用类型数据如数组,可以变化。但是,并不是重新赋值。
//对象同理
const arr=[];
arr[0]=1;//√
arr.push(2);//√
arr=[1,2,3];//×

数组

数组的一些方法就不介绍了,比如
循环:map,foreach,for等
操作:push、pop、slice、from、of、indexOf、includes、find、findIndex等
主要记一些比较“邪门”的。

判断是一个数组

直接上代码,比较直观

// 我当初直接无脑测试typeof,结果有点问题
let arr=[];
console.log(typeof arr);// object 只能判断为一个“对象”所以,我们不能用typeof
console.log( Array.isArray(arr));// true
console.log( arr instanceof Array);// true
console.log( Object.prototype.toString.call(arr));// [object Array]
//还有其他方法,但是日常这几种就基本上够用了。比如
console.log( arr.constructor.toString() );//function Array() { [native code] }

深\浅拷贝

显而易见,深拷贝比浅拷贝要深。但是先不着急看代码,先来确定一下概念。
浅拷贝,就算浅浅的拷贝一下。何种才是浅拷贝呢?

let arr1=[1,2,3,[4,5,6]];
let arr2=arr1;//[1]:这只是赋值,不是拷贝;
arr2[0]=0;//arr1[0]也会变成0;要不咱给他叫做超级浅拷贝吧,啥都没拷贝过去。
let arr3=[...arr1];//[2] 可以实现浅拷贝
arr3[0]='嘿嘿';// arr[0]=0;是上面的arr2修改,导致的arr1[0]变成0,说明arr3的修改没修改到arr1上面;

上面的代码看出,浅拷贝,起码需要拷贝,就是基本数据类型的数据,和原数组是独立开的。相互不影响。那么他“浅”就浅在引用类型上面,所以我没修改arr3[3]=[1]的话,原本的数组arr1也会发送变化。
所以我们可以给浅拷贝下个定义:只有部分数据与原对象独立,还有一些数据是相互影响的。这里的相互影响也就是存储的是数据的地址。

浅拷贝的方法

这部分有看过别人的博客~写的很棒,所以贴一下,而且我也有引用,地址在这里
值得一提的是,引用数据类型比较的时候,对比的是地址值。所以直接赋值,返回为true,浅拷贝,是开辟了一片新的内存,所以地址值不一样了。判断为false。

let myArr=[1];
let myArr2=[1];
let myArr3=myArr;
myArr===myArr2;//false;
myArr[0]===myArr2[0];//true
myArr===myArr3;//true
  1. Object.assgin()
let obj1 = { 
	person: {name: "kobe", age: 41},
	sports:'basketball'
 };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }
  1. […]拓展运算符
let arr1=[1,2,3,[4,5,6]];
let arr2=[...arr[1]];
//下面多余的代码我就不写了
  1. Array.concat()
let arr1=[1,2,3,[4,5,6]]
let arr2 = [].concat(arr1);
arr2[3][0]=-1;
console.log(arr2);//[1,2,3,[-1,5,6]]
console.log(arr1);[1,2,3,[-1,5,6]]
  1. Array.slice()
let arr1 = [1,2,3,[4,5,6]];
let arr2 = arr1.slice();

  1. 循环,for,map等循环都可以实现
let arr1 = [1,2,3,[4,5,6]];
let arr2=[];
for(let i=0;i<arr1.length;i++){
	arr2.push(arr1[i]);
}
深拷贝的方法
  1. 递归
let arr1 = [1,2,3,[4,5,6]];
let arr2=[];
const deepClone=(obj)=>{
  let cloneObj = Object.prototype.toString.call(obj) === "[object Array]" ? [] : {};
   for(let key in obj){
     if(typeof obj[key]=== "object" && obj !== null){
       cloneObj[key] = deepClone(obj[key])
     }else{
       cloneObj[key] = obj[key]
     }
   }
   return cloneObj;
 };
 arr2=deepClone(arr1);

其实和浅拷贝的循环实现基本差不多,想法就是:1、进入判断数据类型,对象还是数组。2、进行循环,判断循环节的数据类型是应用类型还是基本类型,如果是引用类型,进入递归。如果是基本类型,直接赋值。3、每层递归将结果return,最后返回的就是全部递归过的一个新数据了。但是这种简单的只能实现数组或者对象的,也有完整版本的深拷贝。

function deepCopy(obj, cache = new WeakMap()) {
  if (!obj instanceof Object) return obj;
  // 防止循环引用
  if (cache.get(obj)) return cache.get(obj);
  // 支持函数
  if (obj instanceof Function) {
    return function () {
      return obj.apply(this, arguments)
    }
  };
  // 支持日期
  if (obj instanceof Date) return new Date(obj);
  // 支持正则对象
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  // 还可以增加其他对象,比如:Map, Set等,根据情况判断增加即可,面试点到为止就可以了
  // 数组是 key 为数字素银的特殊对象
  const res = Array.isArray(obj) ? [] : {};
  // 缓存 copy 的对象,用于处理循环引用的情况
  cache.set(obj, res);
  Object.keys(obj).forEach((key) => {
    if (obj[key] instanceof Object) {
      res[key] = deepCopy(obj[key], cache)
    } else {
      res[key] = obj[key]
    }
  });
  return res;
}
  1. JSON的方法
let arr1 = [1,2,3,[4,5,6]];
let arr2=[];
arr2=JSON.parse(JSON.stringify(arr1));

简单又方便,但是这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则。

去重

  1. 用ES6的set
let arr1=[1,1,2,3];
let arr2= new Set(arr1);
console.log(arr1);//[1,1,2,3]
console.log(arr2);//Set(3) {1, 2, 3}
/* set有一个问题就,返回后的数据不是数组类型的。
	我们可以通过Array的from或解构赋值获得数组类型的数据。
*/
let arr3=[...new Set(arr1)];//[1,2,3]
  1. 比较常规的遍历,收集,再返回。方法可谓是五花八门,map,forEach,for遍历等,indexOf,includes,filter等等方法比较是否存在或者相邻啥的,但是思想是一样的,就是简简单单,我拿一个,比较一下,已存在,就不动,不存在,就加入新数组,所以就归为一类。
let arr1=[1,1,2,3];
let arr2=[];
const myArr = (arr)=>{
  let resArr = [];
  arr.map((item,index)=>{
    if(resArr.length==0||!resArr.includes(item)){
      resArr.push(item);
    }
  });
  return resArr;
};
arr2=myArr(arr1);//[1,2,3]

简单,粗暴,但是面试肯定不行。平时可以用。
3. ES6给的Map。但是其实和map也关系不大,只是基础的对象而已。map可以简单的理解为对象Plus嘛~
大致想法就是把数据值作为key,数组下标作为value,如果是重复值,就会更新Map的value值。如果不是重复值,就直接新增一位。和上面的有一丢丢不一样。在于我们不用去考虑是否是重复值,我们只需要更新数据就可以了

let arr1 = [1, 1, 2, 3,1];
let arr2 = [];
function uniqueFunc(arr) {
  const res = new Map();
  let arrRes=[];
  arr.map((item,index)=>{
    res[item]=index;
  });
  for(let k in res){
    arrRes.push(k)
  };
  return arrRes
};
arr2 = uniqueFunc(arr1);//[1,2,3]

但是在处理 [1,2,3[1,2,3[1,2,3]]]这样的多重数组的时候,可能会有问题。
不过多重数组你只需要加一个判断和递归就好了,具体判断规则题目中会给出;如:先数组扁平化,再去重这样的。或者[1,2,3,[3,4,5,[5,6,7]]]输出变成[1,2,3,[4,5,[6,7]]]。 不同的输出情况太多,这边不做一一举例。就做一个多维数组,并且每层各自去重的例子。

let arr1 = [1, 1, 2, 3, 1, [1, 2, 1]];
let arr2 = [];
const uniqueFunc=(arr)=>{
  const res = new Map();
  let arrRes = [];
  arr.map((item, index) => {
    if (item instanceof Array) {//做一些判断,是不是数组
      res[JSON.stringify(uniqueFunc(item))]=index//是数组,就把数组stringify一下,
    } else {
     res[item] = index;
    }
  });
  for (let k in res) {
    arrRes.push(JSON.parse(k));
  };
  return arrRes;
};
arr2 = uniqueFunc(arr1); //[1, 2, 3, [1, 2]];
  1. 用Array.filter实现,这个与上面的不同是,我们不用循环,我们只要考虑是否一样就可以了
let arr1 = [1, 1, 2, 3, 1];
let arr2 = [];
function uniqueFunc(arr) {
  return arr.filter((e, i, arr) => {
    return arr.indexOf(e) == i;
  })
};
arr2 = uniqueFunc(arr1);//[1,2,3]

数组扁平化

数组扁平化,就是把多维,变成一维。所以我想到的第一个方法就是循环,判断,递归。

  1. 递归
let arr1=[1,2,3,[4,5,6,[7,8,9]]];
let arr2=[];
function recursionFlat(ary = []) {
  const res = []
  ary.forEach(item => {
    if (Array.isArray(item)) {
      res.push(...recursionFlat(item))
    } else {
      res.push(item)
    }
  })
  return res
}
let arr2=recursionFlat(arr1);//[1,2,3,4,5,6,7,8,9]
  1. Array的方法
let arr1=[1,2,3,[4,5,6,[7,8,9]]];
let arr2=[];
function reduceFlat(ary = []) {
  return ary.reduce((res, item) => res.concat(Array.isArray(item) ? reduceFlat(item) : item), [])
}
let arr2=reduceFlat(arr1);//[1,2,3,4,5,6,7,8,9]
  1. 简单粗暴Array.flat();
let arr1=[1,2,3,[4,5,6,[7,8,9]]];
let arr2=[];
function flat_1(arr=[]){
  return arr.flat(Infinity);
}
let arr2=flat_1(arr1);//[1,2,3,4,5,6,7,8,9]

如果是面试的话,还可能会问一些方法的多次点调用,问你最后的结果。如:

let arr=[1,2,3,[4,5,6]];
arr.map((a,b)=>a-b).reduce((a,b,c)=>b-c);//NAN
arr.map((a,b)=>a-b).slice((a,b)=>a);//[1,1,1,NAN];
arr.sort((a,b)=>a-b).filter((a,b)=>a-b);//NAN
arr.sort((a,b)=>a-b).reduce((a,b)=>b-a);//NAN
arr.filter((a,b)=>b-a).sort((a,b)=>{a-b});//[3,2,1]

最后,这是第一篇文章吧,先慢慢养好习惯,并且从基础出发,慢慢让自己的知识稍微有条理一些。给自己定个目标,大致两周3篇的速度吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值