ECMAScript6的特点
ES6即ES2015增添了许多必要的特性,例如模块和类,块级作用域,常量与变量…还有很多便利的功能如:箭头的功能和简单的字符串拼接等。其实ES6的某些”新”的特点并不是真的新,只是试图简化语法,这样就无需使用老式的方法编写代码,让我们编程更容易。
浏览器的支持程度 http://kangax.github.io/compat-table/es6/,可以通过Babel转码器把ES6写的代码转成ES5的,就不用担心运行环境是否支持。
编写注意:
chrome下使用ES6为保证可以正常使用大部分语法,需要使用严格模式,即在js开始部分加上’use strict’;
在firefox下使用ES6为保证可以正常使用大部分语法,需要知道测试版本,即在script标签的type属性中加上“application/javascript;version=1.7”属性值。
1.let 声明变量的关键字
(1).在相同的作用域内,let不能重复声明一个变量(不同的作用域内除外)
(2).let声明的变量不会被预解析
(3).暂时性死区,变量在let声明前都不能访问,为了防止先调用后声明这个现象
(4).let声明的变量拥有块级作用域,块级作用域指的是一个大括号就是一个作用域,以后就不要写自执行函数了。
'use strict’
//es5:
console.log(a); //undefined
var a=12;
console.log(a); //12
//es6:
console.log(b); //报错 不能提前使用
let b=20;
let b=30; //报错 不能重复声明一个变量
console.log(b);
//例:给一组li添加点击事件弹出其的索引值
'use strict’
//es5实现:
var lis=document.querySelectorAll("li");
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick=function(){
alert(i);
}
})(i);
}
//ES6实现:
for(let i=0;i<lis.length;i++){
lis[i].onclick=function(){
alert(i);
}
}
2.常量const
const:声明一个常量
(1).声明一个常量再修改会报错;
(2).只声明不赋值会报错;
(3).必须先声明再使用,不会被提前解析;
(4).不能重复声明;
注意:对象中的属性是可以修改的。
const str=‘David';
str=12; //报错 声明后不能再修改
const b; //报错 没有赋值
console.log(c); //报错 没声明就用了
const c=20;
const c='David'; //报错 重复声明了
//声明一个对象后,可以对它里面的属性进行修改
const obj={
name:'David'
};
obj.name='小王';
console.log(obj);
3.解构赋值
按照一定模式,从数组或者对象中把数据拿出来,对变量进行赋值
(1).数组解构赋值
等号左边和右边都必须是数组,数组的解构赋值要一一对应,否则结果为undefined
(2).对象解构赋值
等号左边和右边都必须是对象,名字(key)要一一对应,顺序不需要对应,否则结果为undefined
//数组解构赋值
var [a,b,c]=[1,2,3];
console.log(a,b,c);
//可以用来调换两个值
var n1=10;
var n2=15;
var [n1,n2]=[n2,n1];
console.log(n1,n2);
//也可以用来取函数的返回值
function fn(){
return ['red','green','blue'];
}
var [d,e,f]=fn();
console.log(e); //green
//对象解构赋值
var obj={
name:'David',
QQ:3569853,
language:['css','html','js'],
work:function(){
console.log('js');
}
};
var {name,work,QQ,age}=obj;
console.log(name,work,QQ,age);
4.字符串的扩展方法
(1). includes() 字符串是否包含某个字符,参数为一个字符,
(2). startsWith() 字符串的开始位置的字符是否是传入的参数,参数是一个字符串;
(3). endsWith() 字符串的结束位置的字符是否是传入的参数,参数是一个字符串;
(以上的几个方法返一个boolean值)
(4). repeat(num)复制字符串,参数为数字一定要为正数,表示复制次数;
var str='David';
console.log(str.includes('i')); //true
console.log(str.includes('b')); //false
console.log(str.startsWith('k')); //true
console.log(str.endsWith('n')); //true
console.log(str.repeat(2)); //DavidDavid
(5).模板字符串
模板字符串:字符串的拼接方式,用反撇号字符 ` 代替普通字符串的引号 ’ 或 ” 。
1.字符串需要用一对反引号包起来,它可以定义多行字符串,只用一对反引号
2.要拼进去的数据需要放在${}里面
3.大括号里还可以进行运算
4.大括号里还可以调用函数
var obj={
title:'星期一',
content:'今天要上班'
};
function fn(){
return '我爱编程,编程让我快乐';
}
var text=document.getElementById('text');
//es5拼接方法
text.innerHTML='<h1>'+obj.title+'</h1><p>'+obj.content+fn()+'</p>';
//es6拼接方法
text.innerHTML=`<h1>${obj.title}</h1><p>${obj.content+fn()}</p>`;
5.Math对象的扩展方法
(1).Math.trunc(num) 去除小数部分,是直接把小数部分去掉
1.对于非数值,先调用Number方法把它转成数字
2.对于空值和无法转成数字的值,结果是NaN
(2).Math.sign(num) 判断一个数是正数还是负数还是0
1.参数为正数,返回1
2.参数为负数,返回-1
3.参数为0,返回0
4.参数为-0,返回-0
5.参数为其它值,返回NaN
(3).Math.hypot() 开平方,参数可以为多个,把所有的参数的平方加起来,然后再开平方
console.log(Math.trunc(12.74)); //12
console.log(Math.trunc(0.5)); //0
console.log(Math.trunc('36.01')); //36
console.log(Math.trunc(‘David')); //NaN
console.log(Math.sign(5)); //1
console.log(Math.sign(-5)); //-1
console.log(Math.sign(0)); //0
console.log(Math.sign(-0)); //-0
console.log(Math.sign('David')); //NaN
console.log(Math.hypot(3)); //3
console.log(Math.hypot(3,4)); //5
console.log(Math.hypot(3,4,5)); //7.
6.数组:
(1).Array.from()把类数组转成真正的数组
任何有length属性的对象就可以用这个方法转真正的数组, 对象中的key必须是0开始的数字。
(2). […类数组] 它是一个扩展方法,在这里可以把类数组转成真正的数组。
var str=‘David';
var newStr=Array.from(str);
console.log(newStr); //["D", "a", “v", "i", "d"]
//对象身上只要有length属性就可以调用Array.from()把对象转成数组,对象中的key必需是从0开始的数字才能转
var obj={
0:'red',
1:'green',
2:'blue',
3:'yellow',
length:4
};
var obj2={
1:'red',
2:'green',
3:'blue',
4:'yellow',
length:4
};
console.log(Array.from(obj)); //["red", "green", "blue", "yellow"]
console.log(Array.from(obj2));//[undefined, "red", "green", "blue"]
// 对于ajax交互时,提交对象时可以省略一部分代码;如
var form={name:"chenchen",password:"123",phone:'13100000000'};
// 提交时如下;
this.ajax.post("路径",{...form},res=>{
console.log({...form}) // {name:"chenchen",password:"123",phone:'13100000000'}
})
(3).Array.of()数值转数组
(4).Array.includes(“z”,index),查找某个数据在数组中是否存在,返回boolean
(5).for of 循环,能够直接读取键值(for in 循环,能够直接读取键名)它不光可以遍历数组或者对象,只要有遍历接口的对象都可以用它
(6).keys() 存储了数组的所有键名
(7).values() 存储了数组的所有键值
(8).entries() 存储了数组的所有键值对
var color=['red','green','blue','yellow'];
//for in
for(var attr in color){
console.log(attr); //0 1 2 3
}
//for of
for(var value of color){
console.log(value); //red green blue yellow
}
//字符串也可以使用for of
var str='David';
for(var value of str){
console.log(value); //D a v i d
}
//遍历keys
for(var key of color.keys()){
console.log(key); //0 1 2 3
}
// 遍历values
for(var value of color.values()){
console.log(value); //red green blue yellow 提示一下,chrome还不支持
}
//遍历entries
for(let [key,value] of color.entries()){
console.log(key,value); //0 "red" 1 "green" 2 "blue" 3 "yellow"
}
7.函数参数默认值
参数变量是默认声明的,不能用let和const声明
function fn(a,b){
b=b||'David';
console.log(a,b);
}
fn('hello'); //hello David
fn('hello','moto'); //hello moto
//参数变量是默认声明的,不能用let或者const再次声明
function fn2(a=20,b=10){
//console.log(a,b); //20 10
//let a=12; //报错
console.log(a+b);
}
fn2(); //30
fn2(23,45); //68
8.reset参数#####
reset参数,…变量名
reset参数是一个数组,它的后面不能再有参数,不然会报错。
扩展方法 … :
(1).后面跟类数组,加中括号,返回真数组;
(2).后面跟真数组,不加中括号,返回普通集合;
作用:1.替代apply方法;
2.替代concat方法;
3.将字符串转为数组。
function fn(a,b,c,...values){
console.log(values);
fn(1,2,3,4,5,6,78);
function fn2(...values/*,a*/){
let sum=0;
for(var val of values){
sum+=val;
}
//console.log(a); //报错 后面不能再跟参数
console.log(sum);
}
fn2(1,2,3,4,5); //15
//三个点的用法
var arr1=[12,34,5,28,97];
var divs=document.querySelectorAll("div");
console.log([...divs]); //类数组转真数组 注意:类数组以及三个点需要放在一对中括号里面
console.log(...arr1); //12 34 5 28 97,注意把数组转成集合数据,不用加中括号
//作用1:替代数组的apply方法,求最大值
console.log(Math.max(12,34,5,28,97)); //97
var arr2=[12,34,5,28,97];
//es5实现
console.log(Math.max.apply(null,arr2)); //97
//es6实现
console.log(Math.max(...arr2)); //97
//作用2:替代concat
var arr3=[1,2,3];
var arr4=['a','b','c’];
//es5实现:
//console.log(arr3.concat(arr4)); //[1, 2, 3, "a", "b", "c"]
//es6实现
arr3.push(...arr4);
console.log(arr3); //[1, 2, 3, "a", "b", "c"]
//作用3:把字符串转成数组
var str='David';
console.log([...str]); //["D", "a", "v", "i", "d"]
- 箭头函数
语法:
(1).function用var、let、const来表示
(2).参数要写在第一个等号后面
1.如果没有参数,需要写一对空的小括号
2.只有一个参数,那就直接写,不用加括号
3.参数有多个,需要加一个小括号,参数用逗号隔开
(3).函数的主体内容是放在箭头后面,如果语句只有一条,那就直接写。如果语句有多条,需要把它们放在一对大括号里
注意:
1.函数体内的this对象就是定义函数时所在的对象,不是调用函数时候的对象
2.不能当作构造函数来用,不能使用new
3.函数内不能使用arguments对象,如果要用的话就用reset参数来代替
//es5
function fn1(){
console.log('David');
}
fn1();
//es6
var fn1=()=>console.log('David');
fn1();
let fn2=a=>console.log(a);
fn2('小王'); //小王
const fn.=(a,b)=>{
let result=a+b;
console.log(result);
}
fn3(1,2); //3
var fn1= (...values)=>{
console.log(this);
}
fn1(1,2,3);
10.属性名表达式
把表达式放在中括号里作为属性名
'use strict'
var name='abc';
let key='interest';
let obj={
name:'David',
[key]:'编程',
['show'](){
console.log(this.name);
}
}
console.log(obj);
11.Symbol
新增的第7种数据类型,表示独一无二,用来作为属性名,保证不会与其他的属性名冲突。
1.它是通过Symbol函数生成的;
2.它的前面不能加new,因为它生成的是一个原始类型的数据,不是对象。
3.它可以接收一个参数,为了便于区分,即使长得一样也不相同。
4.它不能与其他的值进行运算,没有隐式转换。
5.它的值可以被转换成布尔值 (都为true )或者字符串,不能转成数字。
let s=Symbol();
console.log(s); //Symbol()
console.log(typeof s); //symbol
//console.log(new Symbol()); //报错
var s1=Symbol('David');
var s2=Symbol('David');
console.log(s1,s2,s1==s2); //Symbol(David) Symbol(David) false
//console.log(s1+'大卫'); //报错
console.log(String(s1)); //Symbol(David)
console.log(Boolean(s1)); //true
//console.log(Number(s1)); //报错,不能转成数字
//用法
var mySymbol=Symbol('j');
var obj={
[mySymbol]:'David'
}
console.log(obj);//Symbol(j): "David"
12.Set
新增数据结构,类似数组。所有数据都是唯一的,没有重复的值。它本身是个构造函数。
size 数据的长度
add()添加一个数据
delete()删除一个数据
has() 查找某条数据,返回一个boolean值
clear()删除所有数据
var set=new Set([1,3,4,5,4,3,2]);
set.add(6);
set.delete(1);
console.log(set.has(5)); //true
//set.clear();
console.log(set,set.size); //Set {3, 4, 5, 2, 6} 5
var divs=document.querySelectorAll("div");
var set2=new Set(divs);
console.log(set2);
var set3=new Set(['red','green','blue','yellow']);
set3.forEach(function(value,key,set3){
console.log(value,key,set3);
});
for(let [key,value] of set3.entries()){
console.log(key,value)
}
13.Map
新增数据结构,Map接受一个数组作为构造函数的参数。该数组的成员是一个个表示键值对的数组。所有数据都是唯一的,没有重复的值。
size 数据的长度
set() 添加一条数据
delete() 删除一条数据
get() 获取一条数据
has() 查找某条数据,返回一个布尔值
clear() 删除所有数据
var map=new Map([['name','David'],['age',18],['age',20]]);
map.set('sex','男');
map.delete('sex');
console.log(map.get('name')); //David
console.log(map.has('age')); //true
map.clear();
console.log(map,map.size); //Map {"name" => "David", "age" => 20}
var map2=new Map([['name',’David'],['age',20]]);
//遍历数据
for(let [key,value] of map2.entries()){
console.log(key,value);
}
14.原型、构造函数
es5和es6写法
// es5
// 构造函数定义属性
function Per(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=["aa","bb"];
}
Per.prototype={
// constructor属性指向的构造函数
constructor:Per,
// 原型对象定义的方法
sayName:function(){
alert(this.name);
}
}
// 一个新实例
var per1=new Per("nike",25,"teacher");
// 又一个新实例
var per2=new Per("luce",28,"tea");
per1.friends.push("cc");
//这时两个实例的数组friends是不一样的
//因为构造函数内的属性是属于每个新实例自己的独立的属性
//prototype中的属性和方法则是所有实例共享的
alert(per1.friends)//aa,bb,cc
alert(per2.friends)//aa,bb
//注意:每当访问对象的某个属性时,程序会先从实例对象里找,如果找不到再从对象指向的原型对象里找,也就是执行两次搜索
// es6
class Animal {
constructor(){
this.type = 'animal'
}
says(say){
console.log(this.type + ' says ' + say)
}
}
let animal = new Animal()
animal.says('hello') //animal says hello
// 首先用class定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。简单地说
// constructor内定义的方法和属性是每个实例对象自己的独立的
// constructor外定义的方法和属性则是所有实力对象都可以共享的
// 继承es5
//Suaa构造函数自定义属性
function Suaa(){
this.pro1=true;
}
//Suaa构造函数添加原型对象方法
Suaa.prototype.get1=function(){
return this.pro1;
};
//Subb构造函数自定义属性
function Subb(){
this.pro2=false;
}
//Subb继承Suaa
Subb.prototype=new Suaa();
//给Subb构造函数添加原型对象方法
Subb.prototype.get2=function(){
return this.pro2;
}
//创建Subb()的实例
var ins=new Subb();
//因为继承了Suaa所以拥有了Suaa的所有实例属性与方法,同时还有了指向Suaa原型对象的指针,所以也就有了Suaa的原型对象get1()方法
//其中搜索过程为先搜索实例,然后搜索Subb的原型,最后搜索所继承的Suaa原型
alert(ins.get1()); //true
// es6
class Cat extends Animal {
constructor(){
super()
this.type = 'cat'
}
}
let cat = new Cat()
cat.says('hello') //cat says hello
//上面定义了一个Cat类,该类通过extends关键字,继承了Animal类的所有属性和方法。
//super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
//ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
15、Promise
构造函数,异步操作变同步
// Promise 等待
// resolve()代表成功的状态,reject()失败的状态
let p = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(1);
resolve() //只有变成成功的状态,then才会执行
}, 2000);
})
p.then(function(){
setTimeout(() => {
console.log(2);
}, 2000);
})
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(1);
resolve()
}, 2000);
})
let p2 = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(2);
resolve()
}, 4000);
})
// 只有当p1,p2都为成功的时候才会执行.then
// 并且p1和p2同时执行
// 当其中1个失败,立刻全部是失败
Promise.all([p1,p2]).then(() => {
console.log(3)
},function() {
console.log("失败")
})
// 1
// 2
// 3
16、Generator
异步处理(Promise)的升级版本(了解即可)
1.语法: 在普通的函数后面加上*
2.当遇上yield关键字的时候函数就会暂停执行
3.将函数结果保存在函数中,通过.next()让函数继续执行
手动控制next让函数什么时候继续往下执行
function* fn(){
yield console.log(1); // 什么都没有打印
yield console.log(2);
}
let f = fn(); // 将函数结果保存在函数中
f.next(); // 1 通过.next()让函数继续执行
f.next(); // 2
function* fn(){
let a = yield 0;
yield console.log(a);
}
console.log(fn.next());
console.log(fn.next(2));
17、async
/*
* 语法: 在函数前面加上关键字 async
* await关键字后面必须是Promise对象
* */
let p1 = function (){
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log(1);
resolve()
},3000)
});
};
let p2 = function (data){
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log(`${data} 这里是p2`);
resolve(`已经全部完成`)
},1000)
});
};
/*
当遇到await 自动执行关键字后面的Promise对象
当Promise对象变为成功或失败 会自动继续执行下一个await后面的Promise
* */
async function fn(){
// 只有在async函数里面才能使用await关键字
// Promise对象成功时返回数据 可以在await关键字前面定义一个变量来接收
let pp1 = await p1();
let pp2 = await p2(pp1);
// 这里的return出去的东西是在.then里面接收
return pp2
}
fn().then((data) => {
console.log(data);
});
18、class
/*
* 定义构造函数的语法 class + 自定义的名字 {}
* */
/*function fn(){
}*/
// 上面的 等于 下面
class Cat{
// 构造函数本身
constructor(name){
this.name = name;
}
getname(){
return this.name
}
// 如果是静态的方法 不用new 可以直接调用
static getcolor(color){
console.log(color);
}
}
class Dog extends Cat{
constructor(name){
super(name);// super 父类本身 constructor
}
static getcolor(color){
super.getcolor(color);
}
}
/*let c = new Cat(`猫`);
console.log(c.getname());*/
//Cat.getcolor(`#fff`)
let d = new Dog(`狗`);
/*console.log(d.getname());*/
//d.getcolor(`#000`)
Dog.getcolor(`#ccc`) //要使用父类静态的方法,子类中也要定义成静态的方法