一、ES6简介
1、ECMAScript与JavaScript的关系
ECMAScript是JavaScript的规则,JavaScript是ECMAScript的一种实现。
2、ES6好处以及优势
- let、const变量的声明(默认参数)
- 变量的解构赋值
- 字符串模板(多行字符串)
- 箭头函数
- Promise对象
- Class类的概念
- Module模块化
3、ES6与ES5的关系
ES6是ES5的语法糖
4、 ES6与ES7的关系
与ES6相比,ES7增加了关键词async的功能,并且可以使用await轻松直接调用函数来实现异步调用同步化。
二、ES5回顾
1、 严格模式
1)严格模式的原因
- 消除JavaScript语法上的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全处、保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为新版本JavaScript做好铺垫;
2)关键词:‘use strict’
3)严格模式的特例
- 变量使用前必须要声明
var age=12;
console.log(age);
- 不能直接使用this指向
function f(name,age) {
this.name=name;
this.age=age;
return {a:this.name};
}
console.log(f("cn",20));
- eval函数存在作用域
var a="cn";
eval('var a="cn";console.log(a)');//cn1
console.log(a);//cn
2、JSON
1)JSON.parse()方法:将类似数组或对象格式的字符串转化为JSON格式的对象
var a="[1,2,3,4,5,6,7]";
console.log(typeof a);
console.log(typeof JSON.parse(a));
2)JSON.stringify()方法:将对象或数组转化为字符串
var b=[1,2,3,4,5];
console.log(typeof JSON.stringify(b));
3)实现数组或对象的深拷贝:JSON.parse(JSON.stringify(obj))
3、Object扩展
1)Object.create(原对象,[属性])
创建一个新的对象,原对象不会改变
var obj1={name:"cn",age:20};
var obj2=Object.create(obj1,{
sex:{
value:"女",//设置新增属性的值
enumerable:true,//设置新增属性是否可以枚举显示,默认值是false(不会在输出对象引用中显示)
writable:true,//设置新增属性是否可以修改,默认值是false
configurable:true//设置新增属性是否可以删除,默认值是false
},
sex2:{
value:"男",
enumerable:true,
}
})
console.log(obj1);//{name:"cn",age:20}
obj2.sex = "女孩";
delete obj2.sex;//删除属性
console.log(obj2);
2)Object.defineProperties(原对象,扩展属性)
为指定对象定义扩展多个属性,会改变原对象的值
var obj1={name:"cn",age:20};
var obj2=Object.defineProperties(obj1,{
sex:{
get() {//获取该属性值的时候被调用
console.log("我是get方法");
return "女";
},
set(v) {//设置该属性值的时候被调用
console.log("我是set方法"+v);
}
}
});
obj2.name="cn1";
obj2.sex="男";
console.log(obj1);
console.log(obj2.sex);
4、Array扩展
1)引用名.forEach()
没有生成值或返回值,只可以循环遍历数组。
let arr=[1,2,3,4,5];
var arr1=arr.forEach(function (item ,index) {
return index;
});
console.log(arr1);//undefined
2)引用名.map()
可以根据返回值进行生成新的数组(即返回值组成的数组),也可以循环遍历数组
var arr2=arr.map(function (item,index) {
return index>3;
})
console.log(arr2);//数组
3)引用名.filter()
可根据返回值判断:返回值为true,则会将对应的数组的值返回并生成新的数组。
功能;过滤数组。
var arr3=arr.filter(function (item ,index) {
//return index>2;
return true;//只是用来判断当前值,是否添加到新的数组中。
});
console.log(arr3);
5、函数扩展
1)函数名.bind(obj)
将函数内部的this绑定为obj,并将函数返回
function f(name,age) {
this.name=name;//cn
this.age=age;//20
console.log(this.name);
return {name:this.name,age:this.age};
}
var obj={};
//bind方法将自定义对象和this进行绑定
f.bind(obj)("cn",20);
console.log(f.bind(obj));
6、let和const
1) 语句块
{语句块}
for(){语句块}
if(){语句块}
function a(){语句块}
2)顶层对象
在浏览器环境下,顶层对象是window和_self;在Node中,顶层对象是global。ES2020在标准语言的层面,引入globalThis作为顶层对象,在任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指全局下的this。
3) let
定义变量
4) const
定义常量,声明的同时需要初始化。当数据类型为Number、Boolean、String时,值不可改变;但是对对象或数组时,值可以改变,因为声明的变量相当于指向内存的地址。
注:将对象冻结:Object.freeze()
5) let和const特性
- 块级作用域
- 不存在变量提升,暂时性死区(TZD)
- 同一作用域,不能重复声明变量
6)let和var的区别
- 作用域不同,let是块作用域,var是函数作用域;
- let在同一作用域不能重复声明,var可以覆盖同名变量;属于TDZ问题
- let不存在变量声明提升,var存在;要遵守先声明后使用的原则
7、变量的解构赋值和默认值
1)解构
概念:ES6允许按照一定的模式(即规则),从数组和对象中提取,对变量进行赋值。
解构赋值肯定有赋值运算符,赋值运算符左边的 {} 或 []是模式,右边的是对象或数组。
对象的大括号不是作用域
2)数组的解构赋值
let [foo,[[bar],c]] = [1,[[2],3]];//1 2 3
let [,,third]=["foo","bar","baz"];//baz
let [x,,y]=[1,2,3];//1 3
let [head,...tail]=[1,2,3,4];//1 [2,3,4]
let [x,y,...z]=["a"];//a undefined []
let [bar,foo]=[1];//1 undefined
let [x,y]=[1,2,3];//1,2
let [a,[b],d]=[1,[2,3],4];//1 2 4
let [x,y,z]=new Set(['a','b','c']);//a b c
let [foo=true]=[];//true
let [x,y='b']=['a'];//a b
let [x,y='b']=['a',undefined];//a b
let [x=1]=[null];//null
let [x=1,y=x]=[];//1 1
let [x=1,y=x]=[2];//2 2
let [x=1,y=x]=[1,2];//1 2
let [x=y,y=1]=[];//报错
function f() {
console.log("aaaa");
return "bbb";
}
let [x=f()]=["sdfsdfsdf"];//惰性解构赋值
console.log(x);//sdfsdfsdf
3)对象的解构赋值
对象的属性没有次序,变量必须与属性同名才能取到正确的值。
let {log,sin,cos}=Math;//[Function: log] [Function: sin] [Function: cos]
let {foo:a,foo1:b}={foo:"aaa",foo1:"bbb"};
console.log(a,b);//aaa bbb
let obj={};
let arr=[];
({a:obj.prop,b:arr[0] }={a:"asdasdasd",b:true })//将解构赋值的对象放到()中,可以抵消{}的代码块作用
console.log(obj);//{ prop: 'asdasdasd' }
console.log(arr);//[ true ]
let {log}=console;
log("aaaaaaa");//这两行代码相当于console.log();
let {x = 3} = {};//3
let {x, y = 5} = {x: 1};//1 5
let {x: y = 3} = {};//报错x is not defined 3
let {x: y = 3} = {x: 5};//报错 5
let {x = 3} = {x: undefined}; //3
let {x = 3} = {x: null};//null
({} = [true, false]);
({} = 'abc');
({} = []);
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;//1 3
let x;
//{x} = {x: 1};
({x} = {x: 1});//1
4)解构赋值的作用
- 交换值
let a = 1;
let b = 2;
let c = 3;
[a,b,c] = [b,c,a];
console.log(a,b,c);//2 3 1
- 从对象或数组中解构所需要的值
let obj = {
a:{
b:"bbb",
c:"ccc",
d:{
e:"eee"
}
}
};
let {a:{d:{e}},a:{d}}=obj;
console.log(e);//eee
console.log(d);//{ e: 'eee' }
//如果要解构最深层,它的上一级一定要有
console.log(c);//报错,未解构的变量是无法打印的
//解构的时候是一一对应的
- 从函数的返回值中解构所需要的值
function f(){
return [1,2,3,4];
}
let [,a,,,b]=f();
console.log(a,b);//2 undefined
- 函数参数的解构(支持不完全解构)
function f([a,b,c,d]){
return a+c;
}
console.log(f([1,,7,]));//8
- 可以解构map数据结构类型的key-value
let map = new Map();
map.set("a","aaa");
map.set("b","bbb");
// console.log(map);
for(let [index,value] of map){
// console.log(value);
console.log(index)
}
- 从指定的模块中解构对应的方法
const {readFile}=require("fs");
三、模板字符串
`字符内容${变量输出}字符内容`
注:${ }中的值:
- 变量
- 任意javascript表达式
- 获取对象的属性
- 调用函数
四、对象的扩展
1、对象的简写
1)对象属性名的简写
let a="aaa";
let b={a};
console.log(b);//{ a: 'aaa' }、
function f() {
let name="cn";
let age=20;
let sex="女";
return {name,age,sex};//相当于{name:name,age:age,sex:sex}
}
console.log(f());//{ name: 'cn', age: 20, sex: '女' }
2)对象方法名的简写
let a={
f(){
console.log("aaa");
},
f1(){
console.log("aaaaa2");
}
}
//调用
a.f1();//aaaaa2
let aa="haha";
let obj={
a:"saddfsa"
};
let obj2={
[aa]:"sadsfd"
}
console.log(obj2);//{ haha: 'sadsfd' }
console.log(obj2[aa]);//sadsfd
console.log(obj2.haha);//sadsfd
function f(aname) {
return{
[aname]:"cn"
}
}
console.log(f("a").a)//cn
function f(fnname) {
return{
[fnname](){
console.log("我是函数,缺省名字的函数")
}
}
}
console.log(f("aa"));//{ aa: [Function: aa] }
console.log(f("aa").aa);//[Function: aa]
f("aa").aa();//我是函数,缺省名字的函数
2、对象中变量
1)变量做属性名
let name = 'cn';
const a = {
'age':20,
[name]:'cc'//name是一个变量
};
console.log(a['age']);//20
console.log(a[name]);//cc
console.log(a['cn']);//cc
2)变量做方法名
let obj={
['na'+'me'](){
return 'cn';
}
};
obj.name();
五、箭头函数
1、语法
()=>{}
2、参数
1)无参数
let f=()=>{
cnsole.log('a');
}
1)一个参数
可将()省略
let f=n=>{
consle.log('a');
}
1)两个及以上参数
var fu = (n,m=10)=>{
return n*m;
}
3、返回值
1)函数体内是一条语句
{}可省略
let f=n=>console.log(n);
2)函数体内是一条语句,并且是return关键词
省略{}和return
let f=(n,m)=>n*m;
4、使用场景
箭头函数的两个不适用场景:
- 对象里面
- 事件的回调函数
button.on('click',function(e){
console.log(this)
})
1)回调函数中的箭头函数
let timer=setTimeout(()=>{
console.log(1);
},1000);
2)参数中的箭头函数
function fn(f,a){
console.log(a);
}
fn(()=>{
console.log('我是参数箭头函数');
},10);
5、箭头函数中this的使用规则
箭头函数的this不绑定当前调用者,只与箭头函数定义的上下文环境有关。
1)全局函数中的this
function fun(){
console.log(this);//window
}
let fun1 = n =>{
console.log(this); //window
}
2)事件处理函数中的this
let oDiv = document.getElementById("box");
oDiv.onclick = function () {
console.log(this);//div
}
oDiv.onclick = ()=>{
console.log(this); //window
}
3)对象方法中的this
function Person() {
this.eat = function () {
return function () {
console.log(this); //global
}
}
}
let p = new Person();
p.eat()();
function Dog() {
this.eat = function () {
return ()=>{
console.log(this); //Dog
}
}
}
let d = new Dog(); d.eat()();
6、箭头函数的特性
- 箭头函数是匿名函数,不绑定自己的this,arguments,super,new.target
- 箭头函数会捕获其所在上下文的this值,作为自己的this值,在使用call/apply绑定时,会改变this指向。
- 箭头函数不绑定arguments,取而代之用rest参数运算符解决
- 箭头函数不能作为构造函数,和 new 一起用就会抛出错误
六、ES6中的运算符
1、rest剩余参数运算符
将以“,”隔开的参数转换为数组
注:剩余参数运算符一定要在形参的最后
function f(b,c,...a) {
console.log(a,b,c);//[3, 4, 5, 6, 7, 8, 9, 10, 11] 1 2
}
f(1,2,3,4,5,6,7,8,9,10,11);
2、spread扩展运算符
将一个数组转为用逗号隔开的参数,通常使用在实参的传递中
用于:给函数传参的时候,不确定传参的个数,并且还要调用的时候
function f(a,b,c,d,e) {
console.log(a,b,c,d,e);// 1 2 3 undefined undefined
}
let arr=[1,2,3];
f(...arr);
1)spread 扩展运算符的应用场景:
- 复制、合并数组或对象
(一维数组:深拷贝;多维数组:浅拷贝)
//复制数组
let arr=[1,2,3];
let arr2=[...arr];//深拷贝(值)
console.log(arr2);//[ 1, 2, 3]
//合并数组
let arr=[1,2,3];
let arr2=[4,5,6];
let newArr=[...arr,...arr2];//合并拷贝,深拷贝(值)
console.log(newArr);//[ 1, 2, 3, 4, 5, 6 ]
- 将类似数组或对象转为真正的数组。
let set=new Set();
set.add("aaaa");
set.add("bbbb");
console.log([...set]);//[ 1, 2, 3, 4, 5, 6 ]
七、Symbol
ES第7种数据类型(基本数据类型)
1、定义Symbol类型变量,无参形式
即使使用了参数,参数相当于描述
let a=Symbol();
let b=Symbol();
console.log(a===b);//false
2、Symbol的使用
let a=Symbol();
let obj={
//变量名做属性名
[a]:"hahaha"
}
obj[a]="aaaaaaa";//修改
console.log(obj[a]);//aaaaaaa
let a=Symbol();//生成唯一的哈希值
let b=Symbol();//生成唯一的哈希值
let obj={
[a]:"hahaha"
}
obj[b]="aaaaaaa";
console.log(obj);//两个 { [Symbol()]: 'hahaha', [Symbol()]: 'aaaaaaa' }
3、模拟实现私有属性
function Person() {
let a=Symbol();
let b="bl";
this[a]=()=>{
console.log("我是私有属性");
}
this[b]=()=>{
// this[a]();
console.log("我是单独的方法");
return a;
}
}
const p=new Person();
// console.log(p);//Person { bl: [Function], [Symbol()]: [Function] }
p[p.bl()]();
p.bl();
4、Symbol的for方法可以将两个Symbol定义成同一个Hash
let a=Symbol.for("aaa");
let b=Symbol.for("aaa");
console.log(a===b);//true
console.log(typeof a);//symbol
3、ES6中的Symbol类型有什么作用?
ES6新增了Symbol数据类型,它用来生成一个独一无二的值,Symbol数据常用来给对象属性赋值,让对象属性具备唯一性,不容易被覆盖。
八、Set和Map数据结构
1、Set数据结构
类似数组,与数组的区别在于其内部成员是唯一的(即没有重复元素)。
Set数据结构本身可以去重(数字类型,布尔类型,字符类型)
注:同一变量名声明的数组可能去重,在未重新赋值的情况下可以去重,只要重新赋值了即使与原来的值相同也不能去重;不同变量存储的数组不会去重(因为存的是地址)
1)语法
let set = new Set(数组);//注:参数可以省略
2)常用属性
- size:获取set结构内元素的数量。
3)常用方法
- add(value):添加某个值,返回 Set 结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功,如果元素不存在代码不会报错可以正常执行
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
- forEach:遍历Set结构内的元素。
4)Set用来过滤数组重复数据:let arr = […new Set(arr)];
2、Map数据结构
类似对象,区别在于对象只接受字符串作为键名,而
Map的键名可以是任意类型。
1)语法
let set = new Map(初始化的值);//注:参数可以省略
2)常用属性
- size:获取Map结构内元素的数量。
3)常用方法
- set(key,value):添加一个键值数据。
- get(key):根据key获取value。
- has(key):返回一个布尔值,表示map集合是否包含当前key的成员。
- delete(key):根据指定的key删除数据。
- clear():清除所有成员,没有返回值。
- forEach:遍历Map集合使用forEach。
九、Iterator遍历器
1、ES6中的四种数据结构:
数组(Array)、对象(Object)、Map、Set
2、概念
Iterator是一种接口,所以的数据结构只要部署了接口,都可以进行遍历。
作用:循环遍历输出
Symbol.iterator是属性,本身也是封装好的函数,让定义好的数据结构可以遍历
3、ES6中天生可以遍历的:
Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象
4、遍历
let arr=["a","b","c","d","e"];
let it=arr[Symbol.iterator]();//将遍历器属性绑定到自定义的数据结构中,这里定义的变量it相当于一个指针
it.next();//{value:"a",done:false}
it.next();//{value:"a",done:false}
console.log(it.next());//{value:"a",done:false}
//第六次调用it.next()输出 {value:undefined,done:true}
for(let item of it){
console.log(item);//d e
// console.log(item.next());//报错 如果使用for...of遍历遍历器指针,则不能再使用next()方法
}
十、Generator函数
是ES6提供的一种异步编程解决方案,封装了多个内部的状态;
1、Generator函数的定义
定义的关键词:*(用来修饰函数名) 、yield(用来定义状态)
function *f() {
yield "我是状态一";
yield "我是状态二";
yield "我是状态三";
return "我是G函数返回值";
}
2、Generator函数的调用
1)无参
let git=f();
//获取Genertor函数中的状态
//console.log(git.next());//{ value: '我是状态一', done: false }
//console.log(git.next());//{ value: '我是状态二', done: false }
//注:采用for...of循环只能输出generator函数的状态,无法拿到return的返回值
for (let item of git){//Generator函数默认实现了遍历器接口Symbol.iterator
console.log(item);//我是状态一 我是状态二 我是状态三
}
git.next();
git.next();
console.log(git.next());
console.log(git.next());//{ value: '我是G函数返回值', done: true } 拿到return的返回值
console.log(git.next());//此时{value:undefined,done:true} 再继续git.next()都是这个值
2)可以接受参数的next()方法
function * f1() {
let a=yield "我是状态一";
console.log("我是yield一的输出"+a);
let b=yield "我是状态二";//yield "我是状态二";let a="我是next传参二";
console.log("我是yield二的输出"+b);
yield "我是状态三";
return "我是G函数返回值"
}
let gitf1=f1();
//yield关键词本身具备懒惰原理,
//next参数会赋值给上一个状态,使用next()方法传参,yield的懒惰性,会将参数赋值给上一个状态,即是上一个状态的值
console.log(gitf1.next("我是next传参一"));
console.log(gitf1.next("我是next传参二"));
console.log(gitf1.next("我是next传参三"));
3、Generator函数用同步思想解决异步
function * f() {
let a=yield getData();
console.log(a);
}
let fnn=f();
function getData() {
$.get("./user.json").then((data)=>{
//console.log(data);
//f().next(data);//这样写默认看成了f()这个方法的调用
fnn.next(data);
})
}
fnn.next();
十一、Promise对象
Promise和callback一样,目的都是为了异步数据传递,比如ajax请求数据的传递
1、概念
异步编程的一种解决方案,也称之为一个容器,黑箱操作;
2、特点:
-
对象的状态不受外界影响;
-
一旦状态改变,就不会再变; 状态不可逆 不能互相转换
3、状态:
pending(进行中)、fulfilled(成功)对应的方法resolve()、rejected(失败)对应的方法reject()
4、缺点:
-
无法取消Promise;
-
不设置回调函数,内部抛出的错误不会反应到外部
-
pending状态,无法确定进度;
5、对象的实例方法
Promise对象的结果有两个方法:resolve()–已成功(fulfilled) reject()–已失败(rejected)
//1、resolve()
//2、reject()
//例一
function f(){
return new Promise((resolve,reject)=>{
setTimeout(resolve,3000,"我是字符串");//setTimeout的第三个参数是用来给第一个参数赋值的
})
}
//3、then()获取成功状态的值
f().then((data)=>{
console.log(data);//3s后 输出 我是字符串
})
//console.log(f());//Promise { <pending> }
//例二:用伪代码来表示Promise对象的一个状态传值(实例)
function f() {
return new Promise((resolve,reject)=>{
if(1)
resolve("代码执行成功")
else
reject("代码执行失败")
})
}
//例三:
function f() {
return new Promise((resolve, reject) => {
reject("想用失败传值");
})
}
// Promise对象的then方法,参数一是成功的回调函数,参数二是失败的回调函数(通常不建议使用)
f().then((data)=>{
console.log(data);
},(error)=>{
console.log(error)
})
//例四
function f() {
return new Promise((resolve, reject) => {
resolve("想用成功传值");
reject("想用失败传值");
// console.log(a);
// let a = 2;
// throw关键词 抛出关键词 可以抛出自定义错误
// throw new Error("我是自定义的错误!")
})
}
f().then((data)=>{
console.log(data);
}).catch((err)=>{//4、catch()方法可以捕获错误、异常、失败的传值
console.log(err.message);
}).finally(()=>{//5、finally()方法,最终方法,不管Promise对象是成功状态,还是失败状态,还是出现错误,finally方法都会被执行
console.log("我是finally");
})
//6、all()方法
// 当all方法中全部都是成功状态的时候,会以数组的形式输出全部成功的结果;
// 当all方法中存在失败状态的时候,那么它会返回第一个失败的结果;
//7、race()方法:只会返回第一个Promise的状态,不论成功还是失败
十二、async函数
1、简介
async函数,本质就是Generator函数的语法糖;
语法:将Generator函数的*换成async(在function前),将yield换成await;
返回一个Promise对象,可以添加then()方法添加回调函数;
function f() {
return new Promise((resolve,reject)=>{
setTimeout(resolve,3000,"我我");
})
}
async function testAsync() {
let a=await f();//await可以将异步操作同步化。
console.log(a);
}
testAsync()
//async关键词可以独立出现,但是await关键词不能独立出现,如果需要使用await必须用async来修饰函数
async function testAsync2() {
await f();
console.log("aaaaa");
}
testAsync2();
2、async函数中的return关键词
//错误处理
//方法一:
async function f() {
let a=await Promise.resolve("成功执行");
console.log(a);
//当try块中出现错误或异常时,如果采用了catch块捕获,则只会影响try块内部的代码,不会影响其外部的代码
try {
let b=await Promise.reject("我是失败");
console.log(b);
}catch {
//console.log(e);
}finally {
console.log("我是永久执行块")
}
let c=await Promise.resolve("我是成功二");
console.log(c);
return "我是返回值";
}
f().then((data)=>{
console.log(data);
});
//方法二:
//除了采用try...catch进行捕获外,还可以采用Promise对象本身的catch方法,进行捕获。
async function f() {
let a=await Promise.resolve("成功执行");
console.log(a);
let b=await Promise.reject("我是失败").catch((err)=>{
console.log(err);
});
// console.log(b);
let c=await Promise.resolve("我是成功二");
console.log(c);
return "我是返回值";
}
f().then((data)=>{
console.log(data);
});
//方法三:
//优雅处理async。。。await的异常
function f(msg) {
return new Promise((resolve,reject)=>{
//resolve("sssss");
reject(`我是第${msg}次失败`);
})
}
function to(p) {
return p.then((data)=>{return [data,null]}).catch((err)=>{return [null,err]});
}
async function f1() {
//let [data,err]=await f(1)
let [data,err]=await to(f(1));
console.log(data);
console.log(err);
let [data1,err1]=await to(f(2))
console.log(data1);
console.log(err1);
}
f1();
十三、面向对象
1、面向对象编程
本质是以建立模型体现出来的抽象思维过程和面向对象的一些方法。模型是用来反映现实世界中事物理特征。方法是模型所需要的行为动作。
2、面向对象特点:
封装、继承、多态
十四、Class类
1、定义类
关键词class
class 类名 {}
2、类中的元素
1)类的构造方法
关键词:constructor
constructor()方法是类的默认方法,通过new生成对象实例时会自动调用该方法。
作用:1.给变量赋值;2.声明变量
2)成员函数/方法
在成员方法中声明的变量是不能在外面调用的(undefined)
3)成员变量(在类中定义成员变量,变量名直接赋值)
在类中声明成员变量有两种方法:
- 变量名=值
- this.变量名=值
注:
- 如果是同一变量名,this可以执行赋值功能
- 在类的作用域声明的变量,它绑定到类;在构造方法中声明的变量,它也是绑定到类;
- 如果在方法中使用this绑定到类上的变量,需要调用方法后才能使用,否则不会绑定到类上
- 如果在类的一个成员方法中使用另一个成员方法中的变量,一点要先调用声明的成员方法才能使用
- 类中的一个成员方法需要调用另一个成员方法,采用关键词this.成员方法名
class Person {
name = "cn";//类的成员变量
// constructor() {//类的构造方法(是给变量赋值的,声明变量)
// this.name = "cn1";//this关键字代表实例的对象
// }
// 其他语言可以有多个构造方法,但ES6只能有一个构造方法
constructor(name) {
this.name = name;
}
addSmoking(){//类的成员方法
//在成员方法中声明的变量是不能在外面调用的(undefined)
let name1 = "aaa"
this.name2="bbb";
// 类中成员变量的使用需要使用关键词this,如this.name
console.log("我是"+this.name);
}
addSpeaking(){
// 在一个成员方法中调用另一个成员方法,采用关键词this.成员方法名
this.addSmoking();
console.log(this.name2);
}
}
// 类在使用的时候需要实例化
// 注:在给类实例化的时候,会默认调用构造方法,如果构造方法需要参数,需要在实例化的时候传递实参
// 如果没给变量赋值,默认就是undefined
let p = new Person("cn2");
p.addSmoking();
类中两种变量:成员变量、静态变量
三种方法:成员方法、静态方法、构造方法
3、static
调用静态变量:类名.变量名
调用静态方法:类名.方法名
构造方法中不能声明静态变量;
成员方法中,可以使用静态变量和静态方法,必须使用类名调用;
静态方法中,不能使用成员变量和成员方法,但可以使用静态变量和静态方法,调用方式可以是类名也可以是this
class Person {
static age=20;
name="cn";
constructor(){//构造方法
this.age="女";
}
addSmoking(){//成员方法
Person.addListen();
console.log(this.name,this.age);//this.age是undefined,必须要用类名来调用
}
ststic addListen(){//声明静态的方法
console.log("我是静态方法"+this.age);
}
}
let p=new Person();
p.addSmoking();
Person.addListen();//调用静态的方法
Person.age=12;//静态变量的赋值和调用
4、继承
ES6中的继承是完全继承
关键词:extends
存储机制:
内存块中存的是静态方法和静态属性(预加载时存储);成员方法和成员属性在运行时存储
1.子类中可以重新定义父类中的方法和属性,这种形式称之为多态
2.子类中如果需要使用父类的方法,可以采用super关键词调用对应的方法3.子类不能在成员方法中使用super调用父类的静态方法,会产生运行时错误,可以使用类名里调用父类的静态方法;
4.子类中如果需要使用父类的静态属性,可以使用this
5.子类的构造方法中必须要调用父类的构造方法,语法:super()
6.类中的super关键词指向父类,类的this关键词指向当前类
class Father {
firstName="r";
static sex="男";
constructor() {
this.secondName="p";
}
addSmoking(){
console.log("我是父类中的s");
}
static addDrinking(){
console.log("我是父类中的d");
}
}
class Child extends Father{
firstName="y";
constructor() {
super();//调用父类的构造方法
}
addSmoking() {
//console.log(this.firstName)
//super.addSmoking();
//super.addDrinking();//不能再成员方法中使用super调用父类的静态方法,会产生运行时错误。但是可以使用类名来调用静态的方法
//console.log(this.firstName)
console.log(Father.sex)//可以使用类名来获取静态属性。
Father.addDrinking();
console.log("我是儿子的ns");
}
static addDrinking(){
console.log(this.sex)
super.addDrinking()
console.log("我是儿子的nd");
}
}
const c=new Child();
//c.addSmoking();
// // console.log(c.firstName)
Child.addDrinking();
// console.log(Child.sex)在这里插入代码片
5、属性的修饰符
class A {
username="cn";
//uname是属性名
set uname(value){//set修饰的属性名方法,当给属性名赋值的时候被调用
console.log("我是set修饰的方法")
this.username=++value;
}
get uname(){//get修饰的属性名方法,当输出属性的时候被调用
console.log("我是get修饰的方法")
return this.username;
}
}
// 类必须使用new调用,否则会报错。
const a=new A();
a.uname=123;//调用set修饰的属性名方法
console.log(a.uname);//调用get修饰的属性名方法
十五、数组的扩展
1、静态方法
(1)Array.from()
将对象转化为数组
注:
- 只能将key为下标的对象转为数组(支持隐式转换);
- 且对象中必须要有length属性,因为新生成的数组需要根据length值来生成元素的个数,
- 如果对应下标没有值,则会使用undefined填充;
- 如果出现重复下标则会覆盖值;
let obj={1:"aaa",2:"bbb",3:"ccc",length:7,3:"ss",5:"eee"};
console.log(Array.from(obj));
2)Array.of()
将值转化为数组
console.log(Array.of(1,2,3,4,5,"ssss"));
2、成员方法
1)引用.entries()
将数组以[index,value]新数组的形式返回
2)引用.keys()
3)引用.values()
4)引用.includes(值,searchIndex)
查询数组中是否含有参数一的值,返回值是布尔类型;
参数二是开始查找的下标(包含起始下标),负值:从最大长度开始往左数参数个
includes()方法可以实现模糊搜索,但是区分大小写
5)find()
也是查找,查找数组中满足回调函数中return条件的第一个元素
6)some()
搜索当前数组中是否含有满足回调函数返回值的值,如果有返回true,没有返回false
7)every()
搜索当前数组中的值必须全部都满足回调函数的返回值,满足返回true,否则返回false
一、ES6简介
1、ECMAScript与JavaScript的关系
ECMAScript是JavaScript的规则,JavaScript是ECMAScript的一种实现。
2、ES6好处以及优势
- let、const变量的声明(默认参数)
- 变量的解构赋值
- 字符串模板(多行字符串)
- 箭头函数
- Promise对象
- Class类的概念
- Module模块化
3、ES6与ES5的关系
ES6是ES5的语法糖
4、 ES6与ES7的关系
与ES6相比,ES7增加了关键词async的功能,并且可以使用await轻松直接调用函数来实现异步调用同步化。
二、ES5回顾
1、 严格模式
1)严格模式的原因
- 消除JavaScript语法上的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全处、保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为新版本JavaScript做好铺垫;
2)关键词:‘use strict’
3)严格模式的特例
- 变量使用前必须要声明
var age=12;
console.log(age);
- 不能直接使用this指向
function f(name,age) {
this.name=name;
this.age=age;
return {a:this.name};
}
console.log(f("cn",20));
- eval函数存在作用域
var a="cn";
eval('var a="cn";console.log(a)');//cn1
console.log(a);//cn
2、JSON
1)JSON.parse()方法:将类似数组或对象格式的字符串转化为JSON格式的对象
var a="[1,2,3,4,5,6,7]";
console.log(typeof a);
console.log(typeof JSON.parse(a));
2)JSON.stringify()方法:将对象或数组转化为字符串
var b=[1,2,3,4,5];
console.log(typeof JSON.stringify(b));
3)实现数组或对象的深拷贝:JSON.parse(JSON.stringify(obj))
3、Object扩展
1)Object.create(原对象,[属性])
创建一个新的对象,原对象不会改变
var obj1={name:"cn",age:20};
var obj2=Object.create(obj1,{
sex:{
value:"女",//设置新增属性的值
enumerable:true,//设置新增属性是否可以枚举显示,默认值是false(不会在输出对象引用中显示)
writable:true,//设置新增属性是否可以修改,默认值是false
configurable:true//设置新增属性是否可以删除,默认值是false
},
sex2:{
value:"男",
enumerable:true,
}
})
console.log(obj1);//{name:"cn",age:20}
obj2.sex = "女孩";
delete obj2.sex;//删除属性
console.log(obj2);
2)Object.defineProperties(原对象,扩展属性)
为指定对象定义扩展多个属性,会改变原对象的值
var obj1={name:"cn",age:20};
var obj2=Object.defineProperties(obj1,{
sex:{
get() {//获取该属性值的时候被调用
console.log("我是get方法");
return "女";
},
set(v) {//设置该属性值的时候被调用
console.log("我是set方法"+v);
}
}
});
obj2.name="cn1";
obj2.sex="男";
console.log(obj1);
console.log(obj2.sex);
4、Array扩展
1)引用名.forEach()
没有生成值或返回值,只可以循环遍历数组。
let arr=[1,2,3,4,5];
var arr1=arr.forEach(function (item ,index) {
return index;
});
console.log(arr1);//undefined
2)引用名.map()
可以根据返回值进行生成新的数组(即返回值组成的数组),也可以循环遍历数组
var arr2=arr.map(function (item,index) {
return index>3;
})
console.log(arr2);//数组
3)引用名.filter()
可根据返回值判断:返回值为true,则会将对应的数组的值返回并生成新的数组。
功能;过滤数组。
var arr3=arr.filter(function (item ,index) {
//return index>2;
return true;//只是用来判断当前值,是否添加到新的数组中。
});
console.log(arr3);
5、函数扩展
1)函数名.bind(obj)
将函数内部的this绑定为obj,并将函数返回
function f(name,age) {
this.name=name;//cn
this.age=age;//20
console.log(this.name);
return {name:this.name,age:this.age};
}
var obj={};
//bind方法将自定义对象和this进行绑定
f.bind(obj)("cn",20);
console.log(f.bind(obj));
6、let和const
1) 语句块
{语句块}
for(){语句块}
if(){语句块}
function a(){语句块}
2)顶层对象
在浏览器环境下,顶层对象是window和_self;在Node中,顶层对象是global。ES2020在标准语言的层面,引入globalThis作为顶层对象,在任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指全局下的this。
3) let
定义变量
4) const
定义常量,声明的同时需要初始化。当数据类型为Number、Boolean、String时,值不可改变;但是对对象或数组时,值可以改变,因为声明的变量相当于指向内存的地址。
注:将对象冻结:Object.freeze()
5) let和const特性
- 块级作用域
- 不存在变量提升,暂时性死区(TZD)
- 同一作用域,不能重复声明变量
6)let和var的区别
- 作用域不同,let是块作用域,var是函数作用域;
- let在同一作用域不能重复声明,var可以覆盖同名变量;属于TDZ问题
- let不存在变量声明提升,var存在;要遵守先声明后使用的原则
7、变量的解构赋值和默认值
1)解构
概念:ES6允许按照一定的模式(即规则),从数组和对象中提取,对变量进行赋值。
解构赋值肯定有赋值运算符,赋值运算符左边的 {} 或 []是模式,右边的是对象或数组。
对象的大括号不是作用域
2)数组的解构赋值
let [foo,[[bar],c]] = [1,[[2],3]];//1 2 3
let [,,third]=["foo","bar","baz"];//baz
let [x,,y]=[1,2,3];//1 3
let [head,...tail]=[1,2,3,4];//1 [2,3,4]
let [x,y,...z]=["a"];//a undefined []
let [bar,foo]=[1];//1 undefined
let [x,y]=[1,2,3];//1,2
let [a,[b],d]=[1,[2,3],4];//1 2 4
let [x,y,z]=new Set(['a','b','c']);//a b c
let [foo=true]=[];//true
let [x,y='b']=['a'];//a b
let [x,y='b']=['a',undefined];//a b
let [x=1]=[null];//null
let [x=1,y=x]=[];//1 1
let [x=1,y=x]=[2];//2 2
let [x=1,y=x]=[1,2];//1 2
let [x=y,y=1]=[];//报错
function f() {
console.log("aaaa");
return "bbb";
}
let [x=f()]=["sdfsdfsdf"];//惰性解构赋值
console.log(x);//sdfsdfsdf
3)对象的解构赋值
对象的属性没有次序,变量必须与属性同名才能取到正确的值。
let {log,sin,cos}=Math;//[Function: log] [Function: sin] [Function: cos]
let {foo:a,foo1:b}={foo:"aaa",foo1:"bbb"};
console.log(a,b);//aaa bbb
let obj={};
let arr=[];
({a:obj.prop,b:arr[0] }={a:"asdasdasd",b:true })//将解构赋值的对象放到()中,可以抵消{}的代码块作用
console.log(obj);//{ prop: 'asdasdasd' }
console.log(arr);//[ true ]
let {log}=console;
log("aaaaaaa");//这两行代码相当于console.log();
let {x = 3} = {};//3
let {x, y = 5} = {x: 1};//1 5
let {x: y = 3} = {};//报错x is not defined 3
let {x: y = 3} = {x: 5};//报错 5
let {x = 3} = {x: undefined}; //3
let {x = 3} = {x: null};//null
({} = [true, false]);
({} = 'abc');
({} = []);
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;//1 3
let x;
//{x} = {x: 1};
({x} = {x: 1});//1
4)解构赋值的作用
- 交换值
let a = 1;
let b = 2;
let c = 3;
[a,b,c] = [b,c,a];
console.log(a,b,c);//2 3 1
- 从对象或数组中解构所需要的值
let obj = {
a:{
b:"bbb",
c:"ccc",
d:{
e:"eee"
}
}
};
let {a:{d:{e}},a:{d}}=obj;
console.log(e);//eee
console.log(d);//{ e: 'eee' }
//如果要解构最深层,它的上一级一定要有
console.log(c);//报错,未解构的变量是无法打印的
//解构的时候是一一对应的
- 从函数的返回值中解构所需要的值
function f(){
return [1,2,3,4];
}
let [,a,,,b]=f();
console.log(a,b);//2 undefined
- 函数参数的解构(支持不完全解构)
function f([a,b,c,d]){
return a+c;
}
console.log(f([1,,7,]));//8
- 可以解构map数据结构类型的key-value
let map = new Map();
map.set("a","aaa");
map.set("b","bbb");
// console.log(map);
for(let [index,value] of map){
// console.log(value);
console.log(index)
}
- 从指定的模块中解构对应的方法
const {readFile}=require("fs");
三、模板字符串
`字符内容${变量输出}字符内容`
注:${ }中的值:
- 变量
- 任意javascript表达式
- 获取对象的属性
- 调用函数
四、对象的扩展
1、对象的简写
1)对象属性名的简写
let a="aaa";
let b={a};
console.log(b);//{ a: 'aaa' }、
function f() {
let name="cn";
let age=20;
let sex="女";
return {name,age,sex};//相当于{name:name,age:age,sex:sex}
}
console.log(f());//{ name: 'cn', age: 20, sex: '女' }
2)对象方法名的简写
let a={
f(){
console.log("aaa");
},
f1(){
console.log("aaaaa2");
}
}
//调用
a.f1();//aaaaa2
let aa="haha";
let obj={
a:"saddfsa"
};
let obj2={
[aa]:"sadsfd"
}
console.log(obj2);//{ haha: 'sadsfd' }
console.log(obj2[aa]);//sadsfd
console.log(obj2.haha);//sadsfd
function f(aname) {
return{
[aname]:"cn"
}
}
console.log(f("a").a)//cn
function f(fnname) {
return{
[fnname](){
console.log("我是函数,缺省名字的函数")
}
}
}
console.log(f("aa"));//{ aa: [Function: aa] }
console.log(f("aa").aa);//[Function: aa]
f("aa").aa();//我是函数,缺省名字的函数
2、对象中变量
1)变量做属性名
let name = 'cn';
const a = {
'age':20,
[name]:'cc'//name是一个变量
};
console.log(a['age']);//20
console.log(a[name]);//cc
console.log(a['cn']);//cc
2)变量做方法名
let obj={
['na'+'me'](){
return 'cn';
}
};
obj.name();
五、箭头函数
1、语法
()=>{}
2、参数
1)无参数
let f=()=>{
cnsole.log('a');
}
1)一个参数
可将()省略
let f=n=>{
consle.log('a');
}
1)两个及以上参数
var fu = (n,m=10)=>{
return n*m;
}
3、返回值
1)函数体内是一条语句
{}可省略
let f=n=>console.log(n);
2)函数体内是一条语句,并且是return关键词
省略{}和return
let f=(n,m)=>n*m;
4、使用场景
箭头函数的两个不适用场景:
- 对象里面
- 事件的回调函数
button.on('click',function(e){
console.log(this)
})
1)回调函数中的箭头函数
let timer=setTimeout(()=>{
console.log(1);
},1000);
2)参数中的箭头函数
function fn(f,a){
console.log(a);
}
fn(()=>{
console.log('我是参数箭头函数');
},10);
5、箭头函数中this的使用规则
箭头函数的this不绑定当前调用者,只与箭头函数定义的上下文环境有关。
1)全局函数中的this
function fun(){
console.log(this);//window
}
let fun1 = n =>{
console.log(this); //window
}
2)事件处理函数中的this
let oDiv = document.getElementById("box");
oDiv.onclick = function () {
console.log(this);//div
}
oDiv.onclick = ()=>{
console.log(this); //window
}
3)对象方法中的this
function Person() {
this.eat = function () {
return function () {
console.log(this); //global
}
}
}
let p = new Person();
p.eat()();
function Dog() {
this.eat = function () {
return ()=>{
console.log(this); //Dog
}
}
}
let d = new Dog(); d.eat()();
6、箭头函数的特性
- 箭头函数是匿名函数,不绑定自己的this,arguments,super,new.target
- 箭头函数会捕获其所在上下文的this值,作为自己的this值,在使用call/apply绑定时,会改变this指向。
- 箭头函数不绑定arguments,取而代之用rest参数运算符解决
- 箭头函数不能作为构造函数,和 new 一起用就会抛出错误
六、ES6中的运算符
1、rest剩余参数运算符
将以“,”隔开的参数转换为数组
注:剩余参数运算符一定要在形参的最后
function f(b,c,...a) {
console.log(a,b,c);//[3, 4, 5, 6, 7, 8, 9, 10, 11] 1 2
}
f(1,2,3,4,5,6,7,8,9,10,11);
2、spread扩展运算符
将一个数组转为用逗号隔开的参数,通常使用在实参的传递中
用于:给函数传参的时候,不确定传参的个数,并且还要调用的时候
function f(a,b,c,d,e) {
console.log(a,b,c,d,e);// 1 2 3 undefined undefined
}
let arr=[1,2,3];
f(...arr);
1)spread 扩展运算符的应用场景:
- 复制、合并数组或对象
(一维数组:深拷贝;多维数组:浅拷贝)
//复制数组
let arr=[1,2,3];
let arr2=[...arr];//深拷贝(值)
console.log(arr2);//[ 1, 2, 3]
//合并数组
let arr=[1,2,3];
let arr2=[4,5,6];
let newArr=[...arr,...arr2];//合并拷贝,深拷贝(值)
console.log(newArr);//[ 1, 2, 3, 4, 5, 6 ]
- 将类似数组或对象转为真正的数组。
let set=new Set();
set.add("aaaa");
set.add("bbbb");
console.log([...set]);//[ 1, 2, 3, 4, 5, 6 ]
七、Symbol
ES第7种数据类型(基本数据类型)
1、定义Symbol类型变量,无参形式
即使使用了参数,参数相当于描述
let a=Symbol();
let b=Symbol();
console.log(a===b);//false
2、Symbol的使用
let a=Symbol();
let obj={
//变量名做属性名
[a]:"hahaha"
}
obj[a]="aaaaaaa";//修改
console.log(obj[a]);//aaaaaaa
let a=Symbol();//生成唯一的哈希值
let b=Symbol();//生成唯一的哈希值
let obj={
[a]:"hahaha"
}
obj[b]="aaaaaaa";
console.log(obj);//两个 { [Symbol()]: 'hahaha', [Symbol()]: 'aaaaaaa' }
3、模拟实现私有属性
function Person() {
let a=Symbol();
let b="bl";
this[a]=()=>{
console.log("我是私有属性");
}
this[b]=()=>{
// this[a]();
console.log("我是单独的方法");
return a;
}
}
const p=new Person();
// console.log(p);//Person { bl: [Function], [Symbol()]: [Function] }
p[p.bl()]();
p.bl();
4、Symbol的for方法可以将两个Symbol定义成同一个Hash
let a=Symbol.for("aaa");
let b=Symbol.for("aaa");
console.log(a===b);//true
console.log(typeof a);//symbol
3、ES6中的Symbol类型有什么作用?
ES6新增了Symbol数据类型,它用来生成一个独一无二的值,Symbol数据常用来给对象属性赋值,让对象属性具备唯一性,不容易被覆盖。
八、Set和Map数据结构
1、Set数据结构
类似数组,与数组的区别在于其内部成员是唯一的(即没有重复元素)。
Set数据结构本身可以去重(数字类型,布尔类型,字符类型)
注:同一变量名声明的数组可能去重,在未重新赋值的情况下可以去重,只要重新赋值了即使与原来的值相同也不能去重;不同变量存储的数组不会去重(因为存的是地址)
1)语法
let set = new Set(数组);//注:参数可以省略
2)常用属性
- size:获取set结构内元素的数量。
3)常用方法
- add(value):添加某个值,返回 Set 结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功,如果元素不存在代码不会报错可以正常执行
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
- forEach:遍历Set结构内的元素。
4)Set用来过滤数组重复数据:let arr = […new Set(arr)];
2、Map数据结构
类似对象,区别在于对象只接受字符串作为键名,而
Map的键名可以是任意类型。
1)语法
let set = new Map(初始化的值);//注:参数可以省略
2)常用属性
- size:获取Map结构内元素的数量。
3)常用方法
- set(key,value):添加一个键值数据。
- get(key):根据key获取value。
- has(key):返回一个布尔值,表示map集合是否包含当前key的成员。
- delete(key):根据指定的key删除数据。
- clear():清除所有成员,没有返回值。
- forEach:遍历Map集合使用forEach。
九、Iterator遍历器
1、ES6中的四种数据结构:
数组(Array)、对象(Object)、Map、Set
2、概念
Iterator是一种接口,所以的数据结构只要部署了接口,都可以进行遍历。
作用:循环遍历输出
Symbol.iterator是属性,本身也是封装好的函数,让定义好的数据结构可以遍历
3、ES6中天生可以遍历的:
Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象
4、遍历
let arr=["a","b","c","d","e"];
let it=arr[Symbol.iterator]();//将遍历器属性绑定到自定义的数据结构中,这里定义的变量it相当于一个指针
it.next();//{value:"a",done:false}
it.next();//{value:"a",done:false}
console.log(it.next());//{value:"a",done:false}
//第六次调用it.next()输出 {value:undefined,done:true}
for(let item of it){
console.log(item);//d e
// console.log(item.next());//报错 如果使用for...of遍历遍历器指针,则不能再使用next()方法
}
十、Generator函数
是ES6提供的一种异步编程解决方案,封装了多个内部的状态;
1、Generator函数的定义
定义的关键词:*(用来修饰函数名) 、yield(用来定义状态)
function *f() {
yield "我是状态一";
yield "我是状态二";
yield "我是状态三";
return "我是G函数返回值";
}
2、Generator函数的调用
1)无参
let git=f();
//获取Genertor函数中的状态
//console.log(git.next());//{ value: '我是状态一', done: false }
//console.log(git.next());//{ value: '我是状态二', done: false }
//注:采用for...of循环只能输出generator函数的状态,无法拿到return的返回值
for (let item of git){//Generator函数默认实现了遍历器接口Symbol.iterator
console.log(item);//我是状态一 我是状态二 我是状态三
}
git.next();
git.next();
console.log(git.next());
console.log(git.next());//{ value: '我是G函数返回值', done: true } 拿到return的返回值
console.log(git.next());//此时{value:undefined,done:true} 再继续git.next()都是这个值
2)可以接受参数的next()方法
function * f1() {
let a=yield "我是状态一";
console.log("我是yield一的输出"+a);
let b=yield "我是状态二";//yield "我是状态二";let a="我是next传参二";
console.log("我是yield二的输出"+b);
yield "我是状态三";
return "我是G函数返回值"
}
let gitf1=f1();
//yield关键词本身具备懒惰原理,
//next参数会赋值给上一个状态,使用next()方法传参,yield的懒惰性,会将参数赋值给上一个状态,即是上一个状态的值
console.log(gitf1.next("我是next传参一"));
console.log(gitf1.next("我是next传参二"));
console.log(gitf1.next("我是next传参三"));
3、Generator函数用同步思想解决异步
function * f() {
let a=yield getData();
console.log(a);
}
let fnn=f();
function getData() {
$.get("./user.json").then((data)=>{
//console.log(data);
//f().next(data);//这样写默认看成了f()这个方法的调用
fnn.next(data);
})
}
fnn.next();
十一、Promise对象
Promise和callback一样,目的都是为了异步数据传递,比如ajax请求数据的传递
1、概念
异步编程的一种解决方案,也称之为一个容器,黑箱操作;
2、特点:
-
对象的状态不受外界影响;
-
一旦状态改变,就不会再变; 状态不可逆 不能互相转换
3、状态:
pending(进行中)、fulfilled(成功)对应的方法resolve()、rejected(失败)对应的方法reject()
4、缺点:
-
无法取消Promise;
-
不设置回调函数,内部抛出的错误不会反应到外部
-
pending状态,无法确定进度;
5、对象的实例方法
Promise对象的结果有两个方法:resolve()–已成功(fulfilled) reject()–已失败(rejected)
//1、resolve()
//2、reject()
//例一
function f(){
return new Promise((resolve,reject)=>{
setTimeout(resolve,3000,"我是字符串");//setTimeout的第三个参数是用来给第一个参数赋值的
})
}
//3、then()获取成功状态的值
f().then((data)=>{
console.log(data);//3s后 输出 我是字符串
})
//console.log(f());//Promise { <pending> }
//例二:用伪代码来表示Promise对象的一个状态传值(实例)
function f() {
return new Promise((resolve,reject)=>{
if(1)
resolve("代码执行成功")
else
reject("代码执行失败")
})
}
//例三:
function f() {
return new Promise((resolve, reject) => {
reject("想用失败传值");
})
}
// Promise对象的then方法,参数一是成功的回调函数,参数二是失败的回调函数(通常不建议使用)
f().then((data)=>{
console.log(data);
},(error)=>{
console.log(error)
})
//例四
function f() {
return new Promise((resolve, reject) => {
resolve("想用成功传值");
reject("想用失败传值");
// console.log(a);
// let a = 2;
// throw关键词 抛出关键词 可以抛出自定义错误
// throw new Error("我是自定义的错误!")
})
}
f().then((data)=>{
console.log(data);
}).catch((err)=>{//4、catch()方法可以捕获错误、异常、失败的传值
console.log(err.message);
}).finally(()=>{//5、finally()方法,最终方法,不管Promise对象是成功状态,还是失败状态,还是出现错误,finally方法都会被执行
console.log("我是finally");
})
//6、all()方法
// 当all方法中全部都是成功状态的时候,会以数组的形式输出全部成功的结果;
// 当all方法中存在失败状态的时候,那么它会返回第一个失败的结果;
//7、race()方法:只会返回第一个Promise的状态,不论成功还是失败
十二、async函数
1、简介
async函数,本质就是Generator函数的语法糖;
语法:将Generator函数的*换成async(在function前),将yield换成await;
返回一个Promise对象,可以添加then()方法添加回调函数;
function f() {
return new Promise((resolve,reject)=>{
setTimeout(resolve,3000,"我我");
})
}
async function testAsync() {
let a=await f();//await可以将异步操作同步化。
console.log(a);
}
testAsync()
//async关键词可以独立出现,但是await关键词不能独立出现,如果需要使用await必须用async来修饰函数
async function testAsync2() {
await f();
console.log("aaaaa");
}
testAsync2();
2、async函数中的return关键词
//错误处理
//方法一:
async function f() {
let a=await Promise.resolve("成功执行");
console.log(a);
//当try块中出现错误或异常时,如果采用了catch块捕获,则只会影响try块内部的代码,不会影响其外部的代码
try {
let b=await Promise.reject("我是失败");
console.log(b);
}catch {
//console.log(e);
}finally {
console.log("我是永久执行块")
}
let c=await Promise.resolve("我是成功二");
console.log(c);
return "我是返回值";
}
f().then((data)=>{
console.log(data);
});
//方法二:
//除了采用try...catch进行捕获外,还可以采用Promise对象本身的catch方法,进行捕获。
async function f() {
let a=await Promise.resolve("成功执行");
console.log(a);
let b=await Promise.reject("我是失败").catch((err)=>{
console.log(err);
});
// console.log(b);
let c=await Promise.resolve("我是成功二");
console.log(c);
return "我是返回值";
}
f().then((data)=>{
console.log(data);
});
//方法三:
//优雅处理async。。。await的异常
function f(msg) {
return new Promise((resolve,reject)=>{
//resolve("sssss");
reject(`我是第${msg}次失败`);
})
}
function to(p) {
return p.then((data)=>{return [data,null]}).catch((err)=>{return [null,err]});
}
async function f1() {
//let [data,err]=await f(1)
let [data,err]=await to(f(1));
console.log(data);
console.log(err);
let [data1,err1]=await to(f(2))
console.log(data1);
console.log(err1);
}
f1();
十三、面向对象
1、面向对象编程
本质是以建立模型体现出来的抽象思维过程和面向对象的一些方法。模型是用来反映现实世界中事物理特征。方法是模型所需要的行为动作。
2、面向对象特点:
封装、继承、多态
十四、Class类
1、定义类
关键词class
class 类名 {}
2、类中的元素
1)类的构造方法
关键词:constructor
constructor()方法是类的默认方法,通过new生成对象实例时会自动调用该方法。
作用:1.给变量赋值;2.声明变量
2)成员函数/方法
在成员方法中声明的变量是不能在外面调用的(undefined)
3)成员变量(在类中定义成员变量,变量名直接赋值)
在类中声明成员变量有两种方法:
- 变量名=值
- this.变量名=值
注:
- 如果是同一变量名,this可以执行赋值功能
- 在类的作用域声明的变量,它绑定到类;在构造方法中声明的变量,它也是绑定到类;
- 如果在方法中使用this绑定到类上的变量,需要调用方法后才能使用,否则不会绑定到类上
- 如果在类的一个成员方法中使用另一个成员方法中的变量,一点要先调用声明的成员方法才能使用
- 类中的一个成员方法需要调用另一个成员方法,采用关键词this.成员方法名
class Person {
name = "cn";//类的成员变量
// constructor() {//类的构造方法(是给变量赋值的,声明变量)
// this.name = "cn1";//this关键字代表实例的对象
// }
// 其他语言可以有多个构造方法,但ES6只能有一个构造方法
constructor(name) {
this.name = name;
}
addSmoking(){//类的成员方法
//在成员方法中声明的变量是不能在外面调用的(undefined)
let name1 = "aaa"
this.name2="bbb";
// 类中成员变量的使用需要使用关键词this,如this.name
console.log("我是"+this.name);
}
addSpeaking(){
// 在一个成员方法中调用另一个成员方法,采用关键词this.成员方法名
this.addSmoking();
console.log(this.name2);
}
}
// 类在使用的时候需要实例化
// 注:在给类实例化的时候,会默认调用构造方法,如果构造方法需要参数,需要在实例化的时候传递实参
// 如果没给变量赋值,默认就是undefined
let p = new Person("cn2");
p.addSmoking();
类中两种变量:成员变量、静态变量
三种方法:成员方法、静态方法、构造方法
3、static
调用静态变量:类名.变量名
调用静态方法:类名.方法名
构造方法中不能声明静态变量;
成员方法中,可以使用静态变量和静态方法,必须使用类名调用;
静态方法中,不能使用成员变量和成员方法,但可以使用静态变量和静态方法,调用方式可以是类名也可以是this
class Person {
static age=20;
name="cn";
constructor(){//构造方法
this.age="女";
}
addSmoking(){//成员方法
Person.addListen();
console.log(this.name,this.age);//this.age是undefined,必须要用类名来调用
}
ststic addListen(){//声明静态的方法
console.log("我是静态方法"+this.age);
}
}
let p=new Person();
p.addSmoking();
Person.addListen();//调用静态的方法
Person.age=12;//静态变量的赋值和调用
4、继承
ES6中的继承是完全继承
关键词:extends
存储机制:
内存块中存的是静态方法和静态属性(预加载时存储);成员方法和成员属性在运行时存储
1.子类中可以重新定义父类中的方法和属性,这种形式称之为多态
2.子类中如果需要使用父类的方法,可以采用super关键词调用对应的方法3.子类不能在成员方法中使用super调用父类的静态方法,会产生运行时错误,可以使用类名里调用父类的静态方法;
4.子类中如果需要使用父类的静态属性,可以使用this
5.子类的构造方法中必须要调用父类的构造方法,语法:super()
6.类中的super关键词指向父类,类的this关键词指向当前类
class Father {
firstName="r";
static sex="男";
constructor() {
this.secondName="p";
}
addSmoking(){
console.log("我是父类中的s");
}
static addDrinking(){
console.log("我是父类中的d");
}
}
class Child extends Father{
firstName="y";
constructor() {
super();//调用父类的构造方法
}
addSmoking() {
//console.log(this.firstName)
//super.addSmoking();
//super.addDrinking();//不能再成员方法中使用super调用父类的静态方法,会产生运行时错误。但是可以使用类名来调用静态的方法
//console.log(this.firstName)
console.log(Father.sex)//可以使用类名来获取静态属性。
Father.addDrinking();
console.log("我是儿子的ns");
}
static addDrinking(){
console.log(this.sex)
super.addDrinking()
console.log("我是儿子的nd");
}
}
const c=new Child();
//c.addSmoking();
// // console.log(c.firstName)
Child.addDrinking();
// console.log(Child.sex)在这里插入代码片
5、属性的修饰符
class A {
username="cn";
//uname是属性名
set uname(value){//set修饰的属性名方法,当给属性名赋值的时候被调用
console.log("我是set修饰的方法")
this.username=++value;
}
get uname(){//get修饰的属性名方法,当输出属性的时候被调用
console.log("我是get修饰的方法")
return this.username;
}
}
// 类必须使用new调用,否则会报错。
const a=new A();
a.uname=123;//调用set修饰的属性名方法
console.log(a.uname);//调用get修饰的属性名方法
十五、数组的扩展
1、静态方法
(1)Array.from()
将对象转化为数组
注:
- 只能将key为下标的对象转为数组(支持隐式转换);
- 且对象中必须要有length属性,因为新生成的数组需要根据length值来生成元素的个数,
- 如果对应下标没有值,则会使用undefined填充;
- 如果出现重复下标则会覆盖值;
let obj={1:"aaa",2:"bbb",3:"ccc",length:7,3:"ss",5:"eee"};
console.log(Array.from(obj));
2)Array.of()
将值转化为数组
console.log(Array.of(1,2,3,4,5,"ssss"));
2、成员方法
1)引用.entries()
将数组以[index,value]新数组的形式返回
2)引用.keys()
3)引用.values()
4)引用.includes(值,searchIndex)
查询数组中是否含有参数一的值,返回值是布尔类型;
参数二是开始查找的下标(包含起始下标),负值:从最大长度开始往左数参数个
includes()方法可以实现模糊搜索,但是区分大小写
5)find()
也是查找,查找数组中满足回调函数中return条件的第一个元素
6)some()
搜索当前数组中是否含有满足回调函数返回值的值,如果有返回true,没有返回false
7)every()
搜索当前数组中的值必须全部都满足回调函数的返回值,满足返回true,否则返回false在这里插入代码片