Es2017 将会给我们带来什么?

pipeline-operator

此前,如果我们需要实现函数1的返回值域给函数2调用

最简单的方式是

A(B(C()))

面向对象的话可以

let obj = {
    value: void 0,
    A() {
        this.value = 1;
        return this;
    },
    B() {
      this.value += 2;
        return this;
    },
    C() {
      this.value *=3;
        return this;
    }
}

obj
  .A()
  .B()
  .C()

如果在node端我们还可以使用.pipe

.pipe(A())
  .pipe(B())
  .pipe(C())

基本使用

而在Es2017中,TC39也为我们提供了管道运算符,它的基本用法是,将上一个函数执行,且将返回值作为入参,传递给下个函数的形参。并执行下一个函数,直到全部函数执行完成,返回最后一个函数返回的结果。

例如如下三个函数

function doubleSay (str) {
  return str + ", " + str;
}
function capitalize (str) {
  return str[0].toUpperCase() + str.substring(1);
}
function exclaim (str) {
  return str + '!';
}
// 原来的方式
let result = exclaim(capitalize(doubleSay("hello")));

>>> Hello, hello!
// 使用管道函数重构
let result = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

>>> Hello, hello!

同时,我们可以借助箭头函数在流的中间截获中间值

例如另外一个函数

function bilibliousStringFunction(s, b = ', BiLi') {
  return s.toUpperCase() + b;
}

然后我们改写一下我们的函数

let result = 'hello'
  |> doubleSay
  |> data => bilibliousStringFunction(data)
  |> exclaim;

>>> HELLO, HELLO, BiLi!

柯里化

我们还可以通过pipeline-operator实现函数柯里化

首先我们来复习一下柯里化

function curry(fn) {
  var arg = [].slice.call(arguments, 1);
  return function () {
    var newarg = [].concat.apply(arg, arguments);
    return fn.apply(this, newarg);
    }
}


var addCurry = curry(function (x,y,z) {
  return x+y+z;
},1);

addCurry(2,3);

ok, 接下来我们可以使用pipeline-operator重写上述逻辑

function add(...params1) {
  return function (...params2) {
    let payload = params1.concat(params2);
    return payload.length > 1 ? payload.reduce((b, n) => b + n) : payload[0] || 0;
  }
}

let result = 1
  |> add(2, 3);

result >>> 6

也是比较优雅的

继承

我们也可以在对象继承方面做一些文章

// 基础对象
function Person (name, age) {
  return { name, age };
}

// 功能函数
function Walk (Person) {
  Person.walk = function () {
    console.log('I can walk now!');
  }
  return Person;
}

function Talk (Person) {
  Person.talk = function () {
    console.log('I can talk now!');
  }
  return Person;
}

function Eat (Person) {
  Person.eat = function () {
    console.log('I can eat now!');
  }
  return Person;
}

function Ride (Person) {
 Person.ride = function () {
    console.log('I can ride now!');
  }
  return Person; 
}

// 具体对象
function Father (name, age) {
  return Person(name, age) |> Walk |> Talk |> Eat |> Ride;
}

function Son (name, age) {
  return Person(name, age) |> Walk |> Talk |> Eat;
}

这样我们就能很轻松的搭配我们所需的功能函数,拼装为具体能实现的实例

数据检测

同时,关于数据检验,我们现在可以这样玩

function bounded (prop, min, max) {
  return function (obj) {
    if ( obj[prop] < min || obj[prop] > max ) throw Error('out of bounds');
    return obj;
  };
}

function format (prop, regex) {
  return function (obj) {
    if ( ! regex.test(obj[prop]) ) throw Error('invalid format');
    return obj;
  };
}

function Xss(obj) {
  return testXssInObj(obj); // 伪代码
}

function createPerson (attrs) {
  attrs
    |> bounded('age', 1, 100)
    |> format('name', /^[a-z]$/i)
    |> Xss
    |> Person.insertIntoDatabase;
}

try {
  createPerson({age: 20, name: "__alert('Xss')__"})
} catch(err) {
  alert('Your Name or Age was illegal!')
}

bind-operator

在此之前,如果要绑定函数的作用域,我们一般用的是 bind, call, apply

