ECMAScript:ES6 基础

262 阅读5分钟

ECMA:European Computer Manufacturers Association,欧洲计算机制造商协会。ECMA是一个国际标准化组织,致力于制定和推广信息和通信技术(ICT)标准,以促进全球计算机和通信技术的发展。 ECMA制定了许多标准,包括ECMAScript(JavaScript)和ECMA-262(JavaScript语言规范)等。

ES6

let变量

  • let变量不能重复声明
  • let变量可限制在块级作用域内有效
  • let变量不能实现变量提升(let变量实际也有变量提升,但运行时会报错)

const常量

  • const常量声明时即需要赋值
  • const常量定义后不能再赋值,变更其引用
  • const常量可限制在块级作用域内有效

解构赋值

  • 数组解构赋值,let [var1, var2, var3] = ['val1', 'val2', 'val3']
  • 对象解构赋值,const {filed1, filed2} = {field1: '', field2: ''}

模版字符串

  • 使用````反引号包裹内容
  • 内容中可以使用变量${variable}

箭头函数

  • 使用()=>{}表示,()内是形式参数,{}是函数体
  • 箭头函数没有this,它的this是静态的,指向声明时所在作用域的this
  • 不能作为构造实例化对象
  • 不能使用arguments变量

扩展运算符

  • 扩展运算符使用...表示
  • 扩展运算符可以将数组转为逗号分隔的参数序列,...array

Symbol

在 ES5 中对象属性名都是字符串,这容易造成属性名的冲突,在修改添加新属性或方法时可能造成覆盖。因此为保证每个属性的名字都是独一无二,ES6 引入了 Symbol。

  • Symbol 是原始数据类型,表示独一无二的值
  • Symbol的值是唯一的
// 创建
let s = Symbol();
console.log(s); // Symbol()

// 创建Symbol可以添加描述
// 描述并不代表Symbol的实际值
// 描述只是为了方便区分
let s2 = Symbol('description');
let s3 = Symbol('description');
console.log(s2 === s3); // false

// 调用Symbol.for()可以创建并添加描述
let s4 = Symbol.for('description');
let s5 = Symbol.for('description');
console.log(s4 === s5); // true

// Symbol.prototype.description 可以获取描述
consoel.log(s2.description); // 'description'

将 Symbol 作为对象属性/方法名,这样就能避免属性/函数名冲突

// 对象
const obj = {}

// Symbol
let s = Symbol();

// Symbol作为属性名
obj[s] = 'value';
let name = Symbol();
const obj = {
    name: 'name',
    [name]: function() {
        console.log('hello');
    }
}
console.log(obj.name); // name
obj[name](); // hello

迭代器

具有Symbol.iterator属性(接口)的,可以使用for...of...遍历

const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

生成器函数

生成器函数是一种异步编程的解决方案;
传统的异步函数是回调函数,而生成器函数则是另一种异步函数。
生成器函数使用function *表示。

// 生成器函数在调用时,不会立即执行,而是返回一个迭代器对象
// 当调用 next() 后才执行函数体内容
function * gen() {
  console.log('hello');
}
let i = gen();
console.log(i); // gen {<suspended>}
i.next(); // hello
// 生成器函数中可以使用 yield 实现函数代码分割
// yield 可以是字面量,也可以是表达式
function * gen() {
  console.log('segment1');
  yield 'hello';
  console.log('segment2');
  yield 'world';
  console.log('segment3');
}
let i = gen();
// 遍历时,会以 yield 作为分隔分段执行函数内容
// 遍历时,遍历返回值就是 yield 内容
for (let v of i) {
  console.log(v);
}
/*
segment1
hello
segment2
world
segment3
*/

// 使用迭代器 next() 方法完成分段执行函数内容
// next()会返回 {value:, done:} 的内容
let i2 = gen();
i2.next(); // segment1
i2.next(); // segment2
i2.next(); // segment3
// 传统异步编程,回调嵌套
setTimeout(()=>{
  console.log('start');
  setTimeout(()=>{
    console.log('process');
    setTimeout(()=>{
      console.log('end');
    }, 3000);
  }, 2000);
}, 1000);

