React Native开发2-需要学点ES6

问渠那得清如许,为有源头活水来。——朱熹

来自《观书有感二首·其一》,作者为宋代的朱熹。原文如下,

“半亩方塘一鉴开,天光云影共徘徊。

问渠那得清如许?为有源头活水来。”

意思是,

半亩大的方形池塘像一面镜子一样打开,清澈明净,天光、云影在水面上闪耀浮动。

要问池塘里的水为何这样清澈呢?是因为有永不枯竭的源头源源不断地为它输送活水。

这是一首抒发读书体会的哲理诗,“半亩方塘一鉴开,天光云影共徘徊”,半亩的“方塘”不算大,只有半亩地的一个方方的池塘,但它像一面镜子那样地澄澈明净,“一鉴”的“鉴”,就是“镜”,照人的镜子,“镜”和“鉴”是一个意思。

“半亩方塘”像一面镜子那样打开了。“半亩方塘”虽然不算大,但它却像一面镜子那样地澄澈明净,“天光云影”都被它反映出来了。闪耀浮动,情态毕见。作为一种景物的描写,这也可以说是写得十分生动的。

这两句展现的形象本身就能给人以美感,能使人心情澄净,心胸开阔。这一种感性的形象本身,它还蕴涵着一种理性的东西。很明显的一点是,“半亩方塘”里边的水很深、很清,所以它能够反映“天光云影”;反之,如果很浅、很污浊,它就不能反映,或者是不能准确地反映。

内容较多,所以分成了两篇文章来发送,以下接着第1部分的内容。

11、模板语法和分隔符

ES6 中有一种十分简洁的方法组装一堆字符串和变量。