如今,es2017 为我们提供了一个语法糖(Syntactic sugar)

栗子如下:

const Owen = {
  year: 18,
    getValue() {
      return this.year
    }
}

const bilibiliou = {
  year: 21
}

bilibiliou::Owen.getValue();  // >>> 21
// 等效于 Owen.getValue.call(bilibiliou)

如果不指定左值,则绑定默认的上下文

::console.log
// console.log.bind(console);

我们可以发现,对于函数,如果 有执行符 () 则被编译为call,如果没有则会编译为bind

如果我们传递了多个参数,则会被编译为apply

foo::bar(...[1,2,3]);
// bar.apply(foo, 1,2,3);

bind-operator 为我们带来了很多便利,首先就是React 中需要绑定this域的场景

this.somethingHandle = this.somethingHandle.bind(this);

我们完全可以使用bind-operator 进行改写

this.somethingHandle = ::this.somethingHandle

同时对于一些类数组,我们的操作也可以变得更加优雅

let oBtns = document.querySelectorAll('.button');

oBtns::map(v => {
  // to do something
});

// 等价于

[].map.call(oBthns, v => {
  // to do something
});

当我们对数据需要进行一系列处理的时候,我们还可以这么玩

function (data) {
  function extentionFunction1 (param) {
    return data.blabla(param)
  }

  function extentionFunction2 (param) {
    return data.foofoo(param);
  }


  return data
      .dataHandle1()
      ::extentionFunction1(123)
      .dataHandle2()
      ::extentionFunction2(456)
}

等价于

data = data
      .dataHandle1()
        .dataHandle2()

     data = extentionFunction1(123);
     data = extentionFunction2(456);

     return data;

Object.entries 和 Object.values

在此之前我们就能通过 Object.keys 将对象的key转为数组,如今,TC39为我们扩展了这类的方法

const obj = {
  retcode: 0,
    msg: 'Success',
    data: 'blabla'
}
const result = Object.values(obj);
console.log(result); // [0, 'Success', 'blabla']

如上,我们可以使用values输入一个对象内的所有values

我们还可以使用 entries 输出每一个键值对

const obj = {
  retcode: 0,
    msg: 'Success',
    data: 'blabla'
}
const result = Object.entries(obj);
console.log(result); // [['retcode', 0], ['msg', 'Success'], ['data', 'blabla']]

String Padding

string 扩展了两个方法

// padStart
'abc'.padStart(10);         // "       abc"
'abc'.padStart(10, "foo");  // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0");     // "00000abc"
'abc'.padStart(1);          // "abc"
// padEnd
'abc'.padEnd(10);          // "abc       "
'abc'.padEnd(10, "foo");   // "abcfoofoof"
'abc'.padEnd(6, "123456"); // "abc123"
'abc'.padEnd(1);           // "abc"

未来我们可以更好的处理字符串了

function sayHi (userFirstName) {
  let Hello = ' 大爷,您可来了,小的这就给您斟茶倒水,招呼菊仙姑娘';
  return userFirstName.padEnd(userFirstName.length + Hello.length, Hello);
}

sayHi('bilibiliou')

逗号不会抛错

有些时候(复制多个对象)可能后面不小心会留下一个小逗号

var obj = {
  1,
  2,
};

又或者 写函数入参的时候

function hi(a,b,) {
  console.log(`${a} ${b}`)
}

hi('Hello', 'World',);

还有可能是数组

[1,2,3,4,]

当代码复杂且代码被混淆|压缩|编译|转义的时候,可能一个逗号的Error也要查半天,断点调 在Es8的规范中,能够忽视这种错误,让程序正常的跑起来

当然,虽然规范给了我们这样的便利,还是最好不要犯这种低级的错误比较好。

共享内存

现在共享经济日渐火爆,有共享单车、共享充电宝、共享女友 blabla

当然也少不了共享内存了?! (Shared Memory and Atomics)

我们可以通过new Worker('calc.js') 来开辟一个子进程

let w = new Worker("calc.js");

如果主线程和子线程需要通讯的话,主要使用 postMessage 和 onmessage

主线程

w.postMessage("hi");
w.onmessage = function (ev) {
  console.log(ev.data);
}

