资讯专栏INFORMATION COLUMN

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

izhuhaodev / 2874人阅读

摘要:模块化以项目中普遍会有的文件为例,实现导出再在其他文件中通过实现导入导入模块使用统一的模块化规范,可以提高代码的可读性,更易于维护。类操作先实战创建一个类在中创建实例中的类能让我们可以用更简明的语法实现继承,也使代码的可读性变得更高。

上一篇通过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 (
      
{ 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"}); }
); } }

使用Array.from 同时对每个元素进行操作。

3、模板字符串

常见的使用场景便是写组件模板时使用:

$("#result").append(`
   There are ${basket.count} items
    in your basket, ${basket.onSale}
   are on sale!
 `);

可以在模板字符串中任意的嵌入变量, 调用函数等。

4、解构与扩展操作符

扩展操作符在父组件给子组件传递一批属性的情境中更为方便。

下面的例子把className以外的所有属性传递给div标签

class AutoloadingPostsGrid extends React.Component {
    render() {
        var {
            className,
            ...others,  // contains all properties of this.props except for className
        } = this.props;
        return (
            
); } }

使用react开发最常见的问题就是父组件要传给子组件的属性较多时比较麻烦

class MyComponent extends React.Component{
//假设MyComponent已经有了name和age属性
  render(){
    return (
      
     )
  }
}

使用扩展操作符可以变得很简单

class MyComponent extends React.Component{
//假设MyComponent已经有了name和age属性
  render(){
    return (
      
     )
  }
}

上述方式是将父组件的所有属性都传递下去,如果这其中有些属性不需要传递呢?也很简单

class MyComponent extends React.Component{
//假设MyComponent有很多属性,而name属性不需要传递给子组件
  var {name,...MyProps}=this.props;
  render(){
    return (
      
     )
  }
}

上述方法最常用的场景就是父组件的class属性需要被多带带提取出来作为某个元素的class,而其他属性需要传递给子组件。

在构建通用容器时,扩展属性会非常有用。

function App1() {
  return ;
}

function App2() {
  const props = {firstName: "Ben", lastName: "Hector"};
  return ;
}


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的理解。

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() 的参数是一个函数执行队列,它们会同时发起,然后都请求成功后,会将队列的每个任务的结果组装成一个结果数据,然后返回。


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 = `

${this.title}

${(this.isEditable) ? "
X
" : ""}
    `; this.items.forEach(function(item) { html += item.render(); }); html += `
${(this.isEditable) ? "
Add Item
" : ""}
`; 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 = `
[+] Add List
`; this.lists.forEach(function(list) { html += list.render(); }); html += pastDueList.render(); html += "
"; 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哈哈~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104546.html

相关文章

  • 完结汇总】iKcamp出品基于Koa2搭建Node.js实战共十一堂课(含视频)

    摘要:云集一线大厂有真正实力的程序员团队云集一线大厂经验丰厚的码农,开源奉献各教程。融合多种常见的需求场景网络请求解析模板引擎静态资源日志记录错误请求处理。结合语句中转中间件控制权,解决回调地狱问题。注意分支中的目录为当节课程后的完整代码。 ??  与众不同的学习方式,为你打开新的编程视角 独特的『同步学习』方式 文案讲解+视频演示,文字可激发深层的思考、视频可还原实战操作过程。 云...

    sPeng 评论0 收藏0
  • JS笔记

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。异步编程入门的全称是前端经典面试题从输入到页面加载发生了什么这是一篇开发的科普类文章,涉及到优化等多个方面。 TypeScript 入门教程 从 JavaScript 程序员的角度总结思考,循序渐进的理解 TypeScript。 网络基础知识之 HTTP 协议 详细介绍 HTT...

    rottengeek 评论0 收藏0
  • 前端相关大杂烩

    摘要:希望帮助更多的前端爱好者学习。前端开发者指南作者科迪林黎,由前端大师倾情赞助。翻译最佳实践译者张捷沪江前端开发工程师当你问起有关与时,老司机们首先就会告诉你其实是个没有网络请求功能的库。 前端基础面试题(JS部分) 前端基础面试题(JS部分) 学习 React.js 比你想象的要简单 原文地址:Learning React.js is easier than you think 原文作...

    fuyi501 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<