${ ... } 可以用来渲染一个变量,其中的` 作为分隔符。例如

1letuser ='Jerry';

2console.log(`Hi$!`);// Hi Jerry!

12、import 和 export

import指的是导入模块、export导出模块,import有点类似Java上的引入文件或包的意思。

例如,

1//全部导入

2importpeoplefrom'./example'

3//有一种特殊情况,即允许你将整个模块当作单一对象进行导入

4//该模块将对象所有属性导出

5import*asexamplefrom"./example.js"

6console.log(example.name)

7console.log(example.age)

8console.log(example.getName())

9//导入对象的部分属性

10importfrom'./example'

11//导出默认, 有且只有一个默认

12exportdefaultApp

13// 部分导出14exportclassAppextendComponent{};

以下是收集到的一些经验总结,

1.当用export default people导出时,就用 import people 导入(不带大括号)。

2.当用export name 时,就用import { name }导入(记得带上大括号)。

3.一个文件里,有且只能有一个export default。但可以有多个export。

4.一个文件里,既有一个export default people, 又有多个export name 或者 export age时,导入就用 import people, { name, age } 。

5.当一个文件里出现n多个 export 导出很多模块,导入时除了一个一个导入,也可以用import * as example进行全部导入。

13、 for...of VS for...in

for...of 用于遍历一个迭代器,如数组:

1letnicknames = ['di','boo','punkeye'];

2nicknames.size =3;

3for(letnicknameofnicknames) {

4console.log(nickname);

5}

//Result di, boo, punkeye

1for...in用来遍历对象中的属性:

2letnicknames = ['di','boo','punkeye'];

3nicknames.size =3;

4for(letnicknameinnicknames) {

5console.log(nickname);

6}

//Result: 0, 1, 2

简单点说就是for in是遍历键名,for of是遍历键值。

由于for of的这个特性,所以它可以实现对iterator对象的遍历,而for in就是简单的遍历了。

14、Promise

Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。

Promise对象有以下2个特点:

1.对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved;从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象田静回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

有了Promise对象,就可以把异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供了统一的接口,使得控制异步操作更加容易。

在promise之前代码过多的回调或者嵌套,可读性差、耦合度高、扩展性低。通过Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的方式来编写异步代码,保存线性的代码逻辑,极大的降低了代码耦合性而提高了程序的可扩展性。

说白了就是用同步的方式去写异步代码。

发起异步请求

1fetch('/api/todos')

2.then(res=>res.json())

3.then(data=>({ data }))

4.catch(err=>({ err }));

另外,ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者rejected。

1varp =newPromise(function(resolve, reject){

2if(/* condition */) {

3// fulfilled successfully

4resolve(/* value */);

5}else{

6// error, rejected

7reject(/* reason */);

8}

9});

每一个 Promise 都有一个 .then 方法,这个方法接受两个参数,第一个是处理 resolved 状态的回调,一个是处理 rejected 状态的回调:

1p.then((val)=>console.log("Promise Resolved", val),

2(err)=>console.log("Promise Rejected", err));

15、Symbol

Symbol 是一种新的数据类型,它的值是唯一的,不可变的。ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符:

1varsym =Symbol("some optional description");

2console.log(typeofsym);// symbol

注意,这里 Symbol 前面不能使用 new 操作符。

如果它被用作一个对象的属性,那么这个属性会是不可枚举的:

1varo = {

2val:10,

3[Symbol("random") ]:"I'm a symbol",

4};

5console.log(Object.getOwnPropertyNames(o));// val

如果要获取对象 symbol 属性,需要使用Object.getOwnPropertySymbols(o)。

16、迭代器(Iterators)

迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素是,迭代器便会退出。它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。

ES6 中可以通过 Symbol.iterator 给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的 @@iterator 方法便可以返回一个用于获取值的迭代器。

数组默认就是一个迭代器:

1var arr = [11,12,13];

2var itr = arr[Symbol.iterator]();

3itr.next();//{value:11,done:false}

4itr.next();//{value:12,done:false}

5itr.next();//{value:13,done:false}

6itr.next();//{value:undefined,done:true}

你可以通过 [Symbol.iterator]() 自定义一个对象的迭代器。

17、Generators

生成器( generator)是能返回一个迭代器的函数。生成器函数也是一种函数,最直观的表现就是比普通的function多了个星号*,在其函数体内可以使用yield关键字,有意思的是函数会在每个yield后暂停。

这里生活中有一个比较形象的例子。咱们到银行办理业务时候都得向大厅的机器取一张排队号。你拿到你的排队号,机器并不会自动为你再出下一张票。也就是说取票机“暂停”住了,直到下一个人再次唤起才会继续吐票。

说说迭代器。当你调用一个generator时,它将返回一个迭代器对象。这个迭代器对象拥有一个叫做next的方法来帮助你重启generator函数并得到下一个值。next方法不仅返回值,它返回的对象具有两个属性:done和value。value是你获得的值,done用来表明你的generator是否已经停止提供值。继续用刚刚取票的例子,每张排队号就是这里的value,打印票的纸是否用完就这是这里的done。

1//生成器

2function*createIterator(){

3yield1;

4yield2;

5yield3;

6}

// 生成器能像正规函数那样被调用,但会返回一个迭代器

那生成器和迭代器又有什么用处呢?

围绕着生成器的许多兴奋点都与异步编程直接相关。异步调用对于我们来说是很困难的事,我们的函数并不会等待异步调用完再执行,你可能会想到用回调函数,(当然还有其他方案比如Promise比如Async/await)。

生成器可以让我们的代码进行等待。就不用嵌套的回调函数。使用generator可以确保当异步调用在我们的generator函数运行下行代码之前完成时暂停函数的执行。

那么问题来了,咱们也不能手动一直调用next()方法,你需要一个能够调用生成器并启动迭代器的方法。就像这样子的

1functionrun(taskDef){//taskDef即一个生成器函数

2//创建迭代器,让它在别处可用

3lettask = taskDef();

4//启动任务

5letresult = task.next();

6

7//递归使用函数来保持对 next() 的调用

8functionstep(){

9

10//如果还有更多要做的

11if(!result.done) {

12result = task.next();

13step();

14}

15}

16

17//开始处理过程

18step();

19}

生成器与迭代器最有趣、最令人激动的方面,或许就是可创建外观清晰的异步操作代码。你不必到处使用回调函数,而是可以建立貌似同步的代码,但实际上却使用 yield 来等待异步操作结束。

18、Map 和 WeakMap

ES6 中两种新的数据结构集:Map 和 WeakMap。事实上每个对象都可以看作是一个 Map。

一个对象由多个 key-val 对构成,在 Map 中,任何类型都可以作为对象的 key,如:

1varmyMap =newMap();

2varkeyString ="a string",

3keyObj = {},

4keyFunc = function () {};

5//设置值

6myMap.set(keyString,"value 与 'a string' 关联");

7myMap.set(keyObj,"value 与 keyObj 关联");

8myMap.set(keyFunc,"value 与 keyFunc 关联");

9myMap.size;// 3

10//获取值

11myMap.get(keyString);// "value 与 'a string' 关联"

12myMap.get(keyObj);// "value 与 keyObj 关联"

13myMap.get(keyFunc);// "value 与 keyFunc 关联"

WeakMap

WeakMap 就是一个 Map,只不过它的所有 key 都是弱引用,意思就是 WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。

另一个需要注意的点是,WeakMap 的所有 key 必须是对象。它只有四个方法

1delete(key),has(key),get(key) 锟斤拷set(key, val)锟斤拷

2letw =newWeakMap();

3w.set('a','b');

4// Uncaught TypeError: Invalid value used as weak map key

5varo1 = {},

6o2 = function(){},

7o3 = window;

8w.set(o1,37);

9w.set(o2,"azerty");

10w.set(o3, undefined);

11w.get(o3);// undefined, because that is the set value

12w.has(o1);// true

13w.delete(o1);

14w.has(o1);// false

19、 Set 和 WeakSet

Set 对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型:

1letmySet =newSet([1,1,2,2,3,3]);

2mySet.size;// 3

3mySet.has(1);// true

4mySet.add('strings');

5mySet.add({ a:1, b:2});

可以通过 forEach 和 for...of 来遍历 Set 对象:

1mySet.forEach((item) =>{

2console.log(item);

3// 1

4// 2

5// 3

6// 'strings'

7// Object { a: 1, b: 2 }

8});

9for(letvalueofmySet) {

10console.log(value);

11// 1

12// 2

13// 3

14// 'strings'

15// Object { a: 1, b: 2 }

16}

Set 同样有 delete() 和 clear() 方法。

WeakSet

类似于 WeakMap,WeakSet 对象可以让你在一个集合中保存对象的弱引用,在 WeakSet 中的对象只允许出现一次:

1varws =newWeakSet();

2varobj = {};

3varfoo = {};

4ws.add(window);

5ws.add(obj);

6ws.has(window);// true

7ws.has(foo);// false, foo 没有添加成功

8ws.delete(window);// 从结合中删除 window 对象

9ws.has(window);// false, window 对象已经被删除

20、 类

ES6 中有 class 语法。值得注意是,这里的 class 不是新的对象继承模型,它只是原型链的语法糖表现形式。

函数中使用 static 关键词定义构造函数的的方法和属性:

1classTask{

2constructor() {

3console.log("task instantiated!");

4}

5showId() {

6console.log(23);

7}

8staticloadAll() {

9console.log("Loading all tasks..");

10}

11}

12console.log(typeofTask);// function

13lettask =newTask();// "task instantiated!"

14task.showId();// 23

15Task.loadAll();// "Loading all tasks.."

类中的继承和超集:

1classCar{

2constructor() {

3console.log("Creating a new car");

4}

5}

6classPorscheextendsCar{

7constructor() {

8super();

9console.log("Creating Porsche");

10}

11}

12letc =newPorsche();

13// Creating a new car

14// Creating Porsche

extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。

当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。

有几点需要注意:

类的声明不会提升(hoisting),如果你要使用某个 Class,那你必须在使用之前定义它,否则会抛出一个 ReferenceError 的错误;

在类中定义函数不需要使用 function 关键词;

总结,以上就是ES6常用特性,其实它的新特性远不止于此,但对于我们日常的开发来说,掌握以上内容足够了。如果想更加深入的学习,可以去学习阮一峰的ES6标准入门,据说这本书比较权威,我买了一本,还没有看完,感觉写的很不错,浅显易懂。网上也有电子版的,地址为http://es6.ruanyifeng.com/,大家可以在线学习。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180728G1663700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券