子线程

onmessage = function (ev) {
  console.log(ev.data);
  postMessage("ho");
}

而现在我们可以开辟一定大小的存储空间,进行线程间数据共享

let sab = new SharedArrayBuffer(1024);  // 1KB 的共享内存
w.postMessage(sab)   // 通过postMessage 将指针发送给子线程

子线程直接从全局获取到指针,并写入数据,完成内存共享

var sab;
onmessage = function (ev) {
   sab = ev.data;
}

下面是一个素数生成器的例子

var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); // 100000 个素数
var ia = new Int32Array(sab);  // ia.length == 100000
var primes = new PrimeGenerator(); // 伪代码,素数生成器网上有对应实现
for ( let i=0 ; i < ia.length ; i++ )
   ia[i] = primes.next();
w.postMessage(ia);
var ia;
onmessage = function (ev) {
  ia = ev.data;        // ia.length == 100000
  console.log(ia[37]); // 第38位素数 163
}

值得注意的是,在共享内存内两个线程都能够修改数据

console.log(ia[37]);  // 163
ia[37] = 123456; // 最后为 123456

所以,应该有合理的机制来保证共享内存的合理使用

Atomic

未来还会提供一个类似 Math 方法一样的全局对象 Atomic

Atomic 下存在多个静态方法用来操作 SharedArrayBuffer 共享内存对象

具体可以看 MDN Atomics

关于 Atomic 的介绍

求幂运算符(**)

以前在写动画的时候,经常这么操作

const M = Math;
const { pow: Pow } = M;

现在 新规范为我们推出了 (**) 求幂运算。

我们可以直接这样

5 ** 2 // >>> 25

// 等同于 Math.pow(5, 2)

let num = 5;
num **= 2;
console.log(num);
// >>> num 25

原文发布于微信公众号 - 前端小吉米(villainThr)

原文发表时间:2017-09-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

数据结构C#版笔记--双向链表(DbLinkList)

这是数据结构C#版笔记--线性表(Data Structure)之单链表(LinkList)的继续,对于双向链接,节点上除了Next属性外,还要有Prev属性用...

19710
来自专栏纯洁的微笑

Java 8的新特性—终极版

1. 简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特...

3766
来自专栏移动开发的那些事儿

Android开发之逻辑单元测试

以上createInetSocketAddress方法就是我在编写单元测试的时候单独抽离出来的方法,一方面我需要mock一个InetSocketAddress来...

701
来自专栏程序你好

.NET面试基础知识

不同公司的职位和工作职责不同。在面试中,工作职责和经验对这个职位很重要。程序员职位有一年的经验他们会关注oops概念、并行编程、算法和解决问题的能力等等。另一方...

722
来自专栏腾讯IVWEB团队的专栏

Es2017 将会给我们带来什么?

本文介绍了 es2017 管道运算的基本使用方法、通过 pipeline-operator 实现函数柯里化,以及对象继承和数据检测,了解绑定函数,string ...

3580
来自专栏Java与Android技术栈

RxJava处理业务异常的几种方式关于异常处理业务异常总结

运行时异常: RuntimeException类及其子类都被称为运行时异常,这种异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即...

1323
来自专栏流媒体

Json海量数据解析Json海量数据解析

​ 在android开发中,app和服务器进行数据传输时大多数会用到json。在解析json中通常会用到以下几种主流的解析库:jackson、gson、fa...

742
来自专栏玩转JavaEE

Spring Cloud中Hystrix的请求合并

在微服务架构中,我们将一个项目拆分成很多个独立的模块,这些独立的模块通过远程调用来互相配合工作,但是,在高并发情况下,通信次数的增加会导致总的通信时间增加,同时...

3247
来自专栏一个会写诗的程序员的博客

《Kotin 编程思想·实战》

Xtend是Eclipse推出的一个新的JVM语言,并无意替代Java,而是以己之长补Java之短,精简代码,无类型,改进可读和维护。Eclipse Xtend...

883
来自专栏小樱的经验随笔

【Java学习笔记之二十八】深入了解Java8新特性

前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级。在Java Code Geeks上已经有很多介绍Java 8新特性的文章,...

3037

扫码关注云+社区