美文网首页
es6的语法提炼

es6的语法提炼

作者: 琴先森的博客 | 来源:发表于2019-06-21 11:13 被阅读0次

语法小提

  1. 如果es6的import命令要取代Node的require方法,这就形成了一个障碍。因为require是运行时加载模块,import命令无法取代require的动态加载功能。
  2. ES6的模块自动采用严格模式,不管你有没有在头部加上'use strict';
  3. import()函数,完成动态加载
    • import()类似于Node的require方法,区别主要是前者是异步加载,返回Promise对象,后者是同步加载。
      import {start,exists,readFile} from 'fs';
  4. rest参数
  • ES6引入rest参数(形式为...变量名),用于获取函数的多余参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
    注意:rest参数之后不能再有其他参数(即只能是最后一个参数)
  1. Set和Map数据结构

Generator函数的语法

  1. 简介
  • Generator 函数是ES6提供的一种异步编程解决方案。语法上可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。
  • 执行Generator函数会返回一个遍历器对象,也就是说Generator函数还是一个遍历器对象生成函数。

Generator函数有两个特征:

  • function 关键字与函数名之间有一个星号
  • 函数体内部使用yield表达式,定义不同的内部状态。

Generator函数调用与普通函数调用的区别

  • 调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象。
  • 必须调用遍历器对象的next方法,使得指针移向下一个状态。Generator函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
  1. yield表达式
  • Generator函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。
function* f() {
  console.log('执行了!')
}
 
var generator = f();
 
setTimeout(function () {
  generator.next()
}, 2000);
//如果f是普通函数,在为变量generator赋值时就会执行。

Set

  • [...new Set(array)]可以将 Set 结构转为数组, 也可实现数组去重
  • Array.from方法可以将 Set 结构转为数组,也可实现数组去重。
    const items = new Set([1, 2, 3, 4, 5]);
    const array = Array.from(items);
  • Set实例的属性和方法
    add(value):添加某个值,返回 Set 结构本身。
    delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    has(value):返回一个布尔值,表示该值是否为Set的成员。
    clear():清除所有成员,没有返回值
  • 遍历操作

for...of

let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
  console.log(item);
}
for (let item of set.values()) {
  console.log(item);
}  
for (let item of set.entries()) {
  console.log(item);
}
//Set 结构的实例默认可遍历,直接用for...of循环遍历 Set
for (let x of set) {
  console.log(x);
}
 

forEach()

Map

  • Map 的键实际上是跟内存地址绑定的
    如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键
  • Map实例的属性和方法
    size属性返回Map结构的成员总数 。
    set(key, value):添加某个值,返回 Map 结构本身。可以采用链式写法。
    get(key):读取key对应的健值,如果找不到key,返回undefined。
    delete(key):删除某个健,返回一个布尔值,表示删除是否成功。
    has(key):返回一个布尔值,表示该值是在当前Map对象之中。
    clear():清除所有成员,没有返回值
  • 遍历

for...of

const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);
 
for (let key of map.keys()) {
  console.log(key);
}
 
for (let value of map.values()) {
  console.log(value);
}
 
for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
 
for (let [key, value] of map.entries()) {
  console.log(key, value);
}

Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)

const map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);
[...map.keys()]  
// [1, 2, 3]
 
[...map.values()]
// ['one', 'two', 'three']
 
[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]
 
[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]

结合数组的map方法、filter方法,可以实现 Map 的遍历和过滤(Map 本身没有map和filter方法)。

const map0 = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');
 
const map1 = new Map(
  [...map0].filter(([k, v]) => k < 3)
);
// 产生 Map 结构 {1 => 'a', 2 => 'b'}
 
const map2 = new Map(
  [...map0].map(([k, v]) => [k * 2, '_' + v])
    );
// 产生 Map 结构 {2 => '_a', 4 => '_b', 6 => '_c'}

forEach()

Promise对象

  • Promise 对象是一个构造函数,用来生成Promise实例
function loadImgAsync(url){  
    return new Promise(function(resolve,reject){
        const image = new Image();
        image.onload = function(){
            resolve(image)
        }
        image.onerror = function(){
            reject(new Error('Could not load image at' + url))
        }  
        image.src = url;
    })
}
  • Promise.all()方法用于将多个Promise实例包装成一个新的Promise实例。
  • Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
    const p = Promise.race([p1, p2, p3]);
    只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

Class(类)

class Point{
    constructor(){}
}
Point.prototype.constructor === Point // true   prototype对象的constructor的属性,直接指向”类“的本身。

