# let/const

# let

  • 没有变量提升,var会变量提升
console.log(a);//输出undefine
var a=1;

console.log(a);//会报错
let a=1;
  • 是一个块作用域,var是全局的
  • 不能重复声明,var可以重复声明
var a=1;
var a=2;

# const(常量)

  • 同let具有块级作用域
  • 必须赋初始值,且赋值后其值不能修改

提示

默认情况下使用const,只有在你知道变量值需要被修改的情况下使用let

# 模板字符串

模板字符串可以解析变量

let name=`张三`;
let sayHello=`我的名字叫${name}`;

//模板字符串可以调用函数
cont fn=()=>{ return `张三`;}
let html=`我的名字叫${fn()}`

# 函数参数默认值

带默认值的参数放在后面

function foo(age = 25,){ // ...}

function foo(a,b = 20){ // ...}
foo(30) //输出50

//默认值可以是函数
function foo(a,b = get(5)){ // ...}
function get(val){ return val;}
foo(30) //输出35

# 剩余参数

函数形参个数大于实参个数时,剩余参数允许我们将多个参数合并到一个数组里

    const sum=(...args)=>{  
         let total=0;
         foreach(item=>total +=item);
         return total ;
    };
    sum(10,20);
    sum(10,20,30);

剩余参数和解构配合使用。

	let students=['zhansan','li','wangwu'];
	let [s1,...s2]=students;
	s2='li','wangwu'

# 扩展运算符

  • 扩展运算符可以将数组或者对象转为用逗号分隔的参数序列
    let ary=[1,2,3];
    ...ary  // 1,2,3
	let a = [...'hello world']; 
	// ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
  • 扩展运算符可以用于数组合并
	let ary1=[1,2,3];
	let ary2=[4,5,6];
	let ary3=[...ary1,...ary2]; //方法1
	ary1.push(...ary2); //方法2
  • 扩展运算符可以将伪数组转为真正的数组
	var oDivs=Document.getElementsByTagName('div');
	var ary1= =[...oDivs]; //方法1
	var ary2= Array.from(oDivs);//方法2
  • 扩展运算符配合set可以将数组去重
...new Set([1,2,3,4,5,2,4,1])

# 箭头函数

  • 箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
const fn=(形参)=>{ 函数体 }
  • 函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号以及return
const sun=(num1,num2)=>num1+num2
  • 如果形参只有一个,小括号也可以省略
const fn=v=>v
  • 使用箭头函数,函数内部没有arguments(获取函数的参数)
let getVal=(a,b)=>{
	console.log(arguments); //会报错
}
  • 箭头函数不能用new关键字来实例化对象
let person=()=>{
	
};
let p=new person();//会报错

# 解构赋值

# 数组解构

数组解构允许我们按照一一对应的关系从数组中提取值然后将值赋值给变量

let [a,b,c]=[1,2,3]

如果变量数量和值的数量不一致值时变量的值为undefined

let [a,b,c,d]=[1,2,3]; d="undefined"

# 对象解构

let {name,age}={name:"zhansan",age=20}

let node={
	type:'aa',
	name:'bb'
}
//完全结构, type和name一定是当前对象的属性名
let {type,name}=node;
//不完全结构,type一定是当前对象的属性名
let {type}=node;

# 扩展对象

//直接写入变量和函数作为对象的属性和方法
const name='sylone',age=20;
const person={
	//等价于name:name
	//只有属性名和属性值像相同的时候才能这样写
	name,
	age,
	sayName(){
		//输出 sylone
		console.log(this.name);
	}
}

function fn(x,y){
	return {x,y};
}

//属性名的表达式
const obj = {};
obj.show = true;

const name = 'a';
obj[name+'bc'] = 123;
console.log(obj) //输出{ show:true, abc:123 }

//方法名的组合
obj['f'+'bc'] = function(){
	console.log(this);
}

//也可以写成
const obj = {
	show:true,
	[name+'bc']:123,
	['f'+'bc'](){
		console.log(this);
	}
}

# Symbol数据类型

表示一个独一无二的值,用来定于对象的私有变量

//name和name2内存地址不同
const name = Symbol('name');
const name2 = Symbol('name');

let s1=Symbol('s1');
let obj = {};
//此时obj里的s1是独一无二的
obj[s1] = '小马哥'; 
//或者
let obj = {
	[s1]:'小马哥'
};

//Symbol定义的对象中的变量,取值或赋值要使用[]
console.log(obj[s1]);

//获取Symbol声明的属性方法
let s = Object.getOwnPropertySymbols(obj);
console.log(s[0]);

let m = Reflect.ownKeys(obj);
console.log(m);

# Set 数据结构

集合,表示无重复值的有序列表

const s=new Set(); 
const s=new Set([1,2,3,4]); 

s.size  //数组大小
s.add(1) //添加数值
s.add({a:1}) //也可以添加对象、数组、集合
s.delete(1) //删除
s.has(1) //是否包含
s.clear() //清除
s.forEach() //循环
[..s] //将集合转为数组

# Map 数据结构

键值对的有序列表,键和值可以是任意类型

const m=new Map();
m.set('name','张三')
m.set('age',20)
m.get('name') => '张三'
m.has('name') => true
m.delete('name') =>删除
m.clear() => 清除

# 迭代器 Iterator

Iterator 一种新的遍历机制

const items= ['one','two','three'];
const iterator =items[Symbol.iterator]();
//输出{ value:'one',done:false } false表示遍历继续
console.log(iterator.next());

# 生成器 Generator

可以通过yield关键字将函数挂起,为改变执行流提供可能,同时为异步编程提供了方案
与普通函数的区别

  • function后面、函数名之前有个*
  • 只能再函数内部使用yield表达式,让函数挂起
function* func(){
	yeild 2;
	yeild 3;
}
//返回一个遍历器对象
let fn=func();
//输出{ value:2,done:false }
console.log(fn.next());
//输出{ value:3,done:false }
console.log(fn.next());

总结

generator函数是分段执行的,yield是暂停执行,而next()是恢复执行
一个next()对应一个yeild

# Promise

常用于封装ajax

let pro =new Promise((resolve,reject) => {
	//执行异步操作
	if(res.code==200){
		resolved(res.data);
	}else{
		reject(res.error);
	}
}).then(data =>{ 
	console.log(data);
}).catch(error => {
	console.log(error);
})

Promise.resolve()和Promise.reject()都可以直接将任何一个对象转换为Promise对象

Promise.resolve('foo').then().catch(e => e).finally();
Promise.reject('foo').then().catch(e => e).finally();

Promise.all():所有异步操作行为完成之后再执行

let pro1 = new Promise((resolve, reject) => {});
let pro2 = new Promise((resolve, reject) => {});
let pro3 = new Promise((resolve, reject) => {});

let pro4 = Promise.all([pro1,pro2,pro3]).then((data)=>{
	//三个都成功才会执行
	//执行几个就返回几个结果的数组
	data[0]
	data[1]
	data[2]
}).catch(err = >{
	//只要有一个执行不成功就会执行
})

Promise.race():将多个 Promise 实例,包装成一个新的 Promise 实例

//只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变
//那个率先改变的Promise实例的返回值,就传递给p的返回值
var p = Promise.race([p1,p2,p3]);

# async/await

函数加了async后就会变成Promise对象
但是async是generator的语法糖(简化generator使其更易理解)

async function getData(){
    const res = await api.getTableData(); 
    return res
}
getData.then({}).catch({})

# 类 class

类的继承通过extends

class Animal{
	//默认的方法,实例化时被调用
	constructor(name,age){
		this.name = name;
		thia.age = age;
	}
	//中间没有逗号
	sayName(){
		return this.name
	}
	//中间没有逗号
	sayAge(){
		return this.age
	}
}
//实例化
const animal = new Animal('dog',10);
animal.sayName();//dog
animal.sayAge();//10


//类的继承
class Dog extends Animal{
	constructor(name,age,color){
		thia.color = color;
		//调用父类的构造函数
		super(name,age);
		//功能同super(name,age);
		Animal.call(this,name,age);
	}
	sayColor(){
		return this.color
	}
	//重写父类的方法
	sayName(){
		return 'hello' + super.sayName;
	}
} 
let d = new Dog('小黄',5,'黄色');
d.sayColor();//黄色
d.sayName();//hello小黄

# 模块化

一个js文件即是一个模块。把一个独立的功能写到一个单独的JS文件,称之为一个模块
如果导出文件中没有导出内容时

import './a' //a.js文件,后缀可以省略
import './css/index.css' //css文件

精确导出,如果有导出内容时

//1、前面加export
export const num=10;
export function aa(){ }
//2、在文件底部统一导出
const num=10;
function aa(){ }
export {
	num,
	aa
}

//导入
import { num,aa } from './a'

默认导出,只能有一个默认导出

export default aa
export default {
	const num=10;
	function aa(){ }
}

//导入
import aa from './a'
import obj from './a'

//既有默认导出也有精确导出时
import obj,{ num, aa } from './a'
import * as f from './a'

注意

node模块中,采用的是CommonJS规范,使用module.exports导出接口
使用require引入模块。var vue= require('vue')
也就是说:
NodeJS等CommonJS规范使用module.exports/require来暴露组件成员
ES6使用export/import来暴露组件成员

# 本地存储

  • localStorage:最大5M
  • sessionStorage:生命结束于当前标签页的关闭或浏览器的关闭
// 增加了一个 localStorage ‘myCat’ 数据项
localStorage.setItem('myCat', 'Tom');
// 读取 localStorage ‘myCat’ 数据项
let cat = localStorage.getItem('myCat');
// 移除 localStorage ‘myCat’ 数据项
localStorage.removeItem('myCat');
// 移除所有的 localStorage 数据项
localStorage.clear();
// 是否包含某属性
localStorage.hasOwnProperty('myCat');

# 常用方法

# 字符操作

  • startsWith("hello")、endsWith("hello"):是否以hello开头或结尾
  • includes("hello"):是否包含字符串hello
  • "x".repeat(2) => "xx" :重复
  • 'hello'.padStart(10) => " hello"
  • 'hello'.padEnd(10) =>"hello "
  • 'hello world'.replaceAll('l', '') => "heo word"
  • 用 split()拆分字符串数据后直接获得 数值格式数据
let dataArr = '1,2,3,4,5,6,7,8,9';
console.log(dataArr.split(','))  //  ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
console.log(dataArr.split(',').map(parseFloat))  //  [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 数组操作

  • [1,2].push(3):往数组最后一位添加元素,返回新数组长度
  • [1,2].unshift(0):往数组第一位添加元素,返回新数组长度
  • [1,2].pop():删除数组最后一个元素,返回被删除的元素
  • [0,1,2].shift():删除数组第一个元素,返回被删除的元素
  • [1,2].concat([2,3]):合并数组,对数组1没有影响
  • [1,2].reverse():数组反转
  • [1,2,3,2].indexOf(2):获取元素2第一次出现的索引,没有此元素时返回-1
  • [1,2,3,2].indexOf(2,2):从索引为2的位置开始查找元素2
  • includes():数组是否包含此元素,也可用于字符串是否包含某字符
  • [1,2,3,4,5].slice(2,5):截取第三个元素到第六个元素前的所有元素
  • splice(要操作元素的索引,要删除的个数,要添加的元素):向/数组添加/删除项目,并返回删除的项目
  • Array.from():将为数组转化为数组
  • Array.of(1,2,3,'4'):将一组值转化为数组
  • Array.keys():所有的索引
  • Array.values():所有的值
  • Array.entries():所有的元素
const aa=['1','2'];
let it=aa.entries();
it.next().value; => '1'
it.next().value; => '2'
it.next().value; => 'undefine'

  • Array.isArray():判断一个变量是否为数组
  • map():返回一个新数组,不会改变原始数组
  • filter():返回一个新数组,该新数组的元素是符合筛选条件的结果
  • some():数组中只要有一个元素满足给定的条件返回true
  • every():数组中是否所有的元素满足给定的条件返回true

  • reduce():接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
//数组求和
//acc:上次遍历的返回值 cur:当前元素
var total = [ 0, 1, 2, 3 ].reduce(( acc, cur ) => {
    return acc + cur
}, 0);//0是初始值
console.log(total) // 6

//二维数组转为一维数组
var array = [[1, 2], [3, 4], [5, 6]].reduce(( acc, cur ) => {
    return acc.concat(cur)
}, []);//[]是初始值
console.log(array)  // [ 0, 1, 3, 4, 5, 6 ]

//计算数组中每个元素出现的次数
let arr = [ 0, 1, 3, 0, 2, 0, 2, 3 ]
const arraySum = (arr, val) => arr.reduce((acc, cur) => {
    return cur == val ? acc + 1 : acc + 0
}, 0);
console.log(arraySum(arr, 0)) // 数组arr中 0 元素出现的次数为3

# 对象操作

  • Object.keys({a: 1, b: 2, c: 3}) => [a, b, c]
  • Object.values({a: 1, b: 2, c: 3}) => [1, 2, 3]
  • Object.entries({a: 1, b: 2, c: 3}) => [["a", 1], ["b", 2], ["c", 3]]
  • Object.is(value1,value2):比较两个值是否严格相等,类似于 ===
  • Object.assign(targetObject,obj1,obj2……):用于对象的合并
  • Object.defineProperty:定义新属性或修改原有的属性
const pp={
	name:'张三',
	yanzhi:2
}
let temp=pp.yanzhi;
Object.defineProperty(pp,'yanzhi',{
	//get方法会在获取yanzhi这个属性的时候执行
	//get方法会劫持yanzhi这个属性的获取操作
	get:()=>{
		return temp;
	},
	//set方法会劫持到yanzhi这个属性的设置操作
	set:(value)=>{
		temp=value;
	}
})
  • 循环展示object 和 array
obj = {name: "凡夫俗子",sex: "man",age: "24"}
for(var i in obj) {
	console.log(i) // name sex age
}
for(var i in obj) {
	console.log(obj[i]) // 凡夫俗子 man 24
}

arr = ["zhangsan","wangwu","lisi"]
for(var i in arr) {
    console.log(i) //0 1 2
}
for(var i in arr) {
    console.log(arr[i]) //zahngsan wangwu lisi
}
  • 数组根据对象的某个属性去重
unique(arr, val) {
  const res = new Map()
  return arr.filter(item => !res.has(item[val]) && res.set(item[val], 1))
}
//调用方式 this.unique(DataList, 'GoodsId')
  • 根据某个属性将数组分组
const array = [{
  id: 1,
  name: '小明',
  sex: '男'
},
{
  id: 3,
  name: '小红',
  sex: '女'
},
{
  id: 2,
  name: '小刚',
  sex: '男'
},
{
  id: 4,
  name: '小花',
  sex: '女'
},
{
  id: 5,
  name: '小甜甜',
  sex: '女'
},
];

function getList(list) {
  const map = new Map()
  list.forEach((item, index, arr) => {
    if (!map.has(item.sex)) {
      map.set(
        item.sex,
        arr.filter(a => a.sex == item.sex)
      )
    }
  })
  return Array.from(map).map(item => [...item[1]])
}
const list = getList(array)
console.log(array, '分组前');
console.log(list, '分组后');
  • 对象新增属性
var obj2 = {
            age:50,
            ...obj
        }
  • 对象删除属性
var obj = {x:1};
delete obj.x;
console.log(obj.x)//返回undefined