ES6里面新增内容

ES6
新增了很多的语法规范,可以对写法和开发有很大的帮助
有很多新增的内容,以后慢慢的去适应es6的写法。
有很多小的点,经常出现在面试中,对比性的学习

ECMAScript 第六个版本

ECMAScript 和JavaScript 什么关系?
ECMAScript 是一个语言的标准 if switch var 可以在JavaScript
解析JavaScript是浏览器的内核做的事情5个内核

JavaScript ECMAscript + WEBapi(DOM、BOM) = JavaScript
ActionScript + WEBapi(DOM、BOM)= flash

ES是定义标准的,js是实现者
es的历史 现在用到的最多的版本是ES3.1

1996 ES1.0 Netscape公司叫js交个了ECMA的组织,es正式出现
1998 ES2.0
1999 ES3.0
2007 ES4.0 大的更新,大的改动。开发者完全的不认同。过于激进。被废除了
2008 ES3.1 严重缩水的4.0,名字Harmony ECMAHarmony
2009 ES5.0 正式发布,草案直接指向ES6.0
2013 ES6.0 草案指定完成
2013.12ES6.0草案发布
2015.06 ES6.0正式发布 ES2015
2016 ES就不在使用版本号了,而是使用年份的代号了 ES7
2017 ES8
2018 es9

ES6的前提要求:尽量的保证浏览器是最新的,如果实在有语法看不到效果的,再到编译器中看

node 全部都是ES6的语法

let声明变量

1.let声明的变量不会挂在window中,不会造成全局变量的污染
2.新增了一个块级作用域{},以前只有函数作用域,全局作用域
3.let是不允许重复声明
4.let不会有声明提前(只是人为看到的效果,实际上是有声明提前,提前临时性的死区中:Cannot access ‘num’ before initialization) 面试点

例子:

let a = 10;
 {
 	console.log(a);   
	let a = 20;   //a存到了临时性的死区中了
 }

作用域

有全局作用域和函数作用域,在你这里新增了一个作用域就是块级作用域,所有的代码放在{}中间

例子:
{
	let num = 100;
	console.log(num)
}

面试题:
如何点击每一个按钮获取到每一个按钮的对应的序列号

有两种方法
一种是用立即执行函数

例:
var arr = [];
for(var i = 0;i<10;i++){
	(function(i){
		arr[i] = function(){
			console.log(i);
		}
	})(i)
}

第二种就是用let来解决
例:

var arr = [];
for(let i = 0;i<10;i++){
	arr[i] = function(){
		console.log(i);
	}
}

const声明常量

1.跟let完全相同 增加几个点
5.不允许被修改(不允许改变内存空间的地址)
6.const声明和赋值必须一次性完成,并且后期不允许改变存储空间的地址

大型的公司,对项目进行整改
代码迁移从es5迁移到es6
能使用const就使用const,不能使用就用let。常量的效率比变量要高

字符串模板(``这个符号是esc键正下方的一个按钮的)
在以前的字符串之上增加了一些功能
1、字符串的换行,以前我们要达到字符串的换行就要用上join("\n")这个方法

例子:
let str = `今天天气
很好
sdkljf
sldkfj`

2、字符串的拼接,以前我们进行字符串的拼接是用+变量+这样进行拼接的

例子:
var day = "今天";
var str = "天气不错";
console.log(`${day}${str}可以出去玩`)

ES6中:
${表达式}字符串

可以添加串、可以使用转义字符、还可以嵌套

console.log(`${true?`今天`:`明天`}\n出去`)

解构

结构化赋值
可以简化书写的长度,提升效率

例:
let obj = {
name : "jack",
age : 18,
sex : "nan",
class : 10
}

1、可以这样:

let name,age;
({name,age} = obj);
console.log(name,age)

2、可以这样

let {name , age} = obj;
console.log(name,age);

3、还可以这样

let {name : oName,age : oAge, sex:oSex} = obj;
console.log(oName,oAge,oSex)

4、对数组也可以用

例:
let arr = [1,2,3,{name:'jack'}];
let [,,,{name : oName}] = arr;
console.log(oName)

…运算符 起到参数收集作用
1. 收集符只能出现一次
2. 一个函数,剩余参数收集只能在最后一个形参
运用在数组中,函数中 object是ES7新增的

例:
function computedScore(...arg){}
console.log(computedScore(97,99,93,92,90,81,88,70))

在ES6中基本表现是数组,而ES7中基本表现在对象
这也是ES6中数组的表现方式:

let arr = [1,2,3];
let arr2 = [4,5,6];
let newArr = [...arr,...arr2];
console.log(newArr)

在ES7中的运用是针对对象的运用:

let company = {
	name : "baidu",
	age : 15
};
let teachDepartment = {
	leader : {
		name : "peng",
		age : 18
	},
	personNum : 20
};
let obj = {
	...company,
	...teachDepartment
}
console.log(obj)
obj.leader.name = "yin";
console.log(obj);
console.log(teachDepartment)

函数