// 生成器函数异步编程
function start() {
  setTimeout(()=>{
    console.log('start');
    iterator.next();
  }, 1000);
}
function process() {
  setTimeout(()=>{
    console.log('process');
    iterator.next()
  }, 2000);
}
function end() {
  setTimeout(()=>{
    console.log('end');
    iterator.next();
  }, 3000);
}
function * gen() {
  yield start();
  yield process();
  yield end();
}
let iterator = gen();
iterator.next();
// 生成器函数在执行 next() 时,可以传递实参
// next(val) 传入的实际参数会作为最近一个 yield 的返回值
function start() {
  setTimeout(()=>{
    console.log('start');
    let data = '0%';
    iterator.next(data); // 传递 data = '0%'
  }, 1000);
}
function process() {
  setTimeout(()=>{
    console.log('process');
    let data = '50%';
    iterator.next(data); // 传递 data = '50%'
  }, 2000);
}
function end() {
  setTimeout(()=>{
    console.log('end');
    let data = '100%';
    iterator.next(data); // 传递 data = '100%'
  }, 3000);
}
function * gen() {
  let progress1 = yield start();
  console.log(progress1); // '0%'
  
  let progress2 = yield process();
  console.log(progress2); // '50%'
  
  let progress3 = yield end();
  console.log(progress3); // '100%'
}
let iterator = gen();
iterator.next();

Promise

Promise是ES6中的一种新的异步编程解决方案,语法上它是一个构造函数;
Promise可以用来封装异步操作中成功或失败的返回结果。

// Promise() 构造方法中传入一个函数参数,其中执行异步操作
// 形参函数中分别接收两个函数 resolve,reject
// resovle 在成功时调用
// reject 在失败时调用
const p = new Promise(function(resovle, reject){});

// Promise.then()方法用于异步处理的成功或失败结果
// Promise.then()分别接收两个回调函数,第一个代表成功,第二代表失败
// 成功的回调函数接收一个参数 value,获取 resovle(value)的入参
// 失败的回调函数接收一个参数 reason, 获取 reject(reason)的入参
p.then(function success(value){}, function error(reason){});
// Promise.then()方法返回的是一个Promise对象,因此可以链式调用
p.then().then();
// Promise.then()可以只接收第一个回调函数,只处理成功时的回调
p.then(function (value){});
// Promise.catch()则可以单独作为处理失败时的回调
p.catch(function (reason){});
const p = new Promise(function (resolve, reject) {
  setTimeout(()=>{
    let data = '获取的数据';
    resolve(data);
  }, 1000);
});
p.then(function success(value) {
  console.log(value);
}, function error(reason) {
  console.log(reason);
})

模块化

模块化规范:

  • CommonJS,规范实现有 NodeJS Browserify
  • AMD,规范实现有 requireJS
  • CMD,规范实现有 seaJS

模块化语法:

  • export,规定模块对外的接口
  • import,导入其他模块实现的功能

导入方式:

  • import *,通用导入
  • import {xx, yy},解构赋值导入
  • import {default as xx}export default内容解构赋值导入,必须使用as
  • import xx,简便导入,仅针对于export default内容

模块化示例

  1. 编写模块化JS内容
// 使用 export 标识对外开放的数据
export let variable = 'hello';
export function fn() {
  console.log('world');
}


// 使用 export {} 统一暴露
export {variable, fn}


// 使用 export default {} 默认暴露
export default {
  name: 'w',
  fn() {}
}
  1. 引入模块化JS文件
<script type="module">
  // 导入所有,别名为myjs,从my.js文件导入
  import * as myjs from "./my.js";
  console.log(myjs); // Module {Symbol(Symbol.toStringTag): 'Module'}
  
  // export deafult 内容需要通过 default 访问
  console.log(myjs.default.name);
</script>
  1. 在JS文件中引入模块化JS文件
import * as myjs from './my.js'
console.log(myjs);
  1. 引入模块化JS文件
<script src="./base.js" type="module">/<script>