ES6 —项目综合实战(完结篇)

上一篇经由过程TodoList的演习,目标是为了让人人明白ES6中种种新特征的现实用处。

最好的学习要领就是实践,所以这节课连系现实项目,来更好的明白和掌握ES6的用处和运用场景,到达灵活运用的目标。

1、模块化

以项目中广泛会有的config.js文件为例,完成export导出:

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完成导入:

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一致的模块化范例,能够进步代码的可读性,更易于保护。

2、数组操纵

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 同时对每一个元素举行操纵。

3、模板字符串

罕见的运用场景就是写组件模板时运用:

$('#result').append(`
   There are <b>${basket.count}</b> items
    in your basket, <em>${basket.onSale}</em>
   are on sale!
 `);

能够在模板字符串中恣意的嵌入变量, 挪用函数等。

《ES6 —项目综合实战(完结篇)》

4、解构与扩大操纵符

扩大操纵符在父组件给子组件通报一批属性的情境中更加轻易。

下面的例子把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} />;
}


5、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)
}


6、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的明白。

《ES6 —项目综合实战(完结篇)》

7、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() 的参数是一个函数实行行列,它们会同时提议,然后都要求胜利后,会将行列的每一个使命的效果组装成一个效果数据,然后返回。

《ES6 —项目综合实战(完结篇)》
8、类操纵

先实战建立一个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中的类能让我们能够用更简明的语法完成继续,也使代码的可读性变得更高。

9、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哈哈~
《ES6 —项目综合实战(完结篇)》

    原文作者:前端大彬哥
    原文地址: https://segmentfault.com/a/1190000019423357
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