参数默认值 可以传递表达式,不能传递语句
arguments 严格模式中,arguments和函数的形参不存在关系,没有对应的映射关系
注意:只要给函数加上了参数默认值,该函数就自动变成严格模式
形参和let,const一样,有自己的作用域,根据声明的顺序,会产生临时性死区,null在数学中,默认的为0,所以不要传递null
例子:

function fun(a,b=10,c=20){
			return a+b+c;
		}
console.log( fun(undefined,undefined,30) );
//这里表示a得到的参数值为undefined,
b得的值是他传入的默认值,c则就是直接得到的是他传入的参数值
console.log( fun(1,2,3) )//这里都是获取的是三个参数的值


console.log( fun(30) )//这里a得到的值是30,其余的参数都是用的默认值
console.log( fun(10,undefined,30) )//这里的a的值为10,b为10,c为30
console.log( fun(10,null,30) )//这里a为10,b为0,c为30

这种情况就会出现这种错误(Cannot access ‘b’ before itialization)

function test(a=b,b){
	console.log(a,b)
}
test(undefined,2)
函数的真正用途
普通函数   纯小写
构造函数   大驼峰命名  首字母大写
新增 new.target   构造函数必须使用new来进行调用

注意:如果没有使用new 关键字调用函数,则返回undefined,如果使用了new调用,则返回的是函数的本身

例子:
function Person(firstName,lastName){
	if(new.target === undefined){
		throw new Error("该函数必须使用new调用")
	}
	this.firstName = firstName;
	this.lastName = lastName;
	this.fullName = `${firstName} ${lastName}`
}
const p1 = new Person("张","三");
console.log(p1);

箭头函数

语法:箭头函数是一个函数表达式,理论上,任何使用函数表达式的地方都可以改成箭头函数
例:
	(参数1,参数2...) => {
		函数体
	}
箭头函数的this指向问题
	1.对象调用函数,this指向对象
	2.直接调用函数,this指向window
	3.如果使用了new关键字,this指向新创建的对象
	4.如果使用apply,call,bind  this指向绑定的数据
	5.如果是DOM事件函数,this指向事件源

箭头函数的简写的方法:
1、如果参数只有一个,可以省略小括号
语法:参数 => {}

例:const print = num => {} 

2、如果箭头函数只有一条返回语句,可以省略{},同时也可以省略return
语法:参数 => 返回值

例:const isOdd = num => num % 2 !== 0;

2.1、如果返回值是一个对象的时候,就会认为成函数体,把返回值变成表达式的形式

例:const obj = (a,b) => ({a : a,b : b})
console.log( obj(1,2) )
注意:

1、箭头函数中没有this,argument,new.target,如果要强行使用,则指向函数外层对应的this,argument,new.target
2、箭头函数没有原型,所有说占用空间非常小,不能当成构造函数来使用

应用场景

1.临时使用的函数,并不会刻意的去调用
1.1.异步的处理函数
1.2.事件的处理
2.继续去沿用外层的this
3.对象的属性不要去用箭头函数,除非是特别的需求
4.数组方法的时候,保证代码的简洁

对象

ES6新增
1.属性简写
2.方法简写

例:
function createUser(loginId,loginPwd,nickName){
	const say = function(){
	console.log(loginId,loginPwd)
	}
	return{loginId,loginPwd,nickName,say,
		fun(){   //2方法简写,  不是箭头函数
			console.log(his.loginId,this.loginPwd)
		}
	}
}
const user = createUser("01","123","abc")
console.log(user)
user.say()

user.fun()

3.计算属性名

例:
const prop1 = "name";   //我们知道属性名是什么,由后台返回给你的
	const prop2 = "age";
	const prop3 = "say"
	const user = {
		[prop1] : "尹老师",
		[prop2] : 30,
		[prop3](){
		console.log(this[prop1],this[prop2])
		}
	}
	console.log(user[prop1])
	user[prop3]()
对象里面新增了API

1.is() 基本上和===一样,除了以下两种情况

console.log(NaN === NaN);   
console.log(+0 === -0)

2.assign() 用于混合对象,带浅克隆是ES7里面的

例子:
const obj1 = {a : 123,b : 456,c : "abc"}
 const obj2 = {a : 789,e : "asdf"}
//将2的内容覆盖到1  会对1产生影响
const obj = Object.assign({},obj1,obj2)
console.log(obj)
console.log(obj == obj1)

3…getOwnPropertyNames() 用于枚举的顺序,返回一个数组,枚举出来对象的属性
这里要知道对象的顺序其实是浏览器厂商自行规定的,现排数字并且是升序的,再排其他,按照书写顺序

例:
const obj = {
e : 1,
a : 2,
c : 3,
0 : 6,
5 : 7,
2 : 3
}
console.log(obj)
const arr = Object.getOwnPropertyNames(obj);
console.log(arr); 

4.setPrototypeOf() 设置某个对象的隐式原型 proto

const obj1 = {a : 1}
const obj2 = {b : 2}
//obj1.__proto__ = obj2;  必须要通过构造函数来完成
Object.setPrototypeOf(obj1,obj2);
console.log(obj1);

