上一篇经过TodoList的练习,目的是为了让你们理解ES6中各类新特性的实际用途。html
最好的学习方法就是实践,因此这节课结合实际项目,来更好的理解和掌握ES6的用途和使用场景,达到灵活运用的目的。react
一、模块化git
以项目中广泛会有的config.js文件为例,实现export导出:github
const githubURL = "OUR GITHUB URL HERE"; const staticServer = "http://xxx.com"; const testsPath = `zaz-${type}-${name}/tests/index.htm?zaz[env]=tests`; const name = "stalker"; const type = "mod"; const version = "0.0.1"; const state = "ok"; const description = "JavaScript API to deal with user data"; let globalpkg = null; const config = { _static: { name, version, state, description, docs: `${githubURL}/pages/terra/zaz-${type}-${name}`, source: `${githubURL}/Terra/zaz-${type}-${name}`, tests: `${staticServer}/fe/${testsPath}`, dependencies: ['mod.wilson'] } }; export default config;
再在其余文件中经过import实现导入:ajax
import config from './config';//导入ES6模块 import { globalpkg } from './config'; import factory from './factory'; zaz.use((pkg) => { "use strict"; config.dynamic.globalpkg = pkg; pkg.require(['modFactory'], (modFactory) => { modFactory.create(pkg.utils.deepMerge(config._static, factory)); }); });
使用ES6统一的模块化规范,能够提升代码的可读性,更易于维护。编程
二、数组操做数组
import React,{Component} from 'react'; class RepeatArray extends Component{ constructor() { super(); } render(){ const names = ['Alice', 'Emily', 'Kate']; return ( <div> { let p=document.querySelectorAll('p'); let pArr=Array.from(p); pArr.forEach(function(item){ console.log(item.textContent); }); Array.from(pArr,function(item){return item + 'ES6'}); } </div> ); } }
使用Array.from 同时对每一个元素进行操做。安全
三、模板字符串服务器
常见的使用场景即是写组件模板时使用:app
$('#result').append(` There are <b>${basket.count}</b> items in your basket, <em>${basket.onSale}</em> are on sale! `);
能够在模板字符串中任意的嵌入变量, 调用函数等。
四、解构与扩展操做符
扩展操做符在父组件给子组件传递一批属性的情境中更为方便。
下面的例子把className之外的全部属性传递给div标签
class AutoloadingPostsGrid extends React.Component { render() { var { className, ...others, // contains all properties of this.props except for className } = this.props; return ( <div className={className}> <PostsGrid {...others} /> <button onClick={this.handleLoadMoreClick}>Load more</button> </div> ); } }
使用react开发最多见的问题就是父组件要传给子组件的属性较多时比较麻烦
class MyComponent extends React.Component{ //假设MyComponent已经有了name和age属性 render(){ return ( <SubComponent name={this.props.name} age={this.props.age}/> ) } }
使用扩展操做符能够变得很简单
class MyComponent extends React.Component{ //假设MyComponent已经有了name和age属性 render(){ return ( <SubComponent {...this.props}/> ) } }
上述方式是将父组件的全部属性都传递下去,若是这其中有些属性不须要传递呢?也很简单
class MyComponent extends React.Component{ //假设MyComponent有不少属性,而name属性不须要传递给子组件 var {name,...MyProps}=this.props; render(){ return ( <SubComponent {...Myprops}/> ) } }
上述方法最经常使用的场景就是父组件的class属性须要被单独提取出来做为某个元素的class,而其余属性须要传递给子组件。
在构建通用容器时,扩展属性会很是有用。
function App1() { return <Greeting firstName="Ben" lastName="Hector" />; } function App2() { const props = {firstName: 'Ben', lastName: 'Hector'}; return <Greeting {...props} />; }
五、Promise
场景一 : 全部图片加载完再显示在页面上,避免页面闪动。
function loadImg(src) { return new Promise((resolve, reject) => { let img = document.createElement('img'); img.src = src; img.onload = function () { resolve(img) } img.onerror = function (err) { reject(err) } }) } function showImgs(imgs) { imgs.forEach(function(img){ document.body.appendChild(img); }) } Promise.all([ loadImg('https://example.com/pic1') loadImg('https://example.com/pic2') loadImg('https://example.com/pic3') ]).then(showImgs)
场景二: 多个资源中只要加载了其中一种就可。
{ function loadImg(src) { return new Promise((resolve, reject) => { let img = document.createElement('img'); img.src = src; img.onload = function () { resolve(img) } img.onerror = function (err) { reject(err) } }) } function showImgs(img) { document.body.appendChild(img); } Promise.race([ loadImg('https://example.com/pic1') loadImg('https://example.com/pic2') loadImg('https://example.com/pic3') ]).then(showImgs) }
六、Generator
在异步编程的解决方案中,Generator比Promise更高级些。
使用场景:抽奖次数逻辑控制、长轮询(服务器请求报错再次请求, 定时发送请求)
// 之前控制次数是在全局中申明,既不安全又影响性能 let draw = function (count) { // 具体抽奖逻辑 console.info(`剩余${count}次`) } let residue = function* (count) { while (count > 0) { count-- yield draw(count) } } let start = residue(5) let btn = document.createElement('button') btn.id='start' btn.textContent = '抽奖' document.body.appendChild(btn); document.getElementById('start').addEventListener('click', function() { start.next() }, false) } { // 长轮询 let ajax = function* () { yield new Promise(function(resolve, reject) { setTimeout(() => { resolve({code: 0}) }, 200); }) } let pull = function () { let generator = ajax() let step = generator.next() step.value.then(function(d){ if (d.code !=0 ) { setTimeout(() => { console.info('wait') pull() }, 100); } else { console.info(d) } }) } pull()
经过下面这张流程图,再加深下对Generator的理解。
七、await
在项目中,有时会出现须要同时依赖多个接口,并且必须在这几个请求都处理完后,才能开始处理数据的状况。咱们能够在一个 async函数 中写多个await 语法的请求,而后逐个处理,可是这样效率过低了。
多个请求是能够并行执行的。这时就能够结合 Promise.all 高级方法来处理,能够同时发起多个请求,而后统一处理接口返回数据。
为了方便,这里演示同时请求2个url,多个的也是同样的, 以下:
export default { name: 'hello1', data () { return { msg: 'Hello Vue.js', info: {}, user1: {}, user2: {} } }, methods: { async getUserInfo () { try { const res = await this.$http.get('http://aaa.com/userinfo'); this.info = res.data } catch (e) { console.log(e); } }, async get2UserInfo () { try { const res = await Promise.all([ this.$http.get('http://aaa.com/userinfo1'), this.$http.get('http://aaa.com/userinfo2'), ]) this.user1 = res[0].data; this.user2 = res[1].data; } catch (e) { console.log(e); } } }, created () { this.getUserInfo(); this.get2UserInfo(); } }
再次运行项目,能够发现页面在初始化的时候同时发起了3个请求,并正常渲染出了接口数据。
注意:这里的 Promise.all() 的参数是一个函数执行队列,它们会同时发起,而后都请求成功后,会将队列的每一个任务的结果组装成一个结果数据,而后返回。
八、类操做
先实战建立一个List类
import Utils from "./Utils.js"; class List { constructor(title = "", items = [], isEditable = true, id = "") { this.id = (id) ? id : Utils.guid(); this.title = title; this.items = items; this.isEditable = isEditable; } render() { var html = `<div class="list" data-id="${this.id}" data-iseditable="${this.isEditable}"> <h2 class="list-title">${this.title}</h2> ${(this.isEditable) ? "<div class='btn delete-list danger' data-action='delete-list'>X</div>" : ""} <ul class="items">`; this.items.forEach(function(item) { html += item.render(); }); html += ` </ul> ${(this.isEditable) ? "<div class='btn add-item success' data-action='add-item'>Add Item</div>" : ""} </div>`; return html; } getItemById(id) { let item = this.items.filter(i => i.id === id); return ((item.length) ? item[0] : null); } add(item) { this.items.push(item); } remove(item) { this.items = this.items.filter(i => (i.id !== item.id)); } } export default List;
在app.js中建立List实例:
import List from "./List.js"; import Utils from "./Utils.js"; import Status from "./Status.js"; class App { constructor(lists = []) { this.lists = lists; } getDueItems() { let dueItems = []; this.lists.forEach(function(list) { list.items.forEach(function(item) { if (item.date && item.status === Status.PENDING && Utils.dateDiffInDays(new Date(item.date), new Date()) > 0) { dueItems.push(item); } }); }); return dueItems; } getItemById(id) { const filterById = (function filterById(id1) { return function(listItem) { return listItem.id === id1; }; }(id)); for (let i = 0; i < this.lists.length; i++) { let item = this.lists[i].items.filter(filterById); if (item.length) { return item[0]; } } return null; } getListById(id) { let list = this.lists.filter(l => l.id === id); return ((list.length) ? list[0] : null); } render() { let pastDueList = new List("Past Due Date", this.getDueItems(), false); let html = `<div class="app"> <div class="btn add-list success" data-action="add-list">[+] Add List</div> `; this.lists.forEach(function(list) { html += list.render(); }); html += pastDueList.render(); html += "</div>"; return html; } add(list) { this.lists.push(list); } remove(list) { this.lists = this.lists.filter(l => (l.id !== list.id)); } } export default App;
ES6中的类能让咱们能够用更简明的语法实现继承,也使代码的可读性变得更高。
九、Proxy
Proxy可让咱们根据不一样的业务逻辑进行相应的处理, 对原对象进行映射,生成新的对象,操做新对象的同时经过必定的规则修改原对象。
// 先定义一个函数 function validator(target,validator) { return new Proxy(target, { _validator: validator, set(targer,key,value,proxy){ if (targer.hasOwnProperty(key)) { let va = this._validator[key]; if (!!va(value)) { return Reflect.set(target,key,value,proxy) }else { throw Error(`不能设置${key}到${value}`) } }else { throw Error(`${key} 不存在`) } } }) } const personValidator={ name(val){ return typeof val === 'string' }, age(val){ return typeof val === 'number' && val >18 } } class Person{ constructor(name,age) { this.name = name this.age = age return validator(this, personValidator) } } const person = new Person('lilei', 30) console.info(person) // Proxy {name: "lilei", age: 30} // person.name = 48 // Uncaught Error: 不能设置name到48 // console.info(person) person.name = 'han mei mei' console.info(person) // Proxy {name: "han mei mei", age: 30}
点评:使用Proxy进行数据校验,将对象和验证分离开,便于后期代码的维护。
本篇主要经过实际项目中的例子回顾ES6的知识点,帮你们梳理重点和难点。学会ES6语法不难,活学活用到项目才是关键。
但愿各位小伙伴能充分认识到ES6的强大,经过在实际工做中不断地使用ES6,提高代码质量和工做效率,这样就能多一点喝茶看电影的时间。
最后祝你们都能成为别人眼中的程序猿大牛,O(∩_∩)O哈哈~