?前言
ES6是非常重要的JavaScript版本,新增了很多的语法形式,提高了JavaScript程序的功能,新增的语法:
let const定义变量? ? ?` `? ? 模板字符串
立即执行函数/自执行函数? ? ?数组/对象的解析
箭头函数? ? ?this指向? ?promise??
async? await?
......
一、立即执行函数
普通函数分为 定义封装函数 和 调用执行函数 两个步骤
? ? ? ? 封装函数时,只是在定义一个函数,并没有调用执行函数
立即执行函数一般都是匿名函数
? ? ? ? 在封装定义函数的同时 就调用执行函数
语法形式:
立即执行函数后必须要写分号
? ? ? ? ?(匿名函数)();
? ? ? ? ?!匿名函数();
? ? ? ? ~匿名函数();
立即执行函数带有参数
? ? ? ? (function(形参){})(实参);
//普通函数
//只是封装定义函数,没有调用执行函数
function fun(string){
console.log(string);
}
//调用执行函数
fun('北京');
//立即执行函数
//(匿名函数)() 在封装定义匿名函数的同时 调用执行函数
(function(){console.log(111)})();
!function(){console.log(222)}();
~function(){console.log(333)}();
//立即执行函数 带有参数
(function(string){console.log(string)})('武汉');
二、箭头函数
ES6新增的一种 匿名函数的语法形式,箭头函数是一种非常重要的匿名函数的语法形式
本质作用:为了配合ES6新增的class构造函数定义的,为了配合面对对象编程定义的
注:我们目前先了解掌握它的基本语法,后面具体应用,以后再讲
? ? ? ? function(){}? ? 匿名函数
? ? ? ? () => {}? ? ? ? ? 箭头函数
箭头函数的关键作用:
? ? ? ? 箭头函数 和 普通的函数程序 this指向不同
语法形式1
? ? ? ? () => {}
语法形式2
? ? ? ? 如果只有一个形参,可以不写()
? ? ? ? 形参 => {}
语法形式3
? ? ? ? 如果只有一行代码,可以不写{}
? ? ? ? 形参 => 程序代码;
举例:有一div标签
//获取div标签对象
const oDiv = document.querySelector('div');
//普通的匿名函数
oDiv.addEventListener('click',function(){console.log(111)});
//语法形式1 () => {}
oDiv.addEventListener('click',() => {console.log(222)});
//语法形式2
//如果只有一个形参可以不写() 形参 => {}
oDiv.addEventListener('click',e => {console.log(e)});
//语法形式3
/如果只有一行代码可以不写{} 形参 => 程序代码;
oDiv.addEventListener('click',e => console.log(e));
三、this指向
this是面向对象编程中,非常重要的关键词
this是函数中特有的关键词,调用执行函数程序时,JavaScript程序自动设定this关键词的指向
this指向的理解
this是JavaScript中函数的关键词,本质是一个对象,对象中存储内存地址,这个内存地址指向堆中的一个独立的存储空间,所谓的this指向就是this这个对象存储的内存地址,指向的存储空间,简单的理解就是,this中存储的数据数值
在不同的函数程序中,this指向是不同的,也就是不同的函数中,this存储的内存地址和指向的存储空间是不同的
普通函数的this指向
如果不确定函数的this指向,可以直接输出查看this指向
? ? ? ? this指向是window顶级对象
? ? ? ? ? ? ? ? ? 实际项目中没有什么作用
? ? ? ? ? ? ? ? ? 声明式函数,赋值式函数,定时器,延时器,forEach ......
? ? ? ? this指向是事件源
? ? ? ? ? ? ? ? ? 事件处理函数中的this指向
? ? ? ? this指向是数组/对象
? ? ? ? ? ? ? ? ? 存储在数组/对象中的函数
//声明式函数
function fun1(){console.log(this)};
fun1();
//赋值式函数
const fun2 = function(){console.log(this)};
fun2();
//定时器
setInterval(function(){console.log(this)},1000);
//延时器
setTimeout(function(){console.log(this)},1000);
//forEach
const arr = [1,2,3,4,5];
arr.forEach(function(){console.log(this)});
//以上this指向是window,实际项目中,没有什么作用
存储在数组中的函数
const arr = [1,2,3,function(){console.log(this)}];
//调用执行数组中的函数
//函数的this指向的就是数组本身
arr[3]();
存储在对象中的函数
const obj = {
name:'张三',
age:18,
sex:'男',
addr:'北京',
fun:function(){
console.log(this);
//this就是对象本身,可以通过this.属性,调用属性值
console.log(this.name);
console.log(this.age);
console.log(this.sex);
console.log(this.addr);
},
};
//调用执行对象中的函数
obj.fun();
箭头函数的this指向
普通函数的this指向,不是固定的,可以改变
箭头函数的this指向,是固定的,不能改变的
箭头函数的this指向,是父级程序的this指向,如果没有父级程序/父级程序没有this,那么箭头函数的this指向是window
//没有父级程序,箭头函数this指向是window
const fun1 = () => {console.log(this)};
fun1();
//获取div标签对象
const oDiv = document.querySelector('div');
//普通函数 事件处理函数中的this指向事件源标签对象
oDiv.addEventListener('click',function(){
console.log(this);
}
//箭头函数 事件处理函数中的this指向是父级程序的this指向
//没有父级程序 this指向是window
oDiv.addEventListener('click', () => {
console.log(this);
})
对象中函数
const obj = {
name:'张三',
age:18,
//普通函数 对象中的普通函数 this指向是对象本身
fun1:function(){ console.log(this) },
//箭头函数 对象中的箭头函数 this指向是父级程序
//当前这个箭头函数 父级程序是 obj这个对象
//对象是没有this 箭头函数的this指向是window
fun2:() => {console.log(this)},
fun3:function(){
//赋值式 定义的函数程序
//this指向应该是window
const fun4 = function(){console.log(this)};
fun4();
//箭头函数 定义的函数程序
//this指向应该是父级程序的this指向
//当前函数fun5的父级程序是函数fun3
//函数fun3是匿名函数 this指向是obj这个对象
//函数fun5 this指向是 父级函数fun3的this指向 是obj这个对象
const fun5 = () => {console.log(this)};
fun5();
}
}
obj.fun1();
obj.fun2();
obj.fun3();
四、改变this指向
通过JavaScript提供的函数方法,改变普通函数的this指向
箭头函数的this指向,只能是父级程序的this指向
语法1:call()? ? ?apply()
在执行调用函数时,改变函数的this执行,一般是修改指向为其他对象
call()语法
? ? ? ? 函数.call( 参数1,其他参数);
? ? ? ? ? ? ? ?参数1? ? ? ? 设定的函数新的this指向
? ? ? ? ? ? ? ?其他参数? ?原始函数需要的实参
apply()语法
? ? ? ? 函数.apply(参数1,[其他参数]);
? ? ? ? ? ? ? ?参数1? ? ? ? 设定的函数新的this指向
? ? ? ? ? ? ? ?其他参数? ?原始函数需要的实参
const obj1 = {name:'王昭没有君啊',age:18,sex:'女'};
const obj2 = {name:'王昭君',age:18,sex:'男'};
function fun1(a,b,c){ //声明式函数
console.log(this);
console.log(this.name);//this指向 默认是window,输出空字符串
console.log(a,b,c);
}
fun1(100,200,300);
?通过call() 改变 函数this指向
const obj1 = {name:'王昭没有君啊',age:18,sex:'女'};
const obj2 = {name:'王昭君',age:18,sex:'男'};
function fun1(a,b,c){
console.log(this);
console.log(this.name);
console.log(a,b,c);
}
//参数1将函数fun1的this指向设定为obj1对象
//之后的参数是原始函数fun1执行时需要的实参
fun1.call(obj1,'北京','上海','广州');
//参数1将函数fun1的this指向设定为obj2对象
fun1.call(obj2,'a','b','c');
?通过apply()改变函数this指向
const obj1 = {name:'王昭没有君啊',age:18,sex:'女'};
const obj2 = {name:'王昭君',age:18,sex:'男'};
function fun1(a,b,c){
console.log(this);
console.log(this.name);
console.log(a,b,c);
}
//参数1将函数fun1的this指向设定为obj1对象
//之后的数组是原始函数fun1调用时需要的实参
fun1.apply(obj1,[100,200,300]);
语法2:bind
生成一个新的函数,同时改变this指向
const 变量 = 函数.bind(参数1,其他参数);
? ?参数1? 设定的生成的新函数的this指向
const obj1 = {name:'王昭没有君啊',age:18,sex:'男'};
function fun1(){
console.log(this);
console.log(111);
}
fun1();
//通过bind() 生成一个新的函数 同时 改变this指向
//生成一个新的函数fun2 所有的函数程序内容都和函数fun1相同
//只是this指向 被设定为 obj1
const fun2 = fun1.bind(obj1);
fun2();
const obj1 = {name:'王昭没有君啊',age:18,sex:'男'};
function fun1(a,b,c){
console.log(a,b,c);
console.log(this);
}
fun1(100,200,300);
//生成新的函数fun2 程序代码和fun1相同 只是修改了this指向
const fun2 = fun1.bind(obj1);
//调用时需要输入 实参数据
fun2('x','y','z');
//生成新的函数fun3 程序代码和fun1相同 只是修改了this指向
//并且给形参绑定了实参数据
const fun3 = fun1.bind(obj1,'a','b','c');
fun3('d','e','f');
?五、合并展开运算符
分为合并运算符和展开运算符,其符号都是...,在不同位置有不同的作用
展开运算符
定义在函数的实参位置就是展开运算符
function fun(){}
fun(...数组);
作用:
将数组单元的数据展开一 一对应的赋值给函数的形参
function fun(a,b,c,d,e,f){
console.log(a,b,c,d,e,f);
}
const arr = [100,200,300,400,500,600];
//一般情况下,我们第一想法就是遍历数组,将数组数值逐一当作实参传给形参
//fun(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]);
//运用展开运算符
//将数组arr中每一个数据单元的数据,展开一一对应的赋值给函数的实参
fun(...arr);
?合并运算符
定义在函数的形参位置就是合并运算符
function fun(a,b,...arr){}
作用:
以数组的形式存储对应的实参
//正常情况下,一个形参只会存储一个实参
//function fun(arr){
// console.log(arr);//输出100
//}
//fun(100,200,300,400);
//运用合并运算符定义形参
//第一个实参赋值给第一个形参a
//第二个实参赋值给第二个形参b
//之后所有的实参,以数组的形式存储在arr中
function fun2(a,b,...arr){
console.log(a);
console.log(b);
console.log(arr);
}
fun2(100,200,300,400,500,600,700);
?六、解构赋值
解构赋值是一种将数组/对象数据一 一对应赋值给变量的简易语法形式
数组的解构赋值
let [变量1,变量2,变量3...] = 数组;
将数组中的数据 解构之后一 一对应的赋值给变量
一个数组单元对应一个变量,一个多维数组对应一个[]
const arr = [10,20,30,40,50,[60,70,80,[90,100]]];
//普通的[]语法,获取数据赋值
//let a = arr[0];
//let b = arr[1];
//let c = arr[2];
//数组的解构赋值
let [a,b,c,d,e,[f,g,h,[i,j]]] = arr;
console.log(a,b,c,e,f,g,h,i,j);
?对象的解构赋值
let {键名1,键名2,键名3...} = 对象;
以键名作为变量从对象中获取数据存储在以键名作为变量名称的变量中
const obj = {name:'王昭没有君啊',age:18,sex:'男',addr:'北京',phone:{id1:180,id2:3527,id3:4102},email:['1@qq.com','2@qq.com','3@qq.com']};
//使用name作为键名从对象obj中获取数据,存储到变量中
let {name:a,age:b,sex:c,addr:d,phone:{id1:p1,id2:p2,id3:p3},email:[e1,e2,e3]} = obj;
console.log(a,b,c,p1,p2,p3,e1,e2,e3);
七、map数据类型?
map数据类型是ES6新增的数据类型,适合复杂项目中的一种数据类型,类似于对象结构
创建map数据类型
const?变量 = new Map( [ [键名,键值] ,[键名,键值],[键名,键值]...] );
函数方法
设定:map对象.set(键名,键值)
获取:map对象.get(键名)
删除:map对象.delete(键名)
清空:map对象.clear()
循环遍历:
map对象.forEach(function(参数1,参数2,参数3){})
? ? ? ? 参数1? ? map中的键值
? ? ? ? 参数2? ? map中的键名
? ? ? ? 参数3? ? 原始map
//创建map数据类型
const map = new Map( [ ['name','王昭没有君啊'], ['age',18] ,['sex','男']] );
//新增
map.set('addr','北京');
map.set('phone',123);
//获取
console.log(map.get('addr'));
//删除
map.delete('name');
//清空
map.clear();
//循环遍历
map.forEach(function(a,b,c){
console.log(a,b,c);
})
console.log(map);
八、set数据类型
set数据类型是ES6新增的数据类型,类似于数组的数据类型,set数据类型不会存储重复的数据
创建set数据类型
const set = new Set(数组);
函数方法
新增:set对象.add()
删除:set对象.delete()
清空:set对象.clear()
判断有没有:
set对象.has()
有 true? 没有false
循环遍历
set对象.forEach(function(参数1,参数2,参数3){})
? ? ? ? 参数1? ? set中的键值
? ? ? ? 参数2? ? set中的键名
? ? ? ? 参数3? ? 原始set
//创建set数据类型
const set = new Set( [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5] );
//新增
set.add(100);
set.add(200);
set.add(300);
//删除
set.delete(200);
//清空
set.clear();
//判断有没有
console.log(set.has(5));//输出true
//循环遍历
set.forEach(function(a,b,c){
console.log(a,b,c);
})
console.log(set);
|