ES6 是对javascript语言的一次重大升级,目前es6中很多新语法和特性已经被浏览器兼容,还有一些新语法可以借助插件实现浏览器兼容。
总之现在就开始用es6编写javascript绝对是趋势...这里记录一些es6中常用的新特性和其引用场景。
1.新的数据类型Symbol,新的数据结构(对象)Set,Map
1.1 Symbol数据类型
Symbol和string,bool一样,是一种新增的基础类型数据,代表一个唯一的不可重复的数值
let s1 = Symbol(1); //内部参数为描述 console.log(s1,typeof s1); //Symbol(1) "symbol" console.log(Symbol(2) == Symbol(2)); //false (唯一性) console.log(String(Symbol(1))); //"Symbol(1)" (可以转为字符串类型) console.log(!Symbol(1)); //false (可转为bool类型) //不能转为数字类型,不能使用运算符进行运算
1.2 Set对象
Set类似于数组,但是成员的值都是唯一的,没有重复的值。可以应用Set做数组去重
const s = new Set([1,2,3]); s.size = 3; s.add("a").add("b"); console.log(s); //Set {1, 2, 3, "a", "b"} s.delete("a"); console.log(s.has("a")); //false const arr2 = [1,2,'a','b',2,'a']; console.log([...new Set(arr2)]); //[1,2,'a','b'] 数组去重
1.3 Map对象
Map类似json对象,但是不能像json那样设置,获取,删除属性和值
var map = new Map(); //创建Map数据 map.set(name,value); //设置键和值 map.get(name); //获取值 map.delete(name); //删除值
Map数据只能通过for of遍历
2.字符串,数组,对象,函数的扩展
2.1字符串的扩展
//repeat()重复操作 let str1 = 'a'; let str2 = str1.repeat(3); // "aaa" //includes() 判断是否包含段字符 let str = 'abcf'; console.log(str.includes('cf')); //true console.log(str.includes('cd')); //true //startsWith() 判断是否以某个字符开头 console.log(str.startsWith('ab')); //true console.log(str.startsWith('b')); //flase //endsWidth() 判断是否以某个字符结尾 console.log(str.endsWith('cf')); //true console.log(str.endsWith('c')); //flase
2.2数组的扩展
//Array.from() 将类数组转为数组 var aAs = document.querySelectorAll("a"); var aArr = Array.from(aAs); //aArr为数组,存的是dom对象 //Array.of(); 创建数组 var arr1 = Array.of(1,'a',2,3,3); //find(val,eq,arr) 找出第一个符合条件的数组成员 //findIndex(val,eq,arr) 找出第一个符合条件的数组成员的索引 //三个参数,依次为当前的值、当前的位置和原数组 var arr2 = ['a',2,'c',11,4]; let res1 = arr2.find(function(val,eq,arr){ return val < 4; }); let res2 = arr2.findIndex(function(val,eq,arr){ return val > 2 && val <10; }); console.log(res1); //2 console.log(res2); //4 //fill() 数组填充,覆盖 var oarr = [1,2,3]; //oarr.fill("a"); console.log(oarr); // ["a", "a", "a"] oarr.fill("a",1,2); console.log(oarr); // [1, "a", 3] //map()映射方法.n个值,n个结果 var arr = [61,20,70]; var arr2 = arr.map(function(item){ return item>=60?'及格':'不及格'; }); //arr2 //['及格','不及格','及格'] //reduce()方法.n个值,1个结果 var arrr1 = [68,53,12]; var res = arrr1.reduce(function(tmp,item,index){ //求和 return tmp+item; //返回前两个数的和,然后继续执行,直到返回一个值.index为执行索引 }); //res //133 //filter() 过滤方法 var res2 = arrr1.filter(function(item){ //过滤掉奇数 if(item%2==1){ return false; //奇数不要 }else{ return true; } }); //forEach() 遍历方法 arrr1.forEach(function(item,index){ console.log(`第${index}个是${item}`); //第0个是68 });
2.3对象的扩展
//Object.is() 判断数据形式是否一样 console.log(NaN === NaN); //false console.log(Object.is(NaN,NaN)); //true console.log(+0 === -0); //true console.log(Object.is(+0,-0)); //false //Object.assign() 对象的合并 var obj1 = {a:1} var obj2 = {a:2,b:3} var obj3 = {c:'abc'} Object.assign(obj1,obj2,obj3); //obj1为源对象 console.log(obj1); // Object {a: 2, b: 3, c: "abc"} //stringify() //json转字符串 //pares() //字符串转json
2.4函数的扩展
//函数的rest参数 function fn(...args){ //...可以展开数组和json,此处...args等于[] args.push(4); console.log(args); } fn(1,2,3); //[1,2,3,4] var json1 = {a:"a1",b:"b1"} var json2 = {...json1,c:"c1"} //{a: "a1", b: "b1", c: "c1"} //箭头函数 //原则:1.函数有且只有一个参数,()可以不写. 2.函数有且只有一个语句,且是return语句,{}可以不写. const fn = (a,b) => a+b; //箭头后跟变量,指函数返回值 const fn2 = function(a,b){ //fn2与fn效果一样 return a+b; } const fn = a =>{ const b=a+1;return b } //箭头函数后跟{},不再是返回值,而是函数体 fn(1); //2 const fn2 = (a,b) =>({a,b}); //要返回函数体时,用()包裹,返回的是一个对象 fn2(1,2); //Object {a: 1, b: 2} h => h(App) //等价于 h => { return h(App) } //也等价于function (h) { return h(App) } //箭头函数体内没有自己的this,在使用时,内部的this就是定义时所在环境的对象. document.onclick = ()=>{ console.log("ok"); console.log(this===window); //true,此处this不再指向触发方法的对象 }
3.解构赋值,字符串模板,扩展运算符
3.1解构赋值
原则:等号两边的结构必须一样,需要一个等式同时完成.
简单的场景: var [a,b,c] = [1,2,3]; a为1,b为2..
在得到json数据时也可以直接解构赋值:
var data = {"title":"a","msg":"aa"}; var {title,msg,name="默认名"} = data; //title为"a",msg为"aa",name为"默认名"
函数传参时可以传入默认值:
function fn({name="lili"}={}){ console.log(name); //输出lili } function fn(name="lili"){ console.log(name); //输出lili }
3.2字符串模板字符串连接
let flag = true; let str = "上海"; let html = `<ul> <li>${'首页'}</li> <li>${str}</li> <li>${flag?'北京':'上海'}</li> </ul>`; console.log(html); // <ul><li>首页</li><li>上海</li><li>北京</li></ul>
3.3 扩展运算符
扩展运算符...可用作数组复制,常用的数组复制方式有:Array.from()方法;连接空数组
var arr1 = [1,2]; //var arr2 = Array.from(arr1); //var arr2 = arr1.concat([]); var arr2 = [...arr1]; arr2.push(3); console.log(arr2); //[1,2,3] //arr1 [1,2]
4.for-of循环和iterator
4.1 for-of主要用来循环Map数据,还可以循环数组,不能循环json
var arr = ['a','b','c']; for(var i in arr){ console.log(i); // 0,1,2 } for(var i of arr){ console.log(i); // a,b,c } var map = new Map(); map.set("a","11"); map.set("b","22"); for(var name of map){ console.log(name); //同时输出键和值 a,11 ; b,22 } for(var [a,b] of map.entries()){ //此处map.entries()就是map的默认值 console.log(a,b); // a 11; b 22 } for(var key of map.keys()){ //仅遍历键 console.log(key); // a;b } for(var val of map.values()){ //仅遍历值 console.log(val); // 11;22 }
4.2 iterator方法
var arr = [1,2,3]; var itArr = arr[Symbol.iterator](); //原生方法运行后得到该数据的对象指针 //数组,set,map都有对应各自类型的对象指针,json不具备 console.log(itArr.next()); //{value: 1, done: false} console.log(itArr.next()); //{value: 2, done: false} console.log(itArr.next()); //{value: 3, done: false} console.log(itArr.next()); //{value: undefined, done: true} //具备iterator方法的数据结构都可以进行解构赋值和扩展运算符
5.es6中的面向对象与继承
5.1面向对象
es5中面向对象是通过new构造函数实现的,es6中有了class
class Person{ //类 constructor(name="小明"){ this.name = name } showName(){ console.log(this.name) } } var p1 = new Person("lili"); p1.showName();
5.2对象继承
在es5中,对象的继承分为属性继承和方法继承.属性通过call/apply原型冒充来继承,方法通过原型对象来继承.es6中可以通过extends来继承了
class Person{ //类 constructor(name="小明"){ this.name = name; this.head = 1; } static showClass(){ //静态方法 console.log("人类"); } showName(){ console.log(this.name) } } class Worker extends Person{ } var p1 = new Person(); var w1 = new Worker("工人小王"); p1.showName===w1.showName; //true, 子类和父类的实例的方法都是一个引用地址 Person.showClass(); //人类, 通过extend继承 Worker.showClass() //人类, 子类继承了父类的属性,方法,静态方法
若子类中还需定义其他属性时,需要先继承父类的构造器中的属性:
class Worker extends Person{ constructor(name){ //this.name ="xxx"; //找不到this,子类必须先调用super,才能用this super(name); //继承父类构造器中的属性,类似es5中的call/apply this.name ="xxx"; //子类可以覆盖或新增新的属性 } }
6.es6中的模块化
6.1 export/import实现模块化
早期实现模块化都有sea,require。目前es6中支持export/import的方式实现模块化。目前浏览器对模块化的兼容还不完善,可以用构建工具开发并引入babel等方式实现。
模块文件的创建和引入
//=================export======================= //a.js 一个js文件中,多个export语句导出多个模块 export const a ="dd" export const b ="ee" //b.js 引入a.js //import {a} from 'a.js' //引入模块需要写在{}中 //import {a,b} from 'a.js' //引入时变量名需要对应 import * as objs from 'a.js' //将a.js内所有导出的模块集成为一个对象objs //=================export default================ //c.js 导出一个模块,一个文件中只能有一个export default语句 export default 'hello world' //d.js 引入c.js import a from 'c.js' //引入export default导出的模块时,变量名不用对应 //----------------------------------------------------------- //e.js 用export default语句导出多个模块 const str = 'hello world'; const txt = '你好'; export default {str,txt} //f.js 引入e.js import a from './e.js' console.log(a.str,b.txt) //hello world 你好
6.2 CommonJs模块化 (node中采用的是CommonJs规范)
//a.js 导出模块 const str = 'hello world'; module.exports = str; //b.js 引入模块 const b = require('./a.js'); console.log(b); //hello world
7.es6中的Promise
Promise是一个对象,可以通过new来创建实例。有两个原型方法和几个静态方法。
7.1 then,catch方法
const p = new Promise(function(resolve,reject){ const img = new Image(); img.src = "https://resource.hbiger.com/image/blog/archive/flex/5.jpg"; img.onload = function(){ resolve(this); } img.onerror = function(err){ reject(err); } }); //异步响应,等图片加载动作完成后执行 p.then(function(img){ document.body.appendChild(img) },function(err){ }) //或者用catch方法替换上面第二个参数 p.then(function(img){ document.body.appendChild(img) }).catch(function(err){ })
7.2 all,race等静态方法
var p2 = Promise.resolve(3); //创建一个成功的响应 var p3 = Promise.reject(5); //创建一个失败的响应 //all静态方法,当页面渲染需要等待多个异步数据都完成后才能进行时,使用all Promise.all([p1,p2,p3]).then(function(datas){ console.log(datas); //当p1,p2,p3三个响应都成功时才执行then },function(err){ ///... }) //p1,p2,p3中有一个不成功,便执行err,返回错误信息 //race静态方法,当页面同时发出多个异步请求,使用响应最快的请求的返回数据时,可以用到race var t1 = new Promise(function(resolve,reject){ setTimeout(resolve,500,'one'); //延迟执行resolve('one'); }); var t2 = new Promise(function(resolve,reject){ setTimeout(resolve,300,'two'); }); Promise.race([t1,t2]).then(function(value){ console.log(value); //two });
8.async,await
8.1 await会在async异步函数内阻塞当前线程向后执行
//假设promiseFun是一个异步方法 function promiseFun(){ return new Promise((resolve,reject)=>{ new Promise((resolve,reject)=>{ resolve() }) .then(()=>{ resolve() console.log('innerPromise') }) }) } async function fn(){ let a = await promiseFun(); console.log('fn') console.log(a) } fn(); //打印innerPromise //打印fn //打印promiseFun //返回一个Promise {: undefined}
8.2 await并不是阻塞主线程执行,因为async函数本身是异步的,所以await其实是阻塞的当前异步函数的异步线程
var hold = function () { return new Promise(function (resolve, reject) { resolve(); }) }; async function count(i){ await hold() console.log(i) } for(var i = 0 ;i < 3 ; i++){ count(i); } console.log("run") //打印run //打印0 //打印1 //打印2
1.虽然await会阻塞async异步函数,但是并没有阻塞主线程。
2.虽然await阻塞异步函数向后执行,看起来像是同步的,但是它本质还是异步的,我们同样可以并行执行。而同步函数不能并行执行。
9.proxy代理器,对目标对象的操作进行代理
var oa = {a:"aa"} const proxy = new Proxy(oa, { get(target, key) { // 这里的 target 就是 Proxy 的第一个参数对象 console.log('proxy get key', key) return target[key] }, set(target, key, value) { target[key] = value console.log('value', value) } }) proxy.a //proxy get key a proxy.a = "aa2" //value aa2 //oa.a === "aa2" //true
Proxy支持拦截的操作,一共有13种:
1.get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。 2.set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。 3.has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。 4.deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。 5.ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、6.Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 7.getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 8.defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 9.preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。 10.getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。 11.isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。 12.setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 13.apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。