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

栏目: JavaScript · 发布时间: 5年前

内容简介:上一篇通过TodoList的练习,目的是为了让大家理解ES6中各种新特性的实际用途。最好的学习方法就是实践,所以这节课结合实际项目,来更好的理解和掌握ES6的用途和使用场景,达到灵活运用的目的。1、模块化

上一篇通过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 —项目综合实战(完结篇)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换