一、let与const
1.let
let是变量声明的关键字。
特点:
- 块级作用域:只在声明的代码块内有效 {}
{
let a='a'
console.log(a);//a
}
- 在同一作域内不允许重复声明同一个变量,但可以二次赋值
{ //错误
let a='a';
let a='b'
}
- 没有变量提升 ,暂时性死区
不允许在变量声明之前使用变量,暂时性死区:在声明变量之前无法操作或者读取这个变量。var存在变量提升,即变量可以在声明之前使用,值为undefined
{ //错误
console.log(a);
let a='a';
}
2.const
用于js中定义常量,使用时必须初始化(即必须赋值) 。一旦声明,常量的值就不能改变。
特点:块级作用域
-
不能二次赋值
-
没有变量提升 ,暂时性死区
-
只是保证内存地址是不变的
{
const a =[1,2,3,4]
a.push(7)
console.log(a);
a=[1,2]//错误
}
2.变量的解构赋值
解构赋值可以理解为赋值操作的语法糖,它是针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。代码书写上言简意赅,语义明确,也方便了对象数据的读取操作。
- ES5中赋值变量时,只能直接指定值,但是在ES6中可以写成:
{
//数组
let [a,b,c]=[1,2,3]
console.log(a,b,c);
let a,b,c
[a,b,c=6]=[1,2]
console.log(a,b,c);//1 2 6
}
{
//对象
const a={
name:'一',
age:11,
say:function(){
console.log('a');
}
}
let {name,age,say}=a
console.log(name);
console.log(age);
say()
}
2.1扩展运算符
- 扩展运算符(...)是ES6的语法,用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。
{
let a,other
[a,...other]=[2,3,4,5,6,7]
console.log(a)//2
console.log(other)//[3,4,5,6,7]相当于[a,...[3,4,5,6,7]]=>[2,3,4,5,6,7]
}
{
//占位
//取第一个和第三个值
let a,b
[a,,b]=[1,2,3]
console.log(a,b);//1 3
}
{
let a,b
({a,b}={a:3,b:4})
//在js解析里遇到大括号{}要判断是不是块级作用域,在写对象的时候要用小括号包起来
/*相当于({a:a,b:b}={a:3,b:4}),在es6中键值对出现时,若k=value,可以只写一个*/
console.log(a,b);//3 4
// 如:
let num,total
({a:num,b:total}={a:11,b:22})
console.log(num,total);//11 22
//应用场景 后端返回数据与前端变量名不同
function fn(){
return {
name:'lalal',
nameList:{
name:'JIM'
}
}
}
let b = fn();
let {name:person,nameList:{name:otherperson}}=b
console.log(person,otherperson);//xiaoming JIM
}
- 如果扩展运算符后面是Int类型、Boolen类型、undefined、null这几种类型,都会返回一个空对象,因为它们没有自身属性。
// 等同于 {...Object(1)}
{...1} // {}
// 等同于 {...Object(true)}
{...true} // {}
// 等同于 {...Object(undefined)}
{...undefined} // {}
// 等同于 {...Object(null)}
{...null} // {}
- 自定义的属性和扩展运算符对象里面属性的相同的时候:自定义的属性在扩展运算符后面,则扩展运算符对象内部同名的属性将被覆盖掉。(简单记忆:属性名相同时谁在后边谁就会覆盖上去)
{
let person = {name: "Amy", age: 15};
let someone = { ...person, name: "Mike", age: 17};
someone; //{name: "Mike", age: 17}
}
- 自定义的属性在拓展运算度前面,则变成设置新对象默认属性值。
{
let person = {name: "Amy", age: 15};
let someone = {name: "Mike", age: 17, ...person};
someone; //{name: "Amy", age: 15}
}
二、ES6提供的新的字符串方法及模板字符串
1.模板字符串
1.1普通字符串
{
//let str="cjdujewadnsq
// 开具收款"//错误
//若想换行需要加换行符
let str1="cjdujewadnsq'\n'开具收款"
console.log(str1);
}
1.2模板字符串
反引号``,当遇到字符串与变量拼接的情况使用模板字符串。
- 变量可以直接拼接,内容中可以出现换行符
{
//语法
const name="⼩明"
const age=18
const hobbies="游泳、跑步和打篮球"
// ES5写法
const str1='我的名字是'+name+',我今年'+age+'岁,我喜欢'+hobbies
console.log(str1)
// ES6写法
const str2=`我的名字是${name}, 我今年${age}岁, 我喜欢${hobbies}`
console.log(str2)//会按照书写的格式打印
}
2. 扩展的API
{
let str1 = 'djeru9u324'
console.log('includes', str1.includes('u9u'));//true
console.log('startswith', str1.includes('dje'));//true
console.log('endswith', str1.includes('ww'));//false
//repeat()
let str2 = 'abc'
str2 = str2.repeat(2)
console.log(str2);//abcabc
// padStart(length, str)用于头部补全
let str3 = 'taoa'
// str3=str3.padStart(6,'12')//12taoa
// str3=str3.padStart(5,'12')//1taoa
str3=str3.padStart(3,'12')//taoa 串的长度小于原串直接拿原串
// str3 = str3.padStart(7, '12')//121taoa 串的长度大于原串用拼接的串补位
console.log(str3);
}
三、ES6和ES7提供的新的数组方法及扩展运算符的使用
1.扩展运算符
1.1复制数组
{
let arr1=[1,2,3]
let arr2=arr1//数组名称赋值的时候,赋值的一个指针,而不是克隆一个全新的数组,并没有重新开辟空间,修改arr1,会直接导致arr2的变化。
let arr3=[...arr1]
arr1.push(4)
console.log(arr1,arr2);//1,2,3,4 保存的是指针
console.log(arr3);//1,2,3利用扩展运算符是在内存中新开辟了一块地址。arr3保存的是新的内存地址
}
1.2数组分割
{
let arr = [4, 5, 6, 7]
let [, ...arr4] = arr
console.log(arr4);//5,6,7
}
1.3将数组转化成参数传递给函数
{
function fn(x,y){
return x+y
}
let arr5=[1,2]
console.log(...arr5);//1 2
console.log(fn(...arr5));//3
}
2.fill()
- 替换数组中的元素
arr.fill(value, start, end)
- value:填充值。
- start:填充起始位置,可以省略。
- end:填充结束位置,可以省略,实际结束位置是end-1。
{
const arr = ['a', 'b', 'c', 'd']
//全部替换为9
let arr1 = arr.fill(9)
console.log(arr);//[9,9,9,9]
console.log(arr1);//[9,9,9,9]
//部分替换为6
let arr2 = arr.fill(6, 1, 3) //替换的文本,起始位置,终止位置(管左不管右)
console.log(arr2);// [9, 6, 6, 9]
}
3.find()
- 查找数组中符合条件的某一项
{
const arr = [{ title: 'aa' }, { title: 'bb', id: 1 }, { title: 'c', id: 3 }]
let a = arr.find(function (item) {
return item.title === 'aa'
})
console.log(a);//{title: 'aa'}
}
4.findindex()
- 查找数组中符合条件的某一项的数组的下标
{
const arr = [{ title: 'aa' }, { title: 'bb', id: 1 }, { title: 'c', id: 3 }]
let b = arr.findIndex(function (item) {
return item.id === 3
})
console.log(b);//2
}
5.includes()
- 判断数组中是否存在某个值,返回布尔类型。
{
const arr=[65,3,5,6]
let a=arr.includes(5)
console.log(a);//true
}
6.indexOf()
- indexOf 判断某个值在当前数组中的index值,如果该值不存在返回-1
{
const arr = [65, 3, 5, 6]
let b=arr.indexOf(75)
console.log(b);//-1
}
7.flat()
- 展开数组
-
n维数组展开成为一维数组 flat(n)
{
const arr = [1, 2, 3, ['2nd', 4, 5, ['3rd', 111]]]
let a = [...arr]
console.log('...', a);//[1, 2, 3, Array(4)] 扩展运算符展不开多维数组
let b = [].concat(...arr)//concat 连接
console.log(b);//[1, 2, 3, '2nd', 4, 5, Array(2)]
let c = arr.flat()
console.log(c);//[1, 2, 3, '2nd', 4, 5, Array(2)] 相当于b
let d = arr.flat(3)
console.log(d);// [1, 2, 3, '2nd', 4, 5, '3rd', 111]
}
8.map()
- 数据映射,对数组中的每一项进行同样的操作。
{
const arr = [1, 2, 3]
const arr1 = arr.map(function (item) {
return item * 2
})
console.log(arr1);//[2, 4, 6]
}
注意:map没有实时更新的功能,map执行后原数组的数据发生变化,map不会自动更新。
{
const json = [{ title: 'es6', status: 1 }, { title: 'node', status: 0 }, { title: 'vue', status: 1 }]
let video = json.map(function (item) {
return {
name: item.title,
stustext: item.status ? '已上线' : '未上线'
}
})
console.log('json', json);
console.log('video', video);
//map没有实时更新的功能,map执行后原数组的数据发生变化,map不会自动更新
// json[0].status = 0
// console.log('json', json);//数据会更新
// console.log('video', video);//map不更新
}
9.reduce()
对数组中的每一个元素进行一次回调,升序执行将回调值汇总为一个返回值,并且此返回值在下一次调用该回调函数时作为参数提供。
- reduce(function(acc,currentValue,currentIndex){},{})可以传两个参数,后边的参数是个可选输入,可以输入也可以不输入,可以输入数组也可以不输入数组。
- 第一个参数:回调函数,其中有三个参数:
acc:每次回调之后返回的汇总
currentValue:数组当前回调的值
currentIndex:数组当前回调的值的index
- 第二个参数:可选参数
- 1)如果传入acc就是这个值,不传acc就是数组中的第一项
记录每个字母出现的次数
{
const str='njnjiwejd'
//将字符串转换为数组
const arr=str.split("")
let a=arr.reduce(function(acc,currentValue,currentIndex){
// console.log('acc',acc);
// console.log('curval',currentValue);
// console.log('curIdx',currentIndex);
acc[currentValue]?acc[currentValue]++:acc[currentValue]=1
return acc
},{})
console.log(a);
}
四、ES6和ES8之对象的新特性及新增方法
1.扩展运算符的使用
1.1复制对象
{
const obj1={name:'lalla',age:11}
const obj2={...obj1}
console.log(obj2);//{name: 'lalla', age: 11}
}
1.2设置默认值
{
const obj1 = { name: 'lalla', age: 11 }
const obj3 = { ...obj1, name: 'haha' }
console.log(obj3);//{name: 'haha', age: 11}
}
1.3合并
{
const obj1={name:'lalla',age:11}
const objA={color:'red'}
const obj4={...obj1,...objA}
console.log(obj4);//{name: 'lalla', age: 11, color: 'red'}
}
2.属性初始化的简写
- key和value一样的时候可以只写一个
- 可以省略function
let name = 'lala'
let age = 12
//es5
let es5obj = {
name: name,
age: age,
say: function () {
console.log('es5obj');
}
}
//es6
let es6obj = {
name,//key和value一样的时候可以只写一个
age,
say()/*:function,可以把其省略*/ {
console.log('es6obj');
}
}
//可计算的属性名 Object[key]
let key='gender'
//es5
es5obj[key]='man'
console.log('es5',es5obj);//{name: 'lala', age: 12, gender: 'man', say: ƒ}
//es6
es6obj={
[key]:'woman'
}
console.log('es6',es6obj);//会覆盖之前的值 {gender: 'woman'}
3.新增方法
3.1Object.is()
- 判断是否相同
-
NAN与任何值都不相等,包括它自己本身,但是在Object.is()中没有这一特性
{
let result=Object.is(NaN,NaN)
console.log(result,NaN===NaN);//true false
}
3.2Object.assign()
- 复制对象合并 ,如果对象里包含对象的话那复制过来的是指针
{
let person1={name:'xx',age:11,info:{height:183.6}}
let person2={color:'red'}
Object.assign(person2,person1)
console.log(person2);//{color: 'red', name: 'xx', age: 11, info: {…}}
person1.info.height=188
console.log('p2',person2);//.....height:188
}
3.3Object.keys()
- 遍历对象中的key,返回数组
{
const json={name:'lll',age:18}
console.log(Object.keys(json));// ['name', 'age']
}
3.4Object.values()
- 遍历对象中的values,返回数组
{
const json={name:'lll',age:18}
console.log(Object.values(json));//['lll', 18]
}
3.5Object.entries()
- 遍历键值对,返回数组
{
const json={name:'lll',age:18}
console.log(Object.entries(json));//[Array(2), Array(2)]
let obj={}
for(let key of Object.keys(json)){
obj[key]=json[key]
}
console.log(obj);//{name: 'lll', age: 18}
}
五、Map与WeakMap
1.Map
JavaScript的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制,为了解决这个问题,ES6提供了Map数据结构(本身是个构造函数用来生成Set数据结构)。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串=>值”的对应,Map 结构提供了“值=>值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
{
let obj={
[1n2n3,2]:'a'//错误,原生键值只能用字符串
}
console.log(obj);
}
- 通过构造函数创建⼀个Map
var m = new Map();
- 注意:Map里面也不可以放重复的项。
{
let a=new Map([['a','b']])
a.set('a','b')
a.set('b','c')
console.log(a);//Map(2) {'a' => 'b', 'b' => 'c'}
}
2.Map的内置API
{
let map = new Map()
//set(key, value)添加键值对,如键名已存在,则更新键值对
map.set([1, 2, 3], 'gagg')
console.log(map);//{Array(3) => 'gagg'}
//或者
let map1 = new Map([[{ name: 'lal' }, 'bb'], ['ccc', 'ddd']])
console.log(map1);// {{…} => 'bb', 'ccc' => 'ddd'}
//size返回键值对的数量
console.log(map.size);//1
//get(key)获取指定键名的键值,如不存在则返回 undefined
console.log(map1.get('ccc'));//ddd
//has(key)判断键值对中是否有指定的键名,返回值是布尔值
console.log(map1.has('ggg'));//false
//delete(key)删除指定键名的键值对
map1.delete('ccc');
console.log(map1);//{{…} => 'bb'}
console.log(map1.has('ccc'));//false
//clear()清除所有键值对
map1.clear()
console.log(map1);//Map(0) {size: 0}
}
3.Map遍历器
- keys返回keys数组
- values 返回values数组
- entries 每一对都以数组形式返回
{ key value entry
let obj=new Map([
[{name:'sean'},'sean'],
['age',18]
])
for(let key of obj){
console.log(key);
}
for(let value of obj){
console.log(value);
}
for(let entry of obj){
console.log(entry);
}
}
4.Map遍历方法forEach
{
let obj=new Map([
[{name:'sean'},'sean'],
['age',18]
])
//forEach
obj.forEach((key,value)=>{
console.log(`${key}:${value}`);
})
}
六、Set与WeakSet
Set是ES6给开发者提供的一种类似数组的数据结构(本身是个构造函数用来生成Set数据结构),可以理解为值的集合。它和数组的最大的区别就在于: 它的值不会有重复项。
1.Set
let set = newSet();
- 可以接受一个数组作为参数
- 使用场景:数组去重
{
let arr = [11, 11, 11, 33, 44]
let set = new Set(arr)
console.log(set);//{11, 33, 44}
//把值的集合变一个数组
//let set1=Array.from(set)
//或者
let set1=[...set]
console.log(set1);//[11, 33, 44]
}
2.属性及方法
{
let set = new Set()
let set1 = new Set(['1', 2, 4, 5])
//添加
set1.add(1)
console.log(set1);// Set(5) {'1', 2, 4, 5, 1}
//size 返回成员个数
console.log('size', set1.size);//size 5
//has(value) 判断键值对中是否有指定的值,返回值是布尔值
set.add({ color: 'red' })
console.log(set);//Set(1) {{…}}
console.log('has', set.has({ color: 'red' }));//has false 这样查找{color:'red'}也要占一个空间
//导致内存地址不一样
let item = { color: 'red' }
set1.add(item)
console.log(set1);//Set(6) {'1', 2, 4, 5, 1, …}
console.log('has', set1.has(item));//has true
//delete(value) clear()
}
{
let set = new Set(['a', 'b', 'c', 'd'])
for (let key of set.keys()) {
console.log('key', key);
}
for (let value of set.values()) {
console.log('value', value);
}
for (let entry of set.entries()) {
console.log('entry', entry);
}
}
2.WeakSet
- 数组成员必须是对象
- WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。
- WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( ),values( ),entries( ),forEach( )等方法和size属性。
{
let obj = { name: 'xiaoming' }
let weakset = new WeakSet()
weakset.add(obj)
console.log(weakset);
}
七、数组、对象、Map、Set的区别
1.添加
{
let arr=[]
let obj={}
let map=new Map()
let set=new Set()
let item={fruit:'apple'}
//添加
arr.push(item)
obj['fruit']=item.fruit
map.set('fruit','apple')//set(key,value)
set.add(item)
console.log(arr,obj,map,set);
}
2.查询
{
let arr = []
let obj = {}
let map = new Map()
let set = new Set()
let item = { fruit: 'apple' }
//查询
let rearr = arr.includes(item)
let reobj = 'fruit' in obj
let remap = map.has('fruit')
let reset = set.has(item)
console.log(rearr, reobj, remap, reset);
}
3.修改
{
let arr = []
let obj = {}
let map = new Map()
let set = new Set()
let item = { fruit: 'apple' }
//修改
arr.forEach(item=>{
item.fruit = item.fruit?'peach':''
})
obj.fruit='peach'
map.set('fruit','peach')
set.forEach(item=>{
item.fruit = item.fruit?'peach':''
})
}
4.删除
{
let arr = []
let obj = {}
let map = new Map()
let set = new Set()
let item = { fruit: 'apple' }
//删除
let index = arr.findIndex(item => {
return item.fruit
})
arr.splice(index, 1)
delete obj.fruit
map.delete('fruit')
set.delete(item)
console.log('delete', arr, obj, map, set);
}
八、函数的扩展
1.函数设置默认参数
- es5
{
function es5fn(x,y){
y=y || 'world';
console.log(x+y);
}
es5fn('hello')
es5fn('hello','1111')
}
- es6 :默认值可以直接写到形参上
{
function es6fn(x,y='world'){
console.log(x+y);
}
es6fn('hello')//helloworld
es6fn('hello','1111')//hello1111
}
2.rest
rest是一个形参名,可以自定义,跟扩展运算符搭配使用
{
//rest 是一个形参名,可以自定义 跟扩展运算符搭配使用,可以一次性拿到所有的值
function add(...rest){
let sum=0
for(let value of rest){
sum+=value
}
return rest
}
console.log(add(1,2,3,4));//相当于rest是个数组
//相当于数组展开
console.log(...[1,2,3,5]);
}
3.尾调用
- 在函数调用后返回另一个函数,如果后面还有其他任何运算都不是尾调用
{
//尾调用(理解)
//在函数调用后返回另一个函数,如果后面还有其他任何运算都不是尾调用
function fn1(x){
return(x)
}
function fn2(){
console.log('尾调用');
return fn1(5)
}
function fn3(){
console.log('非尾调用');
return fn1(5)+1
}
fn2()
fn3()
}
4.箭头函数
九、类
1.class
对象是类的实例,类是对象的模板
-
es5中可以通过构造函数添加类的方法(而不是真的类)
{
function Person(name, old) {
this.name = name
this.age = old
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
let a = new Person('a', 11)
console.log(a);
}
- es6中添加了类的概念,可以是class
{
class Person{
constructor(name,age){
this.name=name
this.age=age
}
say(){
console.log(this.name,this.age);
}
}
let a=new Person('a',11)
a.say()
}
2.类的继承 (!)
{
class teacher{
constructor(name='老师'){
this.name=name
}
}
class student extends teacher{
constructor(old,name='同学'){
super(name)//代表父类的构造函数即teacher里的constructor,子类必须执行一次
//并没有手动写name,name继承于teacher
this.age=old
}
}
let a=new student(18)
console.log(a);
}
3.补充set方法、get方法
class a{
constructor(name='xm'){
this.name=name
}
get fullname(){
return this.name+'lastname'
}
set fullname(value){//set 和 get的函数名可以是相同的
this.name=value
}
}
let man=new a()
console.log(man);// a {name: 'xm'}
console.log(man.fullname);//相当于获取(get) xmlastname
man.fullname='xsd'//相当于设置set
console.log(man.name);//xsd
console.log(man.fullname);//xsdlastname
4.静态方法
- static 不能由具体实例调用 ,只存在类原型上
{
class Person{
constructor(name='xm'){
this.name=name
}
//静态方法
static say(child){
console.log(child.name);
}
}
let p=new Person('jim')
console.log(p);//a {name: 'jim'}
// p.say()//p.say is not a function 只有原型上有
Person.say(p)//jim
}