ES6
ES6的开发环境搭建
现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法。Webpack是有自动编译转换能力的,除了Webpack自动编译,我们还可以用Babel来完成。这节课我们就使用Babel把ES6编译成ES5
新建目录
建工程目录之后创建两个文件夹:src和dist
- src:书写ES6代码的文件夹,写的js程序都放在这里。
- dist:利用Babel编译成的ES5代码的文件夹,在HTML页面需要引入的时这里的js文件。
编写index.html
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--注意这里js路径是dist编译成ES5的js文件路径-->
<script src="../dist/index.js"></script>
</head>
<body>
Hello Es6
</body>
</html>
编写index.js
在src目录下,新建index.js用ES6声明方式
let a=1;
console.log(a);
初始化项目
在cmd命令窗口初始化项目-y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件。
npm init -y
全局安装Babel-cli
npm install babel-cli -g
本地安装babel-preset-es2015 和 babel-cli
npm install babel-preset-es2015 babel-cli --save-dev
新建.babelrc
在根目录下新建.babelrc文件,并打开录入下面的代码
{
"presets":[
"es2015"
],
"plugins":[]
}
现在可以在终端输入转换命令可以发现dist目录下已经生成了ES5语法的js文件
babel src/index.js -o dist/index.js
简化转换命令
可以使用npm run build 直接利用webpack进行打包,在这里也希望利用这种方式完成转换。打开package.json文件,把文件修改成下面的样子。
{
"name": "es6test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "babel src/index.js -o dist/index.js"
}
修改好后,以后我们就可以使用 npm run build 来进行转换了。
新的声明方式
var 声明
var 在ES6里是全局变量
var a=2;
{
var a=3;
}
console.log(a); //打印出来是3
let局部声明
var a=2;
{
let a=3;
}
console.log(a);//打印出来是2
var 声明的循环
for(var i=0;i<10;i++){
console.log('循环体中:'+i);
}
console.log('循环体外:'+i);
你会发现循环体外的i变量被污染了,如果在外部再使用i时就会出现问题,这是开发者不想看到的。我们再利用let声明,就可以解决这个问题。
用let声明的循环
for(let i=0;i<10;i++){
console.log('循环体中:'+i);
}
console.log('循环体外:'+i);
你执行时会发现控制台报错了,找不到循环体外的i变量。通过两种声明的比较,可以明白let在防止程序数据污染上还是很有用处的。我们要努力去习惯用let声明,减少var声明去污染全局空间,在vue的使用中也要注意这点。
const声明常量
const a="aaa";
var a='bbb';
console.log(a);
在编译这段代码的过程中,你就会发现已经报错,无法编译了,原因就是我们const声明的变量是不可以改变的。
变量的解构赋值
数组的解构赋值
//ES5写法
let a=0;
let b=1;
let c=2;
//ES6写法
let [a,b,c]=[1,2,3];
console.log(a);
console.log(b);
console.log(c);
数组模式和赋值模式统一
等号左边和等号右边的形式要统一,如果不统一解构将失败。
let [a,[b,c],d]=[1,[2,3],4];
解构的默认值
let [foo = true] =[];
console.log(foo); //控制台打印出true
现在我们对默认值有所了解,需要注意的是undefined和null的区别。
let[a="aa"]=[undefined];
console.log(a); //控制台显示aa
let[a="aa"]=[null];
console.log(a); //控制台显示null
null相当于有值,但值为null。所以b并没有取默认值,而是解构成了null。
对象的解构赋值
let {name,sex}={name:'lm',sex:'男'}
console.log(name+sex);
圆括号的使用
如果在解构之前就定义了变量,这时候你再解构会出现问题。下面是错误的代码,编译会报错。
let name;
{name}={name:'lm'}
console.log(name);
要解决报错,使程序正常,我们这时候只要在解构的语句外边加一个圆括号就可以了。
let name;
({name}={name:'lm'})
console.log(name);
字符串解构
const [a,b,c,d,e]="guosh";
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
扩展运算符和rest运算符
对象扩展运算符(…)
当编写一个方法时,我们允许它传入的参数是不确定的。这时候可以使用对象扩展运算符来作参数,看一个简单的列子
function sj(...arg){
console.log(arg[0]);
console.log(arg[1]);
console.log(arg[2]);
console.log(arg[3]);
}
sj(1,2,3,)
这时我们看到控制台输出了 1,2,3,undefined,这说明是可以传入多个值,并且就算方法中引用多了也不会报错
扩展运算符的用处
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);
console.log(arr1) //结果 0,1,2,3,4,5
rest运算符
对象扩展运算符,rest运算符并它们有很多相似之处,不用特意去区分。它也用…(三个点)来表示。
function gsh(first,...arg){
console.log("first="+first); //结果是0
console.log("arg="+arg);//结果是1,2,3,4,5,6,7
}
gsh(0,1,2,3,4,5,6,7)
字符串模板
字符串模板使用
字符串拼接
//ES5语法
let a="姓名"
let c="我的"+a+"LM";
console.log(c);
//ES6语法
let a="姓名"
let c=`我的${a}LM`;
console.log(c);
对html标签支持
let a="姓名"
let c=`<b>我的${a}LM<b>`;
console.log(c);
字符串查找
includes判断是否存在
let a="姓名"
let c="我的姓名";
document.write(c.includes(a)); //true
startsWith判断开头是否存在
let a="姓名"
let c="我的姓名";
document.write(c.startsWith(a)); //false
endsWith判断结尾是否存在
let a="姓名"
let c="我的姓名";
document.write(c.endsWith(a)); //true
赋值字符串
document.write('Guo|'.repeat(3)); //会打印三遍Guo|
ES6数字操作
二进制八进制声明
//二进制开始是0第二个是B开头
let a=0B010101;
console.log(a); //打印21
//八进制开始是0第二个是O开头
let b=0O666
console.log(b)//打印438
数字验证
Number.isFinite( xx )数字验证
可以使用Number.isFinite( )来进行数字验证,只要是数字,不论是浮点型还是整形都会返回true,其他时候会返回false。
let a=1;
console.log(Number.isFinite(a))//true
console.log(Number.isFinite(''呵呵))//false
NaN验证
console.log(Number.isNaN(NaN)); //true
整数验证
let a=123.1;
console.log(Number.isInteger(a)); //false
整数转换Number.parseInt(xxx)和浮点型转换Number.parseFloat(xxx)
let a='9.18';
console.log(Number.parseInt(a));
console.log(Number.parseFloat(a));
整数安全范围
最大安全整数
console.log(Number.MAX_SAFE_INTEGER);
最小安全整数
console.log(Number.MAX_SAFE_INTEGER);
安全整数判断isSafeInteger( )
let a= Math.pow(2,53)-1;
console.log(Number.isSafeInteger(a));//false
ES6中的数组
JSON数组格式转换
//0,1,2,是下标 length是长度
let json={
"0":"AA",
"1":"BB",
"2":"CC",
length:3
}
let arr=Array.from(json);
console.log(arr);
这就是一个标准的JSON数组格式,跟普通的JSON对比是在最后多了一个length属性。只要是这种特殊的json格式都可以轻松使用ES6的语法转变成数组
Array.of()方法
let a=Array.of('A','B','C');
console.log(a);
它负责把一堆文本或者变量转换成数组
find( )实例方法:
- value:表示当前查找的值。
- index:表示当前查找的数组索引。
- arr:表示当前数组。
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.find(function (value, index, arr) {
return value > 5;
}));
控制台输出了6,说明找到了符合条件的值,并进行返回了,如果找不到会显示undefined。
fill()实例方法
fill()也是一个实例方法,它的作用是把数组进行填充,它接收三个参数,第一个参数是填充的变量,第二个是开始填充的下标位置,第三个是填充到的具体位置。
let arr=[1,2,3,4,5,6,7,8,9];
arr.fill('a',4,9);
console.log(arr); //结果 [1, 2, 3, 4, "a", "a", "a", "a", "a"]
数组的遍历
for…of循环
输出值
let arr=['AA','BB','CC'];
for (let item of arr) {
console.log(item)
}
输出数组索引
let arr=['AA','BB','CC'];
for (let item of arr.keys()) {
console.log(item)
}
输出索引和值
let arr=['AA','BB','CC'];
for (let [index,value] of arr.entries()) {
console.log(index+value)
}
entries( )实例方法
entries()实例方式生成的是Iterator形式的数组,那这种形式的好处就是可以让我们在需要时用next()手动跳转到下一个值。我们来看下面的代码:
let arr=['AA','BB','CC'];
let list=arr.entries();
console(list.next().value);
console(list.next().value);
console(list.next().value);
ES6中的箭头函数和扩展
ES5写法
function add(a,b){
return a+b;
}
console.log(add(2,3));
ES6写法
var add=(a,b)=>a+b;
console.log(add(1,2));
在箭头函数中,方法体内如果是两句话,那就需要在方法体外边加上{}括号。例如下边的代码就必须使用{}.
var add=(a,b)=>{
console.log("AAA")
return a+b;
};
console.log(add(1,2));
ES6中的函数和数组补漏
对象的函数解构
let json={
name:'xm',
age:'18'
}
function fun({name,age}){
console.log(name);
console.log(age);
}
fun(json);
数组的函数解构
let arr = ['a','b','c'];
function fun(a,b,c){
console.log(a,b,c);
}
fun(...arr);
in是用法
对象判断
let obj={
name:'xm',
age:'18'
}
console.log('name' in obj) //true
数组判断
let arr=[,,]
console.log(0 in arr) //false
let arr1=['a','b']
console.log(0 in arr1) //true
注意:这里的0指的是数组下标位置是否为空
数组的遍历方法
forEach
let arr=['aa',,'cc']
arr.forEach((value,index) => {
console.log(value,index) //结果aa 0 aa 2
});
forEach循环的特点是会自动省略为空的数组元素,相当于直接给我们筛空了。
filter
let arr=['aa',,'cc']
arr.filter(x => {
console.log(x)
});
some
let arr=['aa',,'cc']
arr.some(x => {
console.log(x)
});
map
let arr=['aa','bb','cc']
console.log(arr.map(x=>'web')) // 'web' 'web' 'web'
map在这里起到一个替换的作用
数组转换字符串
toString()方法
let arr=['aa','bb','cc']
console.log(arr.toString())
join方法
let arr=['aa','bb','cc']
console.log(arr.join('|')) //自定义分隔符 aa|bb|cc
ES6中对象
对象赋值
let name="XM";
let age="18";
let obj={name,age};
console.log(obj) //{name: "XM", age: "18"}
对象Key值构建
有时候我们会在后台取出key值,而不是我们前台定义好的,这时候我们如何构建我们的key值那。比如我们在后台取了一个key值,然后可以用[ ] 的形式,进行对象的构建。
let key="name"
let obj={
[key]:'XM'
}
console.log(obj); //{name: "XM"}
Object.is( ) 对象比较
let a={name:'XM'};
let b={name:'XM'};
console.log(a.name === b.name);
//ES6比较方法
let a={name:'XM'};
let b={name:'XM'};
console.log(Object.is(a.name,b.name));
区分=== 和 is方法的区别是什么,看下面的代码输出结果。
console.log(+0 === -0); //true
console.log(NaN === NaN ); //false
console.log(Object.is(+0,-0)); //false
console.log(Object.is(NaN,NaN)); //true
===为同值相等,is()为严格相等
Object.assign( )合并对象
let a={name:'XM'};
let b={age:'18',sex:'男'};
let c=Object.assign(a,b);
console.log(c); //{name: "XM", age: "18", sex: "男"}
Symbol在对象中的作用
Symbol的声明
var a=Symbol("ES6");
console.log(a);
console.log(a.toString());
Symbol再对象中的应用
var xm=Symbol();
var obj={
[xm]:'ES6'
}
console.log(obj[xm]); //ES6
Symbol对象元素的保护作用
没有进行保护的写法:
var obj={name:'ES6',sex:'男',age:'18'}
for(let item in obj){
console.log(obj[item]); //ES6 男 18
}
现在我不想别人知道我的年龄,这时候我就可以使用Symbol来进行循环保护。
var obj={name:'ES6',sex:'男'}
var age=Symbol();
obj[age]='18';
for(let item in obj){
console.log(obj[item]); //ES6 男
}
Set和WeakSet数据结构
Set的声明
Set和Array 的区别是Set不允许内部有重复的值,如果有只显示一个,相当于去重。虽然Set很像数组,但是他不是数组。
let setArr=new Set(['aa','bb','cc','aa']);
console.log(setArr); //aa,bb,cc
Set值的增删查
追加add
let setArr=new Set(['aa','bb','cc','aa']);
setArr.add('dd');
console.log(setArr)//aa,bb,cc,dd
删除delete
let setArr=new Set(['aa','bb','cc','aa']);
setArr.delete('aa');
console.log(setArr)//bb,cc
查找has
let setArr=new Set(['aa','bb','cc','aa']);
console.log(setArr.has('aa'));//true
清空clear
let setArr=new Set(['aa','bb','cc','aa']);
setArr.clear();
console.log(setArr);
Set循环
let setArr=new Set(['aa','bb','cc','aa']);
for (let item of setArr) {
console.log(item);
}
WeakSet的声明
let weakObj=new WeakSet();
let obj={
name:"XM",
age:"18"
};
weakObj.add(obj);
console.log(weakObj);
这里需要注意的是,如果你直接在new 的时候就放入值,将报错,只能通过add()插入
let weakObj=new WeakSet();
let obj={
name:"XM",
age:"18"
};
let obj1=obj;
weakObj.add(obj);
weakObj.add(obj1);
console.log(weakObj);
内存空间相同只会插入一个对象
map数据结构
map声明
let obj={
name:"XM",
age:"18"
};
let map=new Map();
map.set("a",obj);
map.set("b",1);
console.log(map);
取值get
console.log(map.get("b"));
删除delete
map.delete("b")
根据key删除值
size属性
console.log(map.size);
查找是否存在has
console.log(map.has('a'))//true
清除所有元素clear
map.clear()
用Proxy进行预处理
get属性与set属性
let pro =new Proxy({
add: function(val){
return val+10
},
name: 'gg'
},{
//get属性是在你得到某对象属性值时预处理的方法 target:目标值。key:目标的Key值。
get: function(target,key,property){
return target[key];
},
//set属性是值你要改变Proxy属性值时,进行的预先处理的方法 target:目标值。key:目标的Key值。value:要改变的值。receiver:改变前的原始值。
set: function(target,key,value,receiver){
return target[key] = value;
}
})
console.log(pro); //触发get
pro.name='aaa'; //触发set
console.log(pro);
apply的使用
apply的作用是调用内部的方法,它使用在方法体是一个匿名函数时。
let target = function () {
return 'Hello';
};
var handler = {
apply(target, ctx, args) {
console.log('do apply');
return Reflect.apply(...arguments);
}
}
var pro = new Proxy(target, handler);
console.log(pro());
promise对象的使用
promise执行多步操作非常好用
let state=1;
function step1(resolve,reject){
console.log('1.开始-第一步');
if(state==1){
resolve('第一步--完成');
}else{
reject('第一步--出错');
}
}
function step2(resolve,reject){
console.log('2.开始-第二步');
if(state==1){
resolve('第二步--完成');
}else{
reject('第二步--出错');
}
}
function step3(resolve,reject){
console.log('3.开始-第三步');
if(state==1){
resolve('第三步--完成');
}else{
reject('第三步-出错');
}
}
new Promise(step1).then(function(val){
console.log(val);
return new Promise(step2);
}).then(function(val){
console.log(val);
return new Promise(step3);
}).then(function(val){
console.log(val);
return val;
});
class类的使用
类的声明
class Coder{
//类中的方法
name(val){
console.log(val);
}
}
let guo=new Coder();
guo.name('AA')
类的多方法声明
class Coder{
//类中的方法
name(val){
console.log(val);
return val;
}
skill(val){
console.log(this.name("aa")+":"+"skill:"+val)
}
}
let guo=new Coder();
guo.skill('bb');
类的传参
class Coder{
constructor(a,b){
this.a=a;
this.b=b;
}
add(){
return this.a+this.b;
}
}
let guo=new Coder(1,2);
console.log(guo.add())
我们用constructor来约定了传递参数,然后用作了一个add方法,把参数相加
类的继承
class Htmlel extends Coder{
}
let guo=new Htmlel();
模块化操作
- export :负责进行模块化,也是模块的输出
- import : 负责把模块引,也是模块的引入操作
export的用法
我们新建一个temp.js文件,然后在文件中输出一个模块变量
export var a='guo';
然后可以在index.js中以import的形式引入
import {a} from './temp.js'
console.log(a);
多变量的输出
var a='guo';
var b='guoa';
var c='guob';
export {a,b,c}
函数的模块化输出
export function add(a,b){
return a+b;
}
as的用法
有些时候我们并不想暴露模块里边的变量名称,而给模块起一个更语义话的名称,这时候我们就可以使用as来操作。
var a='guo';
var b='guoa';
var c='guob';
export {
a as x,
b as c,
c as v
}
export default的使用
加上default相当是一个默认的入口。在一个文件里export default只能有一个。我们来对比一下export和export default的区别
export
export var a ='guo';
对应导入方式
import {a} form './temp';
export defalut
export var a ='guo';
对应导入方式
import str from './temp';