面向对象

面向对象是一种编程思想,跟语言没有关系
这个主要是不去思考过程,而是去思考有几个对象,如果功能非常小,安全,没有必要按照面向对象的思维去思考,例:将一个大象装进冰箱

代码:
function Elephant(){}
function Frige(){}
Frige.prototype.openDoor = function(){}
Frige.prototype.closeDoor = function(){}
Frige.prototype.join = function(){}

var frig = new Frige();
frig.openDoor()
var ele = new Elephant()
frig.join(ele)
frig.closeFrige()

构造函数

以前的构造函数的问题
1.属性和原型方法分开了,代码可读性差
2.原型上的属性也是可以枚举的
3.构造函数也是可以当成普通函数使用的

类的描述和使用:

1.类的声明不会被提升,和let const 一样,有临时性死区
2.类的所有代码全都是在严格模式中执行
3.类的所有方法都是不可枚举的
4.类的所有方法都无法当成构造函数直接使用
5.类的构造器必须使用new 来调用

ES6中的逻辑上的合理写法:

class Person{
	construtor(job,name,age,sex){
		this.job = job;
		this.name = name;
		this.age = age;
		this.sex = sex;
	},
	print(){
	console.log("工作:",this.job);
	console.log("姓名:",this.name);
	console.log("年龄:",this.age);
	console.log("性别:",this.sex);
	}
}
const a = new Person("程序员","zheng",30,"nan");
console.log(a);
a.print();

1.可以写成计算属性名

例子:
const printName = "print";
const test = "job1"
class Person{
constructor(job,name,age,sex){
	this[test] = job;
	this.name = name;
	this.age = age;
	this.sex = sex;
}
	[printName](){
		console.log('工作:',this[test])
		console.log('姓名:',this.name)
		console.log('年龄:',this.age)
		console.log('性别:',this.sex)
	}
}
const a = new Person("程序猿","zhansan",30,"nan");
console.log(a)
a[printName]()

2.可以使用getter 和 setter
getter取值的时候必须走进来 get
setter 设置值得之后必须走进来 set

const printName = "print";
const test = "job1"
class Person{
	constructor(job,name,age,sex){
			this[test] = job;
			this.name = name;
			this.age = age;
			this.sex = sex;
	}
	get age(){  //取值的时候走  没有参数
		return this._age + "岁";
	}
	set age(age){  //创建的时候进来,必须接受一个参数
		if(typeof age !== "number"){
			throw new TypeError("age must a number")
		}
		if(age < 0){
			age = 0
		}else if(age > 200){age = 200}
		this._age = age;
	}

	[printName](){
		console.log('工作:',this[test])
		console.log('姓名:',this.name)
		console.log('年龄:',this.age)
		console.log('性别:',this.sex)
		}
	}
const a = new Person("程序猿","zhansan",-10,"nan");
console.log(a)
a[printName]()

get set 控制的属性不在原型上
ES5的写法

Object.defineProperty(this,"age", {
	set(age){},
	get(){}
})

3.静态成员

const printName = "print";
const test = "job1"
class Person{
constructor(job,name,age,sex){
this[test] = job;
this.name = name;
this.age = age;
this.sex = sex;
}
[printName](){
console.log('工作:',this[test])
console.log('姓名:',this.name)
console.log('年龄:',this.age)
console.log('性别:',this.sex)
}
}
const a = new Person("程序猿","zhansan",-10,"nan");
console.log(a)
a[printName]()

ES6中提供了一个新的关键字static

实例:
class Qi{
constructor(name,width,height){
his.name = name;
// this.width = width;
// this.height = height;
}
static width = 50;   //添加静态成员
static height = 50;
static method = function(){}
}
const ma = new Qi("马",50,50);
const pao = new Qi("炮",50,50);

console.log(ma.width)
console.log(pao)

console.log(Qi.width)

4.字段初始器(es7)也就是可以让你去简写的写法

例:
class Test{
a = 1;  //初始化的工作,如果没有使用static,就是实例成员
b = 2;
static c = 3
	print = () => {    //不会存放在原型上面,会占用一定的存储空间
		console.log(this.a)
	}
}
const t = new Test()
const g = new Test()
console.log(t)
console.log(t.a,t.b,t.c,Test.c)

t.print()
console.log(t.print == g.print)
在使用static这个关键字时要注意的一下几点:

1.使用static添加字段初始器,添加的是静态成员
2.没有使用,则位于对象上
3.箭头函数在字段初始器位置上,指向当前对象

  1. 类表达式
例子:
const A = class{  //匿名类,类表达式,类在js中本身就是表达式
	a = 1;
	b = 2;
}
const a = new A();
console.log(a)

ES6里面的创建对象就是要使用class,这个也刚好也可以创建一个类方法,自然语法也是差不多的,同上面一样

ES6原型链(原型之间的继承)
在之前所讲的ES6里面也有别的方法可以进行继承那个方法就是:Object.setPrototypeOf(Dog.prototype,Amimal.prototype)

