ES6 常用功能总结

目录

1. let / const

2. 模版字符串(template string)

3. 解构赋值

4. 块级作用域

5. 函数默认参数

6. 箭头函数() => {}

7.Set()

8. 模块化

9. promise

async await 与 promise 哪个好用?

10.async await函数

11. class

12.keys,values,entries

13、Generator


1. let / const

es6 以前,都是用 var 关键字来标识,这样有个变量提升的坑。在 es6 中,添加了 let 和 const 两个关键字,let 定义变量,const 定义常量,并且添加了块级作用域。

ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。const声明一个只读的常量。

1、let和const的相同点:
① 只在声明所在的块级作用域内有效。
② 不提升,同时存在暂时性死区,只能在声明的位置后面使用。
③ 不可重复声明。

变量提升:es6 以前,js 引擎将所有的变量都提到最前面,初始化为 undefined。

2、let和const的不同点:

① let声明的变量可以改变,值和类型都可以改变;const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值。
② 数组和对象等复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const只保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个复合类型的变量声明为常量必须非常小心。
想让定义的对象或数组的数据也不能改变,可以使用object.freeze(arr|object)进行冻结。冻结指的是不能向这个对象或数组添加新的属性,不能修改已有属性的值,不能删除已有属性。

const arr = []; 
Object.freeze(arr);
arr[0] = 1;              // 不报错,但数据改变无效
console.log(arr.length); // 输出:0

补充:变量提升
JavaScript 代码的执行分为两个阶段。第一个阶段在当前词法环境中注册所有的变量和函数声明,简单说就是 解析,解析完成之后,第二个阶段的 JavaScript 执行就开始了!
JS中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升。
JavaScript 仅提升声明,而不提升初始化。如果你先使用的变量,再声明并初始化它,变量的值将是 undefined。

1:所有的声明都会提升到作用域的最顶上去。
2:同一个变量只会声明一次,其他的会被忽略掉。
3:函数声明的优先级高于变量申明的优先级,并且函数声明和函数定义的部分一起被提升。

2. 模版字符串(template string)

使用 ``(反引号作为标识),既可以当作普通字符串使用,又可以用来定义多行字符串,还可以在字符串中嵌入变量(使用模板变量${})。

