var:它是variable的简写,可以理解成变量的意思。
let:let是局部变量声明,防止数据污染,let声明只在区块内起作用,外部是不可以调用的。
const:它在英文中也是常量的意思,在ES6用来声明常量的,常量可以简单理解为不变的量,从声明开始,这个变量始终不变。
变量的解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
-
数组的解构赋值
按照位置的对象关系对变量赋值,数组模式和赋值模式统一
理解为等号左边和等号右边的形式要统一,如果不统一解构将失败。
let a=0;
let b=1;
let c=2;
⬇️⬇️⬇️⬇️⬇️⬇️
let [a,b,c]=[1,2,3];
let [a,[b,c],d]=[1,[2,3],4];
-
解构的默认值
解构赋值是允许你使用默认值的
注意的是undefined和null的区别。
let [a,b="你好"]=['xjl']
console.log(a+b);
//控制台显示“xjl你好”
let [a,b="你好"]=['xjl',undefined]
console.log(a+b);
//控制台显示“xjl你好” undefined相当于什么都没有,b是默认值。
let [a,b="你好"]=['xjl',null]
console.log(a+b);
//控制台显示“xjlnull” null相当于有值,但值为null。所以b并没有取默认值,而是解构成了null。
-
对象的解构赋值
解构不仅可以用于数组,还可以用于对象。
let {name,sex} = {name:'xjl',sex:'男'};
console.log(name+sex); //控制台打印出了“xjl男”
注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
-
圆括号的使用
如果在解构之前就定义了变量,这时候你再解构会出现问题。
在解构的语句外边加一个圆括号就可以解决
let a;
({a} ={a:'1'});
console.log(a); //控制台输出1
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
不能使用圆括号的情况
(1)变量声明语句
(2)函数参数也属于变量声明,因此不能带有圆括号。
(3)赋值语句的模式
-
字符串解构
字符串也可以解构,此时字符串被转换成了一个类似数组的对象。
let [a,b,c]="xjl";
console.log(a);
console.log(b);
console.log(c);
-
对象的函数解构
let xjl = {
sex:'男',
age:18
}
function fun({sex,age}){
console.log(sex,age); // 男 18
}
fun(xjl);
-
数组的函数解构
let arr = ['xjl','男','18'];
function fun(a,b,c){
console.log(a,b,c); // xjl 男 18
}
fun(...arr);
扩展运算符和rest运算符
扩展运算符和rest运算符,它们都是(…)三个点,解决参数和对象数组未知情况下的编程
-
对象扩展运算符
当编写一个方法时,我们允许它传入的参数是不确定的。这时候可以使用对象扩展运算符来作参数
例1
function fn(...val){
console.log(val[0]);
console.log(val[1]);
console.log(val[2]);
console.log(val[3]);
}
fn(1,2,3);
//控制台输出:1,2,3,undefined,这说明是可以传入多个值,并且就算方法中引用多了也不会报错。
例2
let arr1=['x','j','l'];
let arr2=arr1;
console.log(arr2); //["x", "j", "l"]
arr2.push('nihao');
console.log(arr1);//["x", "j", "l", "nihao"]
//发现arr1的值也改变了,因为我们这是对内存堆栈的引用,而不是真正的赋值。
例3 利用对象扩展运算符简单的解决例二问题
let arr1=['x','j','l'];
let arr2=[...arr1];
arr2.push('nihao');
console.log(arr2); //["x", "j", "l", "nihao"]
console.log(arr1);//["x", "j", "l"]
-
rest运算符 =剩余部分
for…of的循环可以避免我们开拓内存空间,增加代码运行效率
function arr(first,...arg){
for(let val of arg){
console.log(val);// 输出 1,2,3
}
}
arr(0,1,2,3,);
字符串模版
-
字符串拼接
字符串模版不再使用‘xxx’这样的单引号 变用反引号 【`】
引用变量就需要用 ${xxx}
里边支持html标签,运算表达式,函数
换行和空格都是会被保留的
let a=1;
let b=2;
let name='xjl';
function f(){
return "have fun!";
}
let text= `你好我是${name}${a+b},${f()}`;
console.log(text);// 输出 你好我是xjl3,have fun!
-
字符串查找
支持中文
includes():返回布尔值,判断是否找到参数字符串。
startsWith():返回布尔值,判断参数字符串是否在原字符串的头部。
endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部。
注意:这三个方法只返回布尔值,如果需要知道子串的位置,还是得用 indexOf 和 lastIndexOf 。starts和ends 后边都要加s
repeat(num) : 返回新的字符串,表示将字符串重复指定次数返回。
let text ='海阔凭鱼跃,天高任鸟飞。'
console.log(text.includes('鸟')) //true
console.log(text.startsWith('海')) //true
console.log(text.endsWith('飞'))//false 结尾为【。】
console.log(text.repeat(2))//海阔凭鱼跃,天高任鸟飞海阔凭鱼跃。天高任鸟飞
-
字符串补全
padStart:返回新的字符串,表示用参数字符串从头部(左侧)补全原字符串。
padEnd:返回新的字符串,表示用参数字符串从尾部(右侧)补全原字符串。
以上两个方法接受两个参数,
第一个参数是指定生成的字符串的最小长度,
第二个参数是用来补全的字符串。
console.log("h".padStart(5,"o"));
// "ooooh"
console.log("h".padEnd(5,"o"));
// "hoooo"
console.log("h".padStart(5));
// " h" 如果没有指定第二个参数,默认用空格填充。
console.log("hello".padStart(5,"A"));
// "hello" 如果指定的长度小于或者等于原字符串的长度,则返回原字符串
console.log("hello".padEnd(10,",world!"));
// "hello,worl" 如果原字符串加上补全字符串长度大于指定长度,则截去超出位数的补全字符串
数组
-
Array.from() JSON数组格式转换数组
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
//带有length属性这种特殊的json格式都可以轻松使用ES6的语法转变成数组。
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
-
Array.of() 负责把一堆文本或者变量转换成数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3,'aa') // [3,'aa']
Array.of(3).length // 1
-
数组实例的 find() 和 findIndex()
数组实例的find()
方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
/*
value:表示当前查找的值。
index:表示当前查找的数组索引。
arr:表示当前数组。
*/
数组实例的findIndex()
方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
-
fill( )实例方法
把数组进行填充,它接收三个参数,第一个参数是填充的变量,第二个是开始填充的位置,第三个是结束填充的位置。
注意,如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c'] fill方法从 1 号位开始,向原数组填充 7,到 2 号位之前结束。
-
for…of循环
entries(),keys()和values()——用于遍历数组。
它们都返回一个遍历器对象,唯一的区别是
keys()是对键名的遍历、
values()是对键值的遍历,
entries()是对键值对的遍历。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
箭头函数
let 方法名 = 参数 => 代码块;
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
var sum = (num1, num2) => { return num1 + num2; }
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
如果箭头函数只有一行语句,且不需要返回值,可以采用下面的写法,就不用写大括号了。
let fn = () => void doesNotReturn();
箭头函数可以与变量解构结合使用。
const full = ({ first, last }) => first + ' ' + last;
// 等同于
function full(person) {
return person.first + ' ' + person.last;
}
箭头函数使得表达更加简洁。
const isEven = n => n % 2 === 0;
const square = n => n * n;
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。
in的用法
in是用来判断对象或者数组中是否存在某个值的。
-
对象判断
let xjl={
sex:'男',
age:'18'
}
console.log('age' in xjl); //true
-
数组判断
ES5判断的弊端,以前会使用length属性进行判断,为0表示没有数组元素。但是这并不准确,或者说真实开发中有弊端
// ES5判断
let arr=[,,,,,];
console.log(arr.length); //5
//ES6判断
let arr=[,,,,,];
console.log(0 in arr); //false
let arr1=['男','18'];
console.log(0 in arr1); // true
注意:这里的0指的是数组下标位置是否为空。
数组遍历
-
forEach
forEach循环的特点是会自动省略为空的数组元素,相当于直接给我们筛空了。当然有时候也会给我们帮倒忙。
let arr=['男','18'];
arr.forEach((val,index)=>console.log(index,val));
// 0 "男" 1 "18"
-
filter & some
let arr=['男','18'];
arr.filter(x=>console.log(x)); //男 18
arr.some(x=>console.log(x)); //男 18
-
map
map在这里起到一个替换的作用
let arr=['男','18'];
console.log(arr.map(x=>'aa')); //["aa", "aa"]
数组转换字符串
-
join()方法
数组元素中间,加了一些指定符号进行间隔,开发中很有用处。
let arr=['男','18'];
console.log(arr.join('|')); //男|18
-
toString()方法
转换时只是是用逗号隔开了。
let arr=['男','18'];
console.log(arr.toString()); //男,18
ES6 对象
-
对象赋值
ES6允许把声明的变量直接赋值给对象
let name="xjl";
let age= '18';
var obj= {name,age};
console.log(obj); //Object {name: "xjl", age: "18"}
-
对象 key值构建
有时候我们会在后台取出key值,而不是我们前台定义好的,这时候我们如何构建我们的key值那。比如我们在后台取了一个key值,然后可以用[ ] 的形式,进行对象的构建。
let key='name';
var obj={
[key]:'xjl'
}
console.log(obj.name); //xjl
-
自定义对象方法
对象方法就是把对象中的属性,用匿名函数的形式编程方法。
const obj = {
add(a,b) {
return a+b;
}
};
console.log(obj.add(1,2)); //3
// 等同于
const obj = {
add: function(a,b) {
return a+b;
}
};
-
Object.is( ) 对象比较
=== 和 is方法的区别:===为同值相等,is()为严格相等。
var obj1 = {name:'xjl'};
var obj2 = {name:'xjl'};
console.log(obj1.name === obj2.name);//true
console.log(Object.is(obj1.name,obj2.name)); //true
console.log(+0 === -0); //true
console.log(NaN === NaN ); //false
console.log(Object.is(+0,-0)); //false
console.log(Object.is(NaN,NaN)); //true
-
Object.assign( )合并对象
let a={a:'xjl'};
let b={b:'男'};
let c={c:'18'};
let d=Object.assign(a,b,c)
console.log(d); // {a: "xjl", b: "男", c: "18"}
ES6 Symbol类型
-
Symbol声明
let g = Symbol('xjl');
console.log(g);
console.log(g.toString());
// 这时候我们仔细看控制台是有区别的,没有toString的是红字,toString的是黑字。
-
Symbol在对象中的应用
Symbol构建对象的Key,并调用和赋值。
var xjl = Symbol();
var obj={
[xjl]:'徐佳乐'
}
console.log(obj[xjl]);
obj[xjl]='web';
console.log(obj[xjl]);
-
Symbol对象元素的保护作用
在对象中有很多值,但是循环输出时,并不希望全部输出,那我们就可以使用Symbol进行保护。
let obj={name:'xjl',sex:'男',age:18};
for (let item in obj){
console.log(obj[item]) // xjl 男 18
}
//现在我不想别人知道我的年龄,这时候我就可以使用Symbol来进行循环保护。
let obj={name:'xjl',sex:'男'};
let age=Symbol();
obj[age]=18
for (let item in obj){
console.log(obj[item]) // xjl 男
}
console.log(obj) // {name: "xjl", sex: "男", Symbol(): 18}
Set和WeakSet数据结构
Set数据结构,注意这里不是数据类型,而是数据结构。它是ES6中新的东西,并且很有用处。Set的数据结构是以数组的形式构建的。
-
Set 声明
Set和Array 的区别是Set不允许内部有重复的值,如果有只显示一个,
相当于去重。虽然Set很像数组,但是他不是数组。
let setArr = new Set(['xjl','男','18']);
console.log(setArr);//Set {"xjl", "男", "18"}
-
Set值的增删查清空
add,delete,has
用has进行值的查找,返回的是true或者false。
let setArr = new Set(['xjl','男','18']);
console.log(setArr);//Set {"xjl", "男", "18"}
setArr.add('好孩子')
console.log(setArr);//Set {"xjl", "男", "18","好孩子"}
setArr.delete('好孩子')
console.log(setArr);//Set {"xjl", "男", "18"}
console.log(setArr.has('男'));// true
setArr.clear()
console.log(setArr);//Set {}
-
循环 & size属性
size属性可以获得Set值的数量。
let setArr = new Set(['xjl','男','18']);
// forEach & for..of 循环
setArr.forEach((value)=>console.log(value));
// xjl 男 18
for (let item of setArr){
console.log(item); // xjl 男 18
}
console.log(setArr.size); // 3
-
WeakSet的声明
这里需要注意的是,如果你直接在new 的时候就放入值,将报错
let weakObj=new WeakSet();
let obj={name:'xjl',sex:'男',age:'18'}
weakObj.add(obj);
console.log(weakObj);
// WeakSet {{…}}
map数据结构
map是一种灵活,简单的适合一对一查找的数据结构;我们知道的数据结构,已经有了json和set。
map特点:key => value
一种特殊的键值对,key可以设置成数组,值也可以设置成字符串,让它不规律对应起来。当然也可key字符串,value是对象。
let json = {
name:'xjl',
age:18
}
var map=new Map();
map.set(json,'iam');
console.log(map);
// {{…} => "iam"} {Object => "iam"} key: {name: "xjl", age: 18} value: "iam"
map.set('iam',json);
console.log(map);
// {"iam" => {…}} {"iam" => Object} key: "iam"
value: {name: "xjl", age: 18
map的增删查 同 set ,取json对应的值 map.get()
用Proxy进行预处理
什么是钩子函数。当我们在操作一个对象或者方法时会有几种动作,比如:在运行函数前初始化一些数据,在改变对象值后做一些善后处理。这些都算钩子函数,Proxy的存在就可以让我们给函数加上这样的钩子函数,你也可以理解为在执行方法前预处理一些代码。你可以简单的理解为他是函数或者对象的生命周期。
Proxy的应用可以使函数更加强大,业务逻辑更加清楚,而且在编写自己的框架或者通用组件时非常好用。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
// 回顾一下定义对象的方法。
let obj = {
add(val) {
return val+10;
},
name:'xjl'
};
let target = {name:'xjl'}
console.log(obj.add(10)); //20
console.log(obj.name); //xjl
console.log(target.name); //xjl
-
声明Proxy
需要注意的是这里是两个花括号,
第一个花括号就相当于我们对象方法的主体,
第二个花括号就是Proxy代理处理区域,相当于我们写钩子函数的地方。
new Proxy({},{});
let target = {name: 'xjl'}
let handler = {
get(target, propKey, receiver) {
return target[propKey]
},
set(target, propKey, value, receiver) {
return target[propKey] = value;
}
}
let pro = new Proxy(target, handler)
console.log(pro.name) //xjl
pro.name = '徐乐乐';
console.log(pro.name); // 徐乐乐
get(target, propKey, receiver):拦截对象属性的读取;
set(target, propKey, value, receiver):拦截对象属性的设置,比如pro.name='徐乐乐';
target:目标对象。
propKey:目标对象的Key值 属性名。
value:要改变的对象属性值。
receiver:改变前的原始值。 (可忽略)
promise对象的使用
ES6中的promise的出现给我们很好的解决了回调地狱的问题
promise执行多步操作非常好用,那我们就来模仿一个多步操作的过程,那就以吃饭为例吧。要想在家吃顿饭,是要经过三个步骤的。
1.洗菜做饭。
2.坐下来吃饭。
3.收拾桌子洗碗。
这个过程是有一定的顺序的,你必须保证上一步完成,才能顺利进行下一步。
let state = 1;//定义状态码
/*三个 动作方法*/
const step1 = (resolve, reject) => {
console.log('1.开始-洗菜做饭');
if (state == 1) {
return resolve('洗菜做饭--完成');
} else {
return reject('洗菜做饭--出错');
}
}
const step2 = (resolve, reject) => {
console.log('2.开始-坐下来吃饭');
if (state == 1) {
return resolve('坐下来吃饭--完成');
} else {
return reject('坐下来吃饭--出错');
}
}
const step3 = (resolve, reject) => {
console.log('3.开始-收拾桌子洗完');
if (state == 1) {
return resolve('收拾桌子洗完--完成');
} else {
return reject('收拾桌子洗完--出错');
}
}
new Promise(step1).then((value) => {
console.log(value);
return new Promise(step2);
}).then(
(value) => {
console.log(value);
return new Promise(step3);
}
).then(
(value) => {
console.log(value);
return value;
}
)
/*
1.开始-洗菜做饭
洗菜做饭--完成
2.开始-坐下来吃饭
坐下来吃饭--完成
3.开始-收拾桌子洗完
收拾桌子洗完--完成*/
class 类的使用
ES5中经常使用方法或者对象去模拟类的使用,虽然可以实现功能,但是代码并不优雅,ES6为我们提供了类的使用。需要注意的是我们在写类的时候和ES5中的对象和构造函数要区分开来,不要学混了。
class Boy {
age = (value) => {
console.log(value)
return value;
}
name = (value) => console.log(` ${value} 今年 ${this.age('18')}了`)
constructor(a, b) {
this.a = a;
this.b = b;
}
add = () => this.a + this.b
}
let xjl = new Boy(10, 20); // 用constructor来约定了传递参数,实例化类的时候传进参数
xjl.name('徐乐乐') // 18=name方法里调用了age方法打印得 徐乐乐 今年 18了=name方法得出
console.log(xjl.add()) //30
/*声明一个Girl的新类并继承Boy类,Girl新类里边为空,
这时候我们实例化新类,并调用里边的name方法。结果也是可以调用到的。*/
class Girl extends Boy {
}
let ygg = new Girl;
ygg.name('于乖乖')
两个方法中间不用写逗号
用this调用类里面的其他方法,这里的this指类本身,还有要注意return 的用法
在类的参数传递中我们用constructor( )约定进行传参。传递参数后可以直接使用this.xxx进行调用。
class Girl extends Boy
关键词 extends
模块化操作 export & export defalut
export :负责进行模块化,也是模块的输出。
import : 负责把模块引,也是模块的引入操作。
-
export 用法
export可以让我们把变量,函数,对象进行模块话,提供外部调用接口,让外部进行引用。先来看个最简单的例子,把一个变量模块化。我们新建一个a.js文件,然后在文件中输出一个模块变量或者多个。
export let name = 'xjl'; // 单个变量输出
let age = '18'
let sex = '男';
export {age, sex} // 多变量的输出 包装成对象
//函数的模块化输出
export function add(a, b) {
return a + b;
}
然后可以在b.js中以import的形式引入。
必须用{},必须知道输出文件里的模块名
import {name,age,sex,add} from './a;
console.log(name) // xjl
console.log(age) //18
console.log(sex)// 男
console.log(add(1, 2)) //3
-
export defalut 用法
加上default相当是一个默认的入口。在一个文件里export default只能有一个
export default let name='xjl';
对应的引入方式
不需要{} 名字自定义
import xxx from './a;