然而在这里有一种属性可以进行原型链之间实现原型链的继承关系:extends 继承,这个用于类中的定义
super的两种用法:1.直接当成函数调用,表示父类的构造

用法实例:
class Animal{
	constructor(type,name,age,sex){
		this.type = type;
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	print(){
		console.log(`种类 : ${this.type}`)
		console.log(`名字 : ${this.name}`)
		console.log(`年龄 : ${this.age}`)
		console.log(`性别 : ${this.sex}`)
	}
}
class Dog extends Animal{
// 如果定义了constructor 并表示这个是子类,则必须在constructor的第一行手动调用父类的构造函数
// constructor(name,age,sex){
// 	super("犬类",name,age,sex)
// }
//如果说子类不写constructor,则会有默认的构造器,自动去调用父类的构造器
 }
const d = new Dog("旺财",5,"公");
console.log(d);
d.print();

2.super如果说当成对象使用,则表示父类的原型

用法实例:

class Animal{
	constructor(type,name,age,sex){
		this.type = type;
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	print(){
		console.log(`种类 : ${this.type}`)
		console.log(`名字 : ${this.name}`)
		console.log(`年龄 : ${this.age}`)
		console.log(`性别 : ${this.sex}`)
	}
}

class Dog extends Animal{
	constructor(name,age,sex){
		super("犬类",name,age,sex);
		this.loves = "吃骨头"
	}
	print(){   //同名的方法会进行覆盖
		// console.log("wang")
		// 2.super如果说当成对象使用,则表示父类的原型
		super.print();

		console.log(`爱好 : ${this.loves}`)
	}
}

const d = new Dog("旺财",5,"公");
console.log(d);
d.print();

ES6中新增的符号(Symbol(符号描述))

ES6里面新增的,以前没有这块的内容,面试点,不是开发点,开发基本用不上
这个符号是用来创建的,这个也同时是新增的一个数据类型,可以用typeof来检测,返回的数据类型是symbol

创建形式:
const syb1 = Symbol();   //创建了一个符号
const syb2 = Symbol("asdfsdf");
注意:

符号的设计,给对象去新增私有属性的,只能在对象内部进行访问

符号的特点:
1.没有字面量的写法

var arr = []
var obj = {}
var reg = //

2.新的数据类型,typeof返回的是symbol

3.每次去调用Symbol函数得到的符号永远不会相等,不管符号描述是否相同

例子:
const syb1 = Symbol("abc");   
const syb2 = Symbol("abc");
console.log(syb1,syb2)
console.log(syb1 === syb2)

4.符号可以作为对象的属性名使用,这种属性名叫符号属性

例:
const syb1 = Symbol("abc");  
const obj = {
	a : 1,
	b : 2,
	[syb1] : 3    //符号属性
}
console.log(obj)

5.可以通过设计,让外面无法访问到

例:
const Hero = (() =>{
	const getRandom = Symbol()   //计算属性名
	return class{
	
		constructor(attack,hp,defence){
			this.attack = attack;
			this.hp = hp;
			this.defence;
		}
		gongji(){
			const dmg = this.attack * this.getRandom(0.7,1.2)
		}
		[getRandom](min,max){
			return Math.random() * (max - min) + min
		}
	}
})()
const h = new Hero(3,100,3)
console.log(h)

6.符号属性不能被枚举

例子:
const syb1 = Symbol("abc");  
const obj = {
	a : 1,
	b : 2,
	[syb1] : 3    //符号属性
}
console.log(obj)
for(const prop in obj){
	console.log(prop)
}
console.log(Object.keys(obj))   //es5获取属性名的方法也不行
console.log(Object.getOwnPropertyNames(obj))   //ES6方法也不能获取属性名
// 针对符号属性
// getOwnPropertySymbols(obj)
// console.log(Object.getOwnPropertySymbols(obj))
const sybs = Object.getOwnPropertySymbols(obj)[0];
console.log(sybs == syb1)


const Hero = (() =>{
	const getRandom = Symbol()  
	return class{
	
		constructor(attack,hp,defence){
			this.attack = attack;
			this.hp = hp;
			this.defence;
		}
		gongji(){
			const dmg = this.attack * this.getRandom(0.7,1.2)
		}
		[getRandom](min,max){  
			return Math.random() * (max - min) + min
		}
	}
})()
const h = new Hero(3,100,3);

console.log(h)
const sybs = Object.getOwnPropertySymbols(Hero.prototype);
const prop = sybs[0];
console.log(h[prop](3,5,10))

7.符号类型无法被隐式转换,数学运算,字符串拼接都是不行的
可以进行内部的显式转换 console.log的输出

例:
const syb = Symbol();
console.log(syb + 10)

共享符号:Symbol.for("符号描述")
例:
const syb1 = Symbol.for("abc");   
const syb2 = Symbol.for("abc");
console.log(syb1,syb2)

知名符号是特殊含义的共享符号,通过Symbol的配置得到的。JavaScript 松散,写法不严谨
必须去解决这些严谨性的问题

配置底层的实现原理
1.Symbol.hasInstance

例:
function A(){}
console.log(obj instanceof A) 
const obj = new A();
console.log(A[Symbol.hasInstance](obj));  //不能这种方式配置
Object.defineProperty(A,Symbol.hasInstance,{
	value : function(obj){
		console.log(obj);
		return false;
	}
})
const obj = new A();
console.log(obj instanceof A)    //可以去改变instanceof  的值

2.Symbol.isConcatSpreadable 会对数组的方法产生影响

例:
const arr = [3];
const arr2 = [4,5,6,7]
arr2[Symbol.isConcatSpreadable] = false;
const result = arr.concat(99,arr2) //对两个数组拆分链接成新的数组
console.log(result)

const arr = [1];
const obj = {
	0 : 3,
	1 : 5,
	length : 2,
	[Symbol.isConcatSpreadable] : true
}
const result = arr.concat(99,obj)
console.log(result)

3.Symbol.toPrimitive 对类型的转换产生改变

例:
const obj = {
	a : 1,
	b : 2
}
obj[Symbol.toPrimitive] = function(){
	return 123
}
console.log(obj + 123)

4.Symbol.toStringTag 可以影响Object.prototype.toString的返回值

例:
class Person{
	[Symbol.toStringTag] = "Person"
}
const p = new Person()
console.log(p)
const arr = [12,1,2]
console.log(Object.prototype.toString.call(p))

promise

事件循环
JS运行环境成为宿主环境

ECMAscript 和 JavaScript是什么关系

在这里插入图片描述

执行栈()call stack 一个数据结构,存放各种函数的执行环境,每一个函数执行之前,它的相关信息会加入到执行栈中
,函数调用之前,会创建执行环境,然后加入到执行栈中,函数调用完成,会销毁执行栈
在这里就要记住在栈里面执行的就是先进后出,后进的先出

JS引擎永远执行栈顶。 执行栈的最顶部

JS是单线程
异步函数 : 某些函数不会立即执行,需要等到一定的时候才能执行,这种函数称为异步函数,例如事件,定时器
异步函数的执行,会被宿主环境所控制

浏览器有5条线程

1.js线程(主线程) 负责去执行栈顶的代码
2.GUI线程
js线程和gui线程会互相等待
3.事件监听线程 负责监听各种事件
4.计时线程 负责定时器
5.网络线程 各种网络请求

当上面的线程发生了某些事情的时候,如果该线程发现,这件事情有处理程序,它会将该程序加入到一个事件队列中,当JS引擎发现,执行栈没有任何内容,会将事件队列的第一个函数加入到执行栈中执行

js引擎对事件队列取出执行的方式,以及与宿主环境配合,称为事件循环

在ES6中同时也新增了一个API可以进行监听dom对象的变化就是(MutationObserver),同时还有一个取消监听的方法就是:observer.disconnect()

实例:
const ul = document.getElementById("container");
		let count = 1;
		document.getElementById("btn").onclick = function AAA(){
			// console.log('添加了一个li')
			setTimeout(function(){
				console.log('添加了一个li')
			})

			const li = document.createElement("li");
			li.innerText = count ++;
			ul.appendChild(li)
		}