注意点

  • 严格模式
    类和模块的内部,默认就是\color{red}{严格}模式。
  • 不存在提升
    类不存在变量提升。let也不存在变量提升。
  • this的指向
    类的方法内部如果含有this,它默认指向类的实例。但是必须非常小心,一旦单独使用该方法,很可能会报错。
class Logger {
      constructor() {
          this.printName = this.printName.bind(this)
      }
      printName() {
            this.print(`Hello ${name}`);
      }
      print(text) {
            console.log(text);
      }
 }

 const logger = new Logger();
 const {printName } = logger;
 printName(); // Uncaught TypeError: Cannot read property 'print' of undefined

上面代码中,printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。
一个比较简单的解决方法是,在\color{red}{构造函数中绑定this},这样就不会找不到print方法了

class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
  }

  // ...
}

另一种解决方法是\color{red}{使用箭头函数}

静态方法

  • 方法前加\color{red}{static}关键字
  • \color{red}{不会被实例继承},如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。
  • 直接通过\color{red}{类}来调用(Foo.classMethod()),如果静态方法包含this关键字,这个this指的是类,而不是实例。
  • 父类的静态方法可以\color{red}{被子类继承}。静态方法也是可以从\color{red}{super}对象上调用的。

实例属性的新写法

  • 除了定义在constructor()方法里面的this上面,也可以定义在\color{red}{类的最顶层}
    这种新写法的\color{red}{好处}是,所有实例对象自身的属性都定义在类的头部,一眼就能看出这个类有哪些实例属性。

静态属性

  • Class\color{red}{本身的属性},即Class.propName,而不是定义在实例对象(\color{red}{this})上的属性
// 老写法
class Foo {
// ...
}
Foo.prop = 1;  // 目前只有这种方法可行

// 新写法
class Foo{
    static prop = 1;
} // 目前的提案提供前面加static关键字

私有方法和私有属性

  • 只能类的\color{red}{内部}访问的方法和属性,外部不能访问
  • 但ES6\color{red}{不提供},只能通过变通方法模拟实现
    一种方法是在命名上加以区别,方法或属性前面加_
    一种方法将私有方法移出模块
    一种方法利用symbol值的唯一性,将私有方法的名字命名为一个symbol值
  • 私有属性(方法)的\color{red}{提案},在属性名(方法)之前,使用\color{red}{ # }表示
    前面加上\color{red}{static}关键字,表示静态的私有属性(方法)

Symbol

  • 一种原始的数据类型。Symbol值通过Symbol函数生成。
    let s = Symbol();
  • Symbol函数加参数区分symbol值

字符串作为参数
let s1 = Symbol('s1');
let s2 = Symbol('s2');

对象作为参数
如果Symbol函数的参数是一个对象,就会调用该对象的toString方法,将其转化为一个字符串,然后才生成一个Symbol值。所以,Symbol函数的参数只能是字符串。

Symbol值作为属性名的遍历

  • 使用Object.getOwnPropertySymbols()方法获取一个对象上的Symbol属性名
let s5 = Symbol('s5');
let s6 = Symbol('s6');
let a = {
    [s5]: 's5',
    [s6]: 's6'
}
Object.getOwnPropertySymbols(a);// [Symbol(s5), Symbol(s6)]  
  • 也可以使用Reflect.ownKeys()返回所有类型的属性名,包括常规属性名和 Symbol属性名。
a.hello = 'hello';
Reflect.ownKeys(a);  //  ["hello", Symbol(s5), Symbol(s6)]

Symbol.for()和Symbol.keyFor()

ES6加载规则

<script type="module" src='./foo.js'></script>  
//浏览器对于带有type="module"的<script>,都是异步加载,即先渲染完整个页面,执行脚本。如果页面有多个<script type="module">,它们会按照在页面出现的顺序依次执行。  
<script type="module">
import utils from "./utils.js";
</script>  
//内嵌网页的写法  

使用babel将ES6转码为ES5

工具配置法 (配合gulp)

  • 安装gulp-babel模块
cnpm install --save-dev gulp-babel
  • 配置.babelrc文件 (必须配置,否则不能将es6编译成es5)
  • 编写gulpfile.js文件
var gulp = require("gulp");
var babel = require("gulp-babel");
  
gulp.task("default", function () {
  return gulp.src("src/a.js")
    .pipe(babel())
    .pipe(gulp.dest("lib"));
});

相关文章

网友评论

      本文标题:es6的语法提炼

      本文链接:https://www.haomeiwen.com/subject/xepjqctx.html