如果遇到特殊的字符 比如`,则需要在前面加转义字符\。 这样使用起来很方便,避免字符串拼接中出现的不必要的错误,而且更简单简洁,最重要的是人易懂。需要注意的是 ${ } 要和 `` 一起使用不然不会被解析。

3. 解构赋值

解构赋值属于浅拷贝!

顾名思义,就是先解构,再赋值! 比如先定义一个对象和数组:

var obj = { a: 1, b: 2, c: 3 };
var arr = [1,2,3];
// 在 es6 以前,这样获取属性的值: obj.a; obj.b; arr[i];
// 在 es6 中如下方式获取:
const { a, c } = obj;
const [x, y, z] = arr;
// 很简单就可以获取对象的属性和数组的值,看下编译得过程:
var a = obj.a, c = obj.c;
var arr = [1, 2, 3];
var x = arr[0], y = arr[1], z = arr[2];

4. 块级作用域

代码块(用{}表示)块,就是代码中我们用两个{ }包起来的内容。

5. 函数默认参数

function test (a, b = 0) {
    // ...
} 

编译一下:

function test(a) {

    var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; 

    // ... 
}

6. 箭头函数() => {}

定义:ES6箭头函数结构为 X => X*X

等价:function(X) { return X*X }

箭头函数特点:

  • 更简洁的语法

  • 不绑定this,捕获其所在上下文的 this 值,作为自己的 this 值

  • 箭头函数是匿名函数,不能作为构造函数,不能使用new

  • 不绑定arguments,用rest参数...解决

  • 使用call()和apply()调用,只是传入了参数而已,对 this 并没有什么影响

  • 箭头函数没有原型属性

  • 不能简单返回对象字面量(返回对象时需要用小括号包起来,因为大括号被占用解释为代码块了)

  • 箭头函数不能当做Generator函数,不能使用yield关键字

  • 箭头函数不能换行

let a = ()
           => 1; //SyntaxError: Unexpected token =>

箭头函数与普通函数的区别?
• 箭头函数都是匿名函数
• this的指向不同
(1) 箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
(2) 普通函数的this指向调用它的那个对象

7.Set()

Set()是有序列表的结合,而且是没有重复的,因此Set()对象可以用于数组的去重。

数组去重

1)[...new Set([1,2,3,1,'a',1,'a'])]

2)Array.from(new Set([1,2,3,1,'a',1,'a'])

Set中包含的方法:add()、has、delete()、clear()

Set也能用来保存NaN和undefined, 如果有重复的NaN, Set会认为就一个NaN(实际上NaN!=NaN);

实例Set以后的对象拥有这些属性和方法:

属性:Set.prototype 、Set.prototype.size
方法:Set.prototype.add()、Set.prototype.clear()、Set.prototype.delete()、Set.prototype.entries()、Set.prototype.forEach()、Set.prototype.has()、Set.prototype.values()、Set.prototype[@@iterator] ()

8. 模块化

在现在多个人开发同一个项目很常见,每个人负责不同的模块,还有可能会几个人使用同一个模块,在这种情况下,模块化就很重要!其实使用起来也很简单,比如说有模块A、B、C三个 js 文件,各自在其中定义好自己的代码,使用 export 关键字导出自己的东西,别人使用时用 import 关键字引用即可,模块化的处理工具有 webpack、rollup 等。一个模块就是一个实现特定功能的文件。

1. 模块化开发的4点好处:

1.避免变量污染,命名冲突 2.提高代码复用率 3.提高维护性 4.依赖关系的管理

2. 实现模块化

开始的模块化体现:函数 =》 对象 =》 立即执行函数

1)commonJS

根据commonJS规范,一个单独的文件是一个模块,每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非为global对象的属性。模块只有一个出口,module.exports对象,我们需要把模块想要输出的内容放入该对象。加载模块用require方法,该方法读取一个文件并且执行,返回文件内部的module.exports对象。

2)AMD (Asynchronous Module Definition) 异步模块定义

它是一个在浏览器端模块化开发的规范,由于不是js原生支持,使用AMD规范进行页面开发需要用到RequireJS函数库(实际上AMD是RequireJS在推广过程中对模块定义的规范化的产出)。 AMD推崇的是依赖前置,在定义模块的时候就有声明其依赖的模块。(被提前罗列出来并会被提前下载并执行,后来做了改进,可以不用罗列依赖模块,允许在回调函数中就近使用require引入并下载执行模块。)

requireJS主要解决两个问题:
1 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器。
2 js加载的时候浏览器会停止页面渲染,加载文件愈多,页面失去响应的时间愈长。

3)CMD (common module definition)

就像AMD有个requireJS,CMD有个浏览器实现的sea.js,sj要解决的问题和rj一样,只不过在模块定义方式和模块加载时机上有所不同(cmd是sea.js在推广过程中的规范化产出),sea.js是另一种前端模块化工具,它的出现缓解了requireJS的几个痛点。CMD推崇依赖就近,只有在用到某模块的时候再去require。

4)ES6 Modules模块化实现

import引入, module.export导出

9. promise

  • promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)

  • 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据

  • 代码风格,容易理解,便于维护

  • 多个异步等待合并便于解决

promise详解
 

new Promise(
    function (resolve, reject) {
        // 一段耗时的异步操作
        resolve('成功') // 数据处理完成
        // reject('失败') // 数据处理出错
}).then(
        (res) => {console.log(res)},  // 成功
        (err) => {console.log(err)}   // 失败
)
  • resolve作用:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去; reject作用:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

  • promise有三个状态: 1、pending[待定]初始状态 2、fulfilled[实现]操作成功 3、rejected[被否决]操作失败 当promise状态发生改变,就会触发then()里的响应函数处理后续步骤; promise状态一经改变,不会再变。

  • Promise对象的状态改变,只有两种可能: 从pending变为fulfilled 从pending变为rejected。 这两种情况只要发生,状态就凝固了,不会再变了。

常见用法: 异步操作和定时器放在一起,,如果定时器先触发,就认为超时,告知用户; 例如我们要从远程的服务家在资源如果5000ms还没有加载过来我们就告知用户加载失败

Promise.all

可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

1.它接受一个数组作为参数。

2.数组可以是Promise对象,也可以是其它值,只有Promise会等待状态改变。

3.当所有的子Promise都完成,该Promise完成,返回值是全部值的数组,数组顺序不变

4.如果有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果。

Promise.race

区别在于 它一旦有一个promise返回就算完成(但是进程不会立即停止),该promise对象 resolve 以后,立即把 resolve 的值作为 Promise.race() resolve 的结果;如果该对象 reject,Promise.race也会立即 reject。

1.它接受一个数组作为参数。

2.数组可以是Promise对象,也可以是其它值,只有Promise会等待状态改变。

3.当某一个Promise完成,该Promise完成,返回值是该Promise的结果。

async await 与 promise 哪个好用?

假设同时发十个请求,要求十个请求都返回后再做其他操作?

10.async await函数

awiat必须在使用async的情况下才能使用,它的作用是阻断主函数的执行,等待异步执行的结果返回后才会向下继续执行。

受await阻断影响,必须要在await fn()执行完后才能执行,同时如果fn()没有返回结果,就是说没有reslove()的话,那么下面的代码将不会执行

11. class

实际上应该说是构造函数,通过原型实现的

12.keys,values,entries

用于遍历数组,它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for (let index of ['a', 'b'].keys()) {
		console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
		console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
		console.log(index, elem);
}
// 0 "a"
// 1 "b"

13、Generator

1.相关概念

Generator(生成器)是一类特殊的函数,跟普通函数声明时的区别是加了一个*号。

Iterator(迭代器):当我们实例化一个生成器函数之后,这个实例就是一个迭代器。可以通过next()方法去启动生成器以及控制生成器的是否往下执行。

yield/next:这是控制代码执行顺序的一对好基友。 通过yield语句可以在生成器函数内部暂停代码的执行使其挂起,此时生成器函数仍然是运行并且是活跃的,其内部资源都会保留下来,只不过是处在暂停状态。 在迭代器上调用next()方法可以使代码从暂停的位置开始继续往下执行。

// 首先声明一个生成器函数
function *main() {
    console.log('starting *main()');
    yiled; // 打住,不许往下走了
    console.log('continue yield 1');
    yield; // 打住,又不许往下走了
    console.log('continue yield 2');
}
// 构造处一个迭代器it
let it = main(); 

// 调用next()启动*main生成器,表示从当前位置开始运行,停在下一个yield处
it.next(); // 输出 starting *main()

// 继续往下走
it.next(); // 输出 continue yield 1

// 再继续往下走
it.next(); // 输出 continue yield 2

2.消息传递
3.Generator在流程控制中的应用
4.Generator+Promise实现完美异步
5.async和await
​​​​​​​6.yield委托

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值