ES6
let和var的区别?
-
let是块级作用域,var是函数作用域
-
let不存在变量声明提升,var有声明提升
-
let有暂时性死区,(TDZ)【需要满足先声明后使用的原则】
-
let不能重复声明变量
-
let和const声明的变量不在与浏览器的顶层对象window的属性挂钩,var或function声明的变量会在window的属性中体现出来
1.注意块级作用域 2.暂时性死区 3.不存在变量提升 4.同一作用域内不允许重复声明
const的注意事项
- const声明的时候要赋值(初始化赋值),否则报错
- const声明的变量后续不可在赋值修改,否则报错
const的用法
- 必须在声明的时候赋值,否则报错
- 不能修改
- const声明的对象类型,对象或数组内部得值可以改
- const声明的常量建议使用大写
结构赋值
解构赋值的作用是将数组或对象中地值解构出来赋值给变量
解构赋值重点理解“模式”的概念
什么是模式:所谓的模式就是赋值运算符左边的[]或{},赋值运算符右边是对象或数组
-
结构赋值的作用是将数组或对象中的值解构出来赋值给变量,示例:
let [a,b,c]=[1,2,3]; 数组或对象中的内容小于模式匹配的内容,被认为是解构不成功,反之为不完全结构 let [a,b]=[1,2,3] 不完全结构 let [a,b,c,d]=[1,2,3] 结构不成功 基于解构不成功,提出了默认值的概念,默认值生效的条件是:数组或对象中的内容严格等于undefined,则默认值生效 let [a,b,c,d=4]=[] 数组解构赋值的妙用:交换值 let a=1; let b=2; [a,b]=[b,a] //spread和rest运算符
-
重点!对象的解构赋值(key也是模式)
let {title}= {title:'雪碧'}//使用简写模式 let {title:title}={title:'雪碧'} let {title:t} = {title:'雪碧'} 示例: let obj={ info:[ { name:'雪碧', age:'1' },{ } ] } obj.info[0].name//正确 obj.info[1].age//错误 对象解构赋值的默认值 let {title,name:'xuebi'}= {title:'黎明'}//简写 let {title,name:name='lishi'}
-
重点!函数形参解构赋值
function fun ({type='GET',datatype='json'}={}){ //TODO } fun({type:'GET',datatype:'xml'}) fun({type:'POST'}) fun()
字符串是类数组,数组又是特殊的对象,所以有了下面的解构形式:
let {0:a,1:b,2:c}='abc' 这种形式的解构写法,语法允许但毫无意义
模板字符串
模板字符串(可以接受回车或者换行或空格(回车换行和空格最终可以体现到dom中)变量的嵌入很方便)
好处:
- 模板字符串为构造多行字符串和字符串拼接带来了更加方便的方式
- 统一模板字符串可以通过使用不同的标签,对模板进行进一步处理,输出不同的结果
传统拼串
let title='周三';
let str ='<div>'+ title +'</div>'
模板字符串拼串
let str =`<div>${title}</div>`
let str = `
<div>
<h1>${title}</h1>
<p>段落</p>
</div>
`
多行拼串
let a=`In JavaScript \n is a line-fead`
let b=`In JavaScript this
not legal`;
标签模板
标签指的是函数名,模板指的是函数的实参(es6模板字符串形式的实参)
let a = 5;
let b = 10;
fun`${a+b}world${a}hello${a*b}`
等同于
tag(['hello','world',''],15,50)
标签模板的第一个参数是一个数组,用来接受模板中的非变量部分
标签模板的第二个参数或后面的参数,用来接受模板中的变量部分
function fun(){
console.log(arguments);
}
深拷贝
深拷贝、浅拷贝指的都是对象数据类型的拷贝
**原理:**js的深拷贝发生在对象的赋值上,对象赋值的时候仅仅是一个引用赋值,也就是说两个不同变量名指向的是同一份内存空间;基本数据类型则不存在这样的行为;要完成对象的深拷贝需要使用递归遍历所有对象的属性进行赋值,也可以使用JSON.stringify和JSON.parse操作
默认的对象拷贝是浅拷贝
let arr = [1,1,3];
let arr1= arr;
arr[0]= 4;
使用json完成深拷贝
let m= [1,2,3];
let n = JSON.parse(JSON.stringify(m));//深拷贝
spread扩展运算符
spread运算符的表示是:’…'三个点表示
-
数组使用扩展运算符
var arr=[1,3,4]
console.log(…arr)
场景:函数的接收参数
…运算符在函数形参中出现,被认为是rest剩余参数运算符
所谓的剩余参数指的是,出了…前面德参数之外,所有的实参都存到args参数里,所以args参数是一个数组
剩余参数运算符应该出现在形参列表的末尾
当…运算符出现的在函数形参中的时候,表示rest剩余参数运算符
对象属性名简写和属性名表达式
对象属性名简写
let x = 10;
let title = 'xuebi'
let obj={
x,
file:function(){
console.log('1')
},
discuss(){
console.log('2')
}
}
obj[title]='可乐'
对象属性名表达式
let obj ={};
obj.title='雪碧';//属性名是字符串
obj['age']='1';//属性名是字符串
obj[title+1] = '可乐';//属性名表达式(重点理解表达式概念)
console.log(obj)
对象在新增属性名的时候可以后字符串形式或表达式形式两个做法
取出对象属性内容的时候也可以是字符串或表达式
symbol
symbol是ES6新增的数据类型,也就是说symbol是es6中的第七种数据类型
它的作用是产生独一无二的值
它的使用场景:
-
给对象属性名赋值,防止被覆盖
-
模拟class私有变量
console.log(Symbol()); console.log(typeof Symbol()) 严重注意:symbol()每次调用都要产生一个独一无二的值 使用场景:给对象属性名赋值,防止被覆盖 let obj={}; obj[Symbol()]='你永远找不到我'; console.log(obj[Symbol()]); //改进 let key = Symbol(); let obj={}; let obj[key]='你永远得不到我'; console.log(obj[key]); symbol带描述符的用法 console.log(Symbol('电影')===Symbol('电影')); symbol.for 的用用法(for的key如果一样,则symbol.for产生的内容就是一样的) console.log(Stmbol.for('电影')===Symbol.for('电影'))
Promise
Promise用来解决异步回调问题,由于js是单线程的,很多异步操作都是依靠回调方法实现的,这种做法在逻辑比较复杂的回调嵌套中会相当复杂;也叫做回调地狱;promise用来讲这种繁杂的做法简化,让程序更具备可读性,可维护性;promise内部有三种状态,pedding、fulfilled、rejected;pedding表示程序正在执行单位得到结果,及异步操作没有执行完毕,fulfilled表示程序执行完毕,且执行成功,rejected表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非要报错,其实,promise和回调函数一样,都是要解决数据的传递和消息发送问题,promise中的then一般对应成功后的数据处理,catch一般对应失败后的数据处理。
resolve表示成功的状态
reject表示失败的状态
var p = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve('成功');
reject('失败')
})
})
resolve对应then的回调结果
reject对应catch的回调结果
p.then(function(rst){
console.log(rst)
}).catch(function(err){
console.log(err)
})
链式操作
promise的then的链式操作,then内部的return返回,如果return是promise对象,则下一个then调用者是promise对象,如果return的是非promise对象数据,则该数据作为下一个then的回调函数参数,链式的then只处理resolve,then默认返回一个promise对象,这个默认promise就是上一次执行的promise对象
var p = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve('成功')
})
})
p.then()是一个链式操作,也就是说then方法内部会返回一个promise对象,这个promise默认就是当前promise对象
then的回调函数参数是由resolve来触发调用的
p.then(function(rst){
console.log(rst)
return '成功1'
}).then(function(rst){
console.log(rst)
}).catch(function(err){})
Promise_all
var p1 = new Promise(function(resolve,reject){
setTimeout(function(){
reject('p1失败')
},1000)
})
var p2 = new Promise(function(resolve,reject){
setTimeout(function(){
reject('p2失败')
},1000)
})
p1和p2在数组中的次序决定了rst结果集中的顺序
all里面的promise对象如果有一个失败则全部失败,不会返回任何成功结果
p1(true) && p2(true) 执行then
p1(false) && p2(true) 执行catch
p1(true) && p2(false) 执行catch
p1(false) && p2(false) 执行catch
Promise.all([p1,p2]).then(function(rst){
console.log(rst)
}).catch(function(err){
console.log(err)
})
promise_race
var p1 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve('p1失败')
},1000)
})
var p2 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve('p2失败')
},1000)
})
Promise.race([p1,p2]).then(function(rst){
console.log(rst)
}).catch(function(err){
console.log(err)
})
Promise简写
var p1 =new Promise.resolve($.get('http://www.bestqingshan.top/demo/ajaxWeather.php'))
p1.then(function(rst){
console.log(rst)
})
函数参数默认值
ES5中的默认值设置
function fun(x){
x = x ===undefined ? 1 : x;
console.log(x)
}
ES6中默认值使用
function fun(x=1){
console.log(x)
}
fun();//默认值生效
fun(2);//默认值不生效
fun(undefined);//默认值生效
fun(null);//默认值不生效
箭头函数
- 箭头函数是匿名函数,不能绑定自己的this、arguments、super、new、target
- 箭头函数会捕捉其所在上下文的this值,作为自己的this值,在使用call/apply绑定时,相当于只是传入了参数。对this没有影响
- 箭头函数不绑定arguments,取而代之用rest参数…解决
- 箭头函数当方法使用的时候,没有定义this绑定
- 箭头函数不能作为构造函数,和new一起用就会抛出错误
- 箭头函数没有原型属性
- 不能简单返回对象字面量
try…catch
try...catch捕获的是运行错误,不是语法错误(语法错误在程序编译的时候就被检查出来)
使用try...catch的目的是让程序更加健壮
try{
let obj={}
if(JSON.stringify(obj)=='{}'){}
let a = obj.info.age
} catch (err){
console.log(err)
}
面向对象
面相对象(oop):面向对象是相对于面向过程而言的
面向过程:解决问题的时候,把问题过程化和步骤化去解决。
面向对象:把问题拆解归类,然后描述的是类与类,类与对象,对象与对象的关系
类:具备相同属性和行为的事务的抽象,所以类是用来描述属性和行为地
对象:对象是类的一个实例化,对象应该具备类所描述的行为的属性
了解面向对象:重点了解:属性、行为、对象和类,他们之间的关系
class Animal{
constructor(){
this.type = '动物'
}
}
class Tigger extends Animal {
constructor(){
super();
this.name = '雪碧'
}
}
let tigger = new Tigger();
console.log(tigger.type)
Class
class Animal {
/**
类是用来描述属性(变量)和行为(方法)的
var type;
this.type
constructor是ES6内置的方法,是一个构造方法使用new实例化一个对象的时候构造方法自动被调用,不要手动调用该方法
constructor构造方法的作用是用来初始化(初始化属性,初始调用一些方法)
**/
constructor(Newname,Newage){
//属性的描述应该放在constructor里面,否则报错
//var type = ''//局部变量
this.type = '动物';//成员变量
this.name = Newname;
this.age = Newage;
}
sayHi(){
console.log(this.type)
//方法内部访问属性,使用this
}
}
var animal = new Animal('雪碧',1)
animal.sayHi();
class用法this指向
new操作符都进行了什么操作?
new Object()
- 创建一个空对象,
- 调用对象的constructor
- 返回经过constructor构造方法初始化过所有属性和方法的新对象
两个对象是绝对不可能相等的
let a = {}
let b = {}
if (a===b){}
通过对象使用的属性或方法叫做成员变量和成员方法,成员变量和成员方法是属于对象,也就是说每个对象都有一份属于自己的属性和方法
与成员变量和成员方法相对的是静态变量合静态方法(类变量和类方法);因为类的声明不能重复(重复报错)所以静态变量或静态方法是独一份,是属于当前类的
this指的是当前调用者,谁调用就是谁(注意箭头函数内的this)
class静态
class Animal{
static type = '动物';//静态属性不要写到constructor里面
constructor(Newname){
//成员属性
this.name = Newname
}
//成员方法
sleep(){
console.log(this);
console.log('特别的睡姿')
}
//静态方法
static eat(){
console.log(this);
console.log('吃')
}
}
/**
成员变量和成员方法归对象所有
静态变量和静态方法归类所有
**/
let animal = new Animal('雪碧');
animal.sleep();
console.log(Animal.type);
Animal.eat()
class属性
public:公有(属性或方法在类内部或类外部或子类都可以访问到)
protect:保护(属性或方法只能在类内或子类使用)
private:私有(属性或方法只能造当前类内使用)
var siyou = Symbol('私有');
class Animal{
constructor(){
this.type = 'haha'
}
//获取方法getter
getType(){
return '$'+this.type
}
//设置方法setter
setType(newType){
if(newType == null) return;
this.type = newType;
}
[siyou](){}
}
let animal = new Animal();
console.log(animal.type)
animal.type = 'hehe'
class继承
class Animal{
static type = '动物';
constructor(Newname){
//super();报错在没有继承关系的类里面不能使用super
this.name = Newname;
}
static eat(){
console.log('饿了么');
}
sleep(){
console.log('睡觉');
}
ts(){}
}
//父类-子类, 超类-子类, 超类-派生类
class Tigger extends Animal {
constructor(Newname,Newage){
//super.sleep();报错,因为super方法还没有完成初始化
//super方法必须出现在constructor的第一行
super(Newname);//调用父类的构造方法,来初始化父类属性;
this.age = Newage;
//super.sleep()可以
}
/**
覆盖:子类方法和父类方法同名,会覆盖父类方法,在调用的时候父类方法不可见
当父类方法不能满足子类需求的时候,子类可以选择覆盖父类方法
覆盖是一种多态表现,多态是为了统一接口调用
**/
sleep(){
//super();报错;super方法只能出现在constructor里面,否则报错
//super对象用来调用父类中被子类覆盖的方法,出现在方法中
super.sleep();
this.ts();
console.log('睡不着')
}
ts(){
//super.sleep()
}
}
let tigger = new Tigger('雪碧',1)
//成员变量和成员方法
console.log(tigger.name);
tigger.sleep();
tigger.ts()
//静态变量和静态方法
console.log(Tigger.type)
Tigger.eat();
补充
class Chef {
title = '';
constructor(food) {
this.food = food;
this.dish = [];
} //getter
get menu() {
console.log('getter');
return this.dish;
} //setter
set menu(dish) {
console.log('setter');
this.dish.push(dish);
}
cook() {
console.log(this.food);
}
}
Chef.title = ''; //当class不支持static属性的时候可以采用这种方式
let zhangsan = new Chef();
console.log(zhangsan.title);
总结
- class的基本语法写法
- class中的constructor的作用:
- 初始化属性
- 初始化方法调用
- 方法的简写
- this的指向
- new一个对象的过程
- 成员和静态内的this指向
- 静态变量和静态方法的写法
- 继承的写法
- super的两种用法
- super方法
- super对象
class类中super有哪些用法?
super有两种用法,一个是super方法,一个super对象,super方法只能出现在constructor方法中,super对象一般出现在子类覆盖父类的方法中
静态和成员的区别
静态的变量或方法归类所有,全局独一份,成员的变量或方法归对象所有,每次实例化对象成员方法和成员变量就会得到一份拷贝,对于一些通用的属性或方法,可以考虑设置为静态
async…await
async…await
- async是修饰方法的
- await必须出现在async修饰的方法中,否则报错
- async修饰的方法内部默认返回一个promise对象,在async修饰的方法中return数据,数据会作为promise对象的resolve参数
- await等待的异步操作一般是promise操作,当promise的状态变为fulfilled的时候await不在等待,程序得以继续执行,等待过程中,程序处于中断暂定状态,await的等待结果是resolve函数的参数。
- await不等待reject的执行结果,如果要处理reject需要使用try…catch或者promise.catch
//async...await用法
//async...await用来等待promise的resolve执行结果,等待同步方法没有明显意义
function fn(){
//同步操作
console.log('同步');
return '1';
//异步操作
var p = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('456')
},1000)
})
return p ;//必须return 要返回promise对象,否则await不会等待
}
async function fun (){
//await不能单独使用,需要出现在由async修饰的方法中
console.log('123')
let rst = await fn();
/**
1.处理await的reject结果
try{
var rst = await fu();
} catch(error){
console.log(error)
}
2.处理await的reject结果
var rst = await fn().catch(err=>{
console.log(err)
})
**/
console.log('789')
return rst
}
fun().then(rst=>{
console.log(rst)
})
callback
const WEATHER = 'ajaxWeather.php';
const TEST = 'ajax.php';
const REGISTER = 'ajaxRegister.php';
const LOGIN = 'ajaxlog.php';
class Http{
constructor(){
this.baseUrl = 'https://www.bestqingshan.top/demo/'
}
common({url,type='GET',data={}}={}){
url = this.baseUrl + url;
var p = new Promise((resolve,reject)=>{
$.ajax({
type,
url,
data,
dataType:'json',
success:function(response){
resolve(response)
},
error:function(err){
reject(err)
}
})
})
return p;
}
async weather(callback){
await this.common({url:WEATHER})
}
async register(callback){
let rst = await this.common({url:REGISTER,type:'POST',data})
callback(rst)
}
login(data){
return this.common({
url:LOGIN,type:'POST',data
})
}
}
iterator迭代器,遍历器
iterator作用:统一数据结构(数组,对象,map,set,数组包对象,对象包数组)的遍历方式
在数据结构上部署iterator接口:所谓的部署接口表现形式为,给对对象或数组等集合增加iterator属性,属性的内容是一个根据iterator接口规范自行实现的办法
//示例一:说明iterator接口的书写规范
var it = makeIterator(['a','b']);
console.log(it.next());//{value:'a',done:false}
console.log(it.next());//{value:'b',done:false}
console.log(it.next());//{value:undefined,done:true}
//makeIterator的作用是创建一个遍历器方法
function makeIterator(array){
var nextIndex = 0;
retrun {
next:function(){
return nextIndex < array.length ? {value:array[nextIndex++],done:false} : {value:undefined,done:true}
}
}
}
//示例二:给对象部署iterator接口,iterator接口的默认属性是Symbol.iterator
//一、对象iterator接口遍历
const obj = {
[Symbol.iterator]:function(){
var count = 10;
var index = 0;
return {
next:function(){
//done:false和value:undefined都可以省略
if(index<count){
return {value:index++,done:false}
} else {
return {value:undefined,done:true}
}
}
}
}
}
var objNoIterator = {
title:'周五',
age:1,
}
for(item of obj){
console.log(item)
}
for(item of objIterator){
console.log(item)
}
二、数组iterator接口遍历
var names = ['马龙白兰度', '纪梵希', '奥黛丽赫本', '猫王', '玛丽莲梦露', '迈克杰克逊', '麦当娜'];
inames = names[Symbol.iterator]();
console.log(inames.next())
for (item of names){
console.log(item)
}
三、字符串iterator接口遍历
let str = 'helloworld';
1.iterator遍历
istr = str[Symbol.iterator]();
console.log(istr.next());
2.for...of遍历
for(item of str){
console.log(item)
}
iterator小结:iterator的目的是迭代器,遍历数据结构,提供了统一遍历数据结构的接口
Generator:生成器
generator和async…await的关系
async…await是基于promise的generator语法糖
状态机:什么是状态?所谓的状态就是变量内容,状态机的意思就是说可以管理或存储多个变量
generator函数的特征是function关键字和函数名之间有*,函数内部有yieid表达式
function* fnGenerator (){
var a = 'hello';
yieid a;
var b = 'wprld';
yieid b;
}
//generator方法调用后会返回一个遍历器对象,该对象可以使用next或for...of遍历
var fn = fnGenerator();
console.log(fn.next());
//generator函数内部没有yieid表达式的时候,此时调用f()内部的代码也不会执行,除非执行了next
iterator是遍历器,给数据结构提供统一的遍历接口(for…of)
for…of和forEach的区别?
for…of内部支持break,continue,return,forEack不行
for…of和for…in的区别?
for…in会把对象的原始属性都遍历出来,但是for…of没有这样的缺点
set和map
set和array是对应关系
map和object是对应关系
set集合里面不允许重复值
var arr = [1,23,33,223,44,55,2,1]
let arr1 = [...new Set([1,2,3,1,2,3])];
console.log(arr)
//判断空对象
if(JSON.stringify({})==='{}'){}
var obj = {
title:'雪碧',
age:500
};
console.log(Object.keys(obj))
console.log(Object.values(obj))
console.log(Object.entries(obj))
var map = new Map();
map.set(1,1);
map.set('1','1')
map.set(ture,true);
map.set([1,2,3],[1,2,3]);
map.set({title:'周五'},{title:'周五完了'})
console.log(map.get([1,2,3]))