		const observer = new MutationObserver(function BBB(){
			console.log('ul里面内容发生了改变')
		})

		observer.observe(ul,{
			attributes : true,
			childList : true,
			subtree : true
		})

事件队列分为两种,宏队列和微队列 微队列相当于一个vip
宏任务 计时器 事件回调,http回调
微任务 Promise MutationObserver

当执行栈清空时,JS引擎首先会将微队列的所有任务依次执行,如果没有微任务,将执行宏任务

事件和回调
回调和事件处理来解决异步的问题

回调:运行某个函数实现某个功能的时候,传入一个函数作为参数,当发生某件事情的时候,会执行该函数
1.回调地狱:某个异步操作需要等待之前的异步操作完成,无论回调是事件还是其他函数,都会陷入不断的嵌套
2.异步之间存在联系的 某个异步操作要等待别的操作对他的结果,这种联系的处理,会让代码的复杂度急剧增加

异步处理的模型
ES官方参考了大量的异步场景,总结出了一套异步通用的模型,这套模型可以覆盖几乎所有的异步场景

ES6中增强的功能,ES为了兼容以前的版本,以前旧的写法并没有抛弃,针对这些场景推出了新的API,这套API对异步的处理,变得更为简洁

ES6将某一件事情可以发生异步操作的时候,分为了2个阶段 unsettled 和 settled
unsettled未决阶段
settled已决阶段

事情总是从 未决阶段逐步发展到已决阶段,并且,未决阶段拥有控制通往已决阶段的能力

es6将程序分为了三种状态 pending resolved rejected
pending:挂起(等待) 处于未决阶段,表示事情还是在挂起,最后的结果没有出来
resolved:已处理 处于已决阶段,表示整个事情已经出现结果,并且可以按照正常的逻辑进行下去的结果
rejected:已拒绝 处于已决阶段,表示整个事情已经出现结果,并且是一个无法按照正常逻辑进行下去的结果

实例:
const pro = new Promise((resolve,reject) => {
	// reject表示的是失败的请求  没网,微信发不出去
	console.log('张三向女生发出表白微信')
	setTimeout( () => {
		if(Math.random() < 0.1){
			resolve(true)
		}else{
			resolve(false)
		}
	},1000)
})

pro.then(data => {
	console.log('通过resolve推过来的状态')
	console.log(data)
},err => {
	console.log("通过reject推过来的状态")
	console.log(err)
})
pro.then(data => {
	console.log('通过resolve推过来的状态')
	console.log(data)
},err => {
	console.log("通过reject推过来的状态")
	console.log(err)
})
pro.then(data => {
	console.log('通过resolve推过来的状态')
	console.log(data)
},err => {
	console.log("通过reject推过来的状态")
	console.log(err)
})

未决阶段有权利决定事情的走向,未决阶段可以决定事情走向最终的状态

把事情推向resolved 状态的过程,可能会传递一些数据
把事情推向resolved 状态的过程,可能会传递一些数据,这些数据一般为错误信息

无论是哪个阶段还是状态,都是不可逆的

当事情已经到达已决阶段后,通常要进行后续的处理,不同的已决解决,决定了不同的后续处理

resolved 这是一个正常的已决状态,后续处理表示为 thenable
rejected 这是一个非正常的已决状态,后续处理表示为 catchable

后续的处理可能会有多个,因此会形成任务队列,这些后续处理会按照顺序,当达到对应的状态后依次执行

Promise 承诺
const pro = new Promise((resolve,reject) => {
未决阶段
通过调用resolve函数将promise推向已决阶段的resolve状态
通过调用reject函数将promise推向已决阶段的reject状态
resolve 和 reject 只能使用一个,如果使用了多个,也只有第一个有用
传递参数只能有一个,表示推向状态的数据
resolve({})
reject(456)
})
pro.then(data=>{
thenable函数,promise已经是已决阶段,resolve状态

},err => {
catchable reject状态
})

1.未决阶段的处理函数是同步的,会立即执行
2.thenable和catchable函数是异步的,就算会立即执行,也是会加入等待队列中,加入微队列

例子:
const pro = new Promise((resolve,reject) => {
	console.log("a")
	// resolve(1)
	reject(123)
	setTimeout( ()=>{
		console.log('b')
	},0)
})
pro.then(data => {
	console.log(data)
})
pro.catch(err => {
	console.log(err)
})
console.log('c')

3.pro.then可以只添加thenable函数,pro.catch可以单独添加catchable函数
例子:
const pro = new Promise((resolve,reject) => {
	throw new Error("123")
})

pro.then(data => {
	console.log(data)
})

pro.catch(err => {
	console.log(err)
})

4.在未决阶段的处理函数中,如果发生未补获的错误,会将状态推向rejected,并且会被catchable捕获

5.一旦状态推向了已决阶段,无法再去做任何的改变

const pro = new Promise((resolve,reject) => {
	throw new Error("123asdfsdf")   //未捕获
	try {
		throw new Error("123")   //捕获了的错误
	} catch(e) {

	}
	resolve(123); //无效
	reject(456);  //无效

})

pro.then(data => {
	console.log(data)
})

pro.catch(err => {
	console.log(err)
})		
处理异步的消息的
注意:
1、如果当前的promise是未决状态的,得到的新的promise是挂起状态的
例子:
const pro1 = new Promise((resolve,reject) => {
	resolve(1)
})
console.log(pro1)
const pro2 = pro1.then(result => result*2)   //通过then调用以后,又是返回的一个全新promise对象
console.log(pro2)  //pending状态  等待前面的处理结果

2、多个promise对象串联的时候如何完成

例:
const pro1 = new Promise((resolve,reject) => {
	throw 1
})
const pro2 = pro1.then(result => {result * 2},err => {
	throw err * 3
})  
const pro3 = pro1.catch(err => {return err * 10})
pro3.then(result => {
	console.log(result * 2)
},err => {
	console.log(err * 3)
})

3、如果前面的promise的后续处理,返回的是一个promise,则返回的promise状态和后续处理返回的promise状态保持一致

例子:
const pro1 = new Promise((resolve,reject) => {
	resolve(1)
})

const pro2 = new Promise((resolve,reject) => {
	resolve(2)
})

const pro3 = pro1.then(result => {
	return pro2;   //推一个对象过去,这个对象不能是这种promise,推pro2的状态
})

pro3.then(result => {
	console.log(result)
})

4、Promise并不是消除回调,只是让回调变得更简单,变更可控,解决promise的回调

例子:
function biaobai(nvsheng,callback){
	return new Promise(resolve => {
		console.log(`张三向女生${nvsheng}`)
		setTimeout(() => {
			if(Math.random() < 0.2){
				resole(true);
			}else{
				resolve(false);
			}
		},5000)
	})
}
const nvArr = ["女生1","女生2", "女生3","女生4","女生4"];
let pro;
for(let i = 0 ; i < nvArr.lenght ; i++){
	if(i == 0){
		pro = biaobai(nvArr[i]);
	}
	pro = pro.then(result => {
		if(result === undefined){
			return
		}else if(result){
			console.log(`${nvArr[i]}同意了`)}else {
			console.log(`${nvArr[i]}拒绝了`);
			if(i < nvArr.lenght - 1){
				return biaobai{nvArr[i+1]}
			}
		}
	})
}

原型成员(实例成员)

then(data => {},err => {})
注册一个后续处理函数,当promise为resolved状态是运行该函数,当promise为rejected状态是运行该函数的第二个参数
catch() 注册一个后续处理函数,当promise为rejected状态是运行该函数,习惯把失败写在catch中
关键字finally() ES2018(ES9)出来的,没有参数的,当promise为已决时运行该函数

const pro = new Promise((resolve,reject) => {
resolve(1)
})
pro.finally(() => {
console.log(‘finally’)
})
pro.then(result => {
console.log(‘then’,result * 2)
})

构造函数成员(静态成员)

1.resolve()

例:
const pro = Promise.resolve(1)
等同于
const pro = new Promise((resolve,reject) => {
	resolve(1)
})

2.reject()
例:

const pro = new Promise((resolve,reject) => {
	reject(1)
})
const pro = Promise.reject(1)

特殊情况:如果传递的是Promise,则直接返回传递的Promise对象

例:

const pro = new Promise((resolve,reject) => {
			resolve(123)
		})
		const pro2 = Promise.resolve(pro)
		console.log(pro,pro2)
		console.log(pro2 === pro)

在这里pro2 === pro返回的是true

注意:
1、all(arr) 这个方法会返回一个新的promise对象,如果里面所有的promise对象都成功才会触发,一旦有一个失败,则该promise对象为失败
所有的都成功才为成功,只要有一个失败,就失败
2、race(arr) 当参数中的任意一个promise对象完成时候,就马上回去使用完成的这个promise对象的结果,不管这个结果成功还是失败

在ES2016(ES7)中 新增了两个关键字 async await 为了去简化promise的写法的
结合生成器来简化promise的操作

1、async 用于去修饰函数(函数声明和函数表达式),放在函数的开始位置,被修饰的函数一定返回一个promise对象

例子:
简化promise创建的
function test(){
	return new Promise((resolve,reject) => {
		// resolve(123)
		throw(123)
	})
}
const pro = test();
console.log(pro)

2、await 等待
await关键字必须出现在async函数中

例子:
async function test1(){
	return 123;
}
async function test2(){
	const result = await test1();
	console.log(result)
}
test2()

如果await后面不是一个promise对象

async function test(){
	const result = await 1;   // 如果await的表达式不是Promise,则会对包装一个promise继续按照规则执行
	console.log(result);
}

如果async中有错误的时候

async function getPromise(){
	if(Math.random() < 0.5){
		return 1;
	}else {
		throw 2;
	}
}

async function test(){
	try {   //可以使用trycatch去捕获async中的错误
		const result = await getPromise();
		console.log("正常",result)
	} catch(err) {
		console.log("错误",err);
	}
}
test()

迭代器

1.什么是迭代?
从一个数据集合中按照一定的顺序,不断的取出数据的过程
2.迭代和遍历有什么区别?
迭代强调是依次取出,不能确定取出的有多少,也不能保证把数据全部取完

3.迭代器
对迭代过程的封装,通常为对象,不同的语言中,表现出来的迭代形式不一样

4.迭代模式
一种设计模式,用于同一迭代的过程,并且规范迭代器的规格

迭代器有得到下一个数据的能力
判断是否有后续数据的能力

js中的迭代器
js的规定,如果一个对象有next方法,并且返回一个对象,就认为这个对象为迭代器

语法:
const obj = {
	next(){   用于得到下一个数据
		return {
			value : xxx  数据
			done : xxx   判断是否有后续数据,一般为boolean
		}
	}
}

在创建迭代器是只需要他考虑他的后面还有没有数,不需要去考虑数的多少,直到没有数据为止,这个在数组和对象都可以使用

注意:
在es6中,如果对象具有知名符号的属性 Symbol.iterator,则表示对象可以迭代
例:
const arr = [545,874854,15485,54854,6];
const inerator = arrStmbol.iterator;

在ES6及之后,数组可以直接创建迭代对象

for of 循环就是专门遍历可迭代的对象的,不是可迭代的对象不能使用forof遍历

例:
for(const item of arr){
	console.log(item)
}

自定义可迭代对象
书写方法:

const obj = {
	a : 1,
	b : 2,
	[Symbol.iterator](){   //for of循环肯定是会走到这个函数中的
		const keys = Object.keys(this);
		// console.log(keys)   //
		let i = 0;
		return {
			next:() => {
				const propName = keys[i];
				const propValue = this[propName];
				const result = {
					value : {
						propName,
						propValue,
						name : "alskdfj"
					},
					done : i >= keys.length
				}
				i ++;
				return result;
			}
		}
	}
}

// console.log(obj)
for(const item of obj){
	console.log(item)
}

生成器(generator)

1.什么是生成器?
生成器就是通过构造函数Generator创建出来的对象,生成器既是一个迭代器,同时又是一个可迭代的对象

2.创建
只需要把函数变成Generator函数
async和* 不能同时加

例:
function* test(){}
const generator = test();  //next  symbol
console.log(generator) // 迭代器

3.生成的内部执行
关键字 yield 只能在函数内部使用,表示产生一个迭代数据
每一次调用生成器的next方法,会将生成器函数运行到下一个yield关键字位置

例子:
function *test(){
	console.log(123);
}
const generator = test();  //生成了一个生成器而已
generator.next()

set集合

// array object 在不同的场景去发挥作用的

1、set用于存放不重复的数据

例:
const s1 = new Set(iterable);
const s1 = new Set([1,2,3,4,5,6,7,8,9,1,23,4,5,6])

2、会转换成字符串对象,再进行存储

例:
const s1 = new Set("lasdkjflksdjflksdjf");
console.log(s1)
console.log(new String("sadfsdf"))

原型方法(实例方法)
1、add()

例:
const s1 = new Set();
s1.add(1)
s1.add(2)
s1.add(3)
s1.add(1)   //无效的
console.log(s1)

2、Object.is() +0 和 -0 set是认为相等的

例:
s1.add(+0);
s1.add(-0);
console.log(s1)

3、has()

例:
console.log(s1.has(1))
console.log(s1.has(10))

4、delete() 返回是否删除成功

例:
console.log(s1.delete(1))
console.log(s1.delete(10))

5、clear()

例:
s1.clear()
console.log(s1)

6、size属性 只能读,不能改

例:console.log(s1.size)

// 遍历
// for of
for(const item of s1){
console.log(item)
}
// 重写的实例方法 forEach

例:
s1.forEach((item,index,s) => {
注意:
index 不是下标,set集合没有下标
forEach中的第一个参数的值和第二个参数的值是相同的,都表示set中的每一项

	console.log(item,index,s)
})

Map集合

map键值对,特点:建名不能重复
对象存储的问题:
1.建名只能是字符串
2.获取数据的数量的时候不方便
3.建名容易和原型上的名称发生冲突

1、创建
const map = new Map(iterable);
传递的应该为二维数组,数组的子数组里面只能有两项,第一项为键,第二项为值

例:
const map = new Map([
		["a",123],
		["b",456],
		["c",789],
		["d",1]
	])
console.log(map)

后续操作
1、size

console.log(map.size)

//set() 传递的是键值对,两个参数,键是可以为任意类型的

map.set("e","alsdjk")

注意:
1、键不存在,则添加一项
2、 键存在,则修改

// get()

console.log(map.get("a"))

has()、delete()、clear()这个的使用和Set的使用这个的方法是一个样的

遍历

例:
for(const item of map){
	console.log(item[0],item[1])
}

解构

例:
for(const [key,value] of map){   
 	console.log(key,value)
}

forEach()的使用方法:

map.forEach((value,key,map) => {
	console.log(value,key,map)
	value 值
	key 键
	map 对象本身
})

WeakSet集合和 WeakMap集合

使用WeaSet集合,可以实现和set一样的功能
1.内部存储地址不会影响垃圾回收
2. 只能添加对象
3.不能遍历,不是一个可迭代的对象,没有size属性,没有foreach方法

weakmap和map集合类似
1.内部存储地址不会影响垃圾回收
2.键名只能对象
3.不能遍历,不是一个可迭代的对象,没有size属性,没有foreach方法

例:
const wmap = new WeakMap();
let lis = document.getElementsByTagName("li");
for(const li of lis){
	wmap.set(li,{
		id : li.innerHTML,
		name : `名字${li.innerHTML}`
	})
}

lis[0].remove()
console.log(wmap)
Property Desciptor属性描述符

就是一个普通的对象,描述属性的相关信息

Object.getOwnPropertyDescriptor(obj,“a”) 可以得到对象的某个属性的属性描述
console.log( Object.getOwnPropertyDescriptor(obj,“a”) ) 一个
console.log( Object.getOwnPropertyDescriptors(obj) ) 多个

configurable: 该属性是否可以被属性描述符修改
enumerable: 是否可以枚举
value: 属性值
writable: 是否可以重新赋值

对属性进行修改
Object.defineProperty 这个只能得到一个
Object.defineProperties 这个只能得到多个

存储器属性

class getter 和 setter 一样
存的时候会去调用setter 取得时候会去调用getter

例:
const obj = {b : 2}

Object.defineProperty(obj,"a",{
	get(){
		console.log('不知道哪里查看了a属性')
	},
	set(val){
		console.log('设置a属性',val)
	}
})
obj.a = 10;
obj.a = obj.a + 1;
console.log(obj.a) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值