前端学习篇 -- ES6 学习

1、let 与 const

1.1 let

1.1.1 作用

与var类似,声明一个变量

1.1.2 特点
  1. 声明的变量只在代码块内有效

    {
          
          
      let a = 10;
      var b = 1;
    }
    console.log(a) // ReferenceError: a is not defined.
    console.log(b) // 1
    
  2. 不允许重复声明

    {
          
          
      let a = 10;
      var a = 1;
    }
    console.log(a)  //SyntaxError: Identifier 'a' has already been declared
    
  3. 不存在变量提升

    // var 的情况
    console.log(foo); // 输出undefined
    var foo = 2;
    
    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;
    
  4. 暂时性死区

    • 使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
    if (true) {
          
          
      // TDZ开始
      tmp = 'abc'; // ReferenceError
      console.log(tmp); // ReferenceError
    
      let tmp; // TDZ结束
      console.log(tmp); // undefined
    
      tmp = 123;
      console.log(tmp); // 123
    }
    
1.1.3 应用

循环遍历加监听

闭包方法输出索引

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
  var btns = document.querySelectorAll("button");
  for (var i = 0; i < btns.length; i++) {
    
    
    (function(i) {
    
    
      btns[i].onclick = function() {
    
    
      alert(i)
    }
    })(i);
  }
</script>

let 方法

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
  var btns = document.querySelectorAll("button");
  for (let i = 0; i < btns.length; i++) {
    
    
    btns[i].onclick = function() {
    
    
      alert(i)
    }
  }
</script>

1.2 const

1.2.1 作用

声明一个常量,一旦声明就不能修改

1.2.2 特点
  1. 声明后值不能修改
  2. 只声明不赋值也会报错
  3. 只能先声明后使用,不会被提前解析
  4. 不能重复声明一个常量

注意:const声明的对象中属性是可以修改的

1.3 声明变量的六种方法

ES5:var function

ES6:let const import class

2、解构赋值

2.1 作用

从对象或数组中提取数组,并赋值给变量(多个)

2.2 对象的解构赋值

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo); //aaa
console.log(bar); //bbb

2.3 数组的解构赋值

let [, b, c] = [1, 2, 3];
conssole.log(b) //2
conssole.log(c) //3

2.4 函数参数的解构赋值

//数组
function add([x, y]){
    
    
  return x + y;
}

add([1, 2]); // 3

//对象
function move({
    
    x = 0, y = 0} = {
    
    }) {
    
    
  return [x, y];
}

move({
    
    x: 3, y: 8}); // [3, 8]
move({
    
    x: 3}); // [3, 0]
move({
    
    }); // [0, 0]
move(); // [0, 0]

2.5 剩余运算符

//数组
let [a, ...b] = [1, 2, 3];
console.log(a); //1
console.log(b); //[2,3]

//对象
let {
    
    a, b, ...rest} = {
    
    a: 10, b: 20, c: 30, d: 40};
console.log(a);    //10
console.log(b);    //20
console.log(rest); //{c:30,d:40}

3、模板字符串

3.1 作用

简化字符串的拼接

3.2 使用

必须用 `` 包含,变化的部分用 ${XXX} 定义

// 多行字符串
`In JavaScript this is
 not legal.`

// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${
      
      name}, how are you ${
      
      time}?`

// 调用函数
function fn() {
    
    
  return "Hello World";
}

`foo ${
      
      fn()} bar`
// foo Hello World bar

4、对象的扩展

4.1 简写

4.1.1 属性名简写
function f(x, y) {
    
    
  return {
    
    x, y};
}
// 等同于
function f(x, y) {
    
    
  return {
    
    x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
4.1.2 方法名简写
const person = {
    
    
  sayHi() {
    
    
    console.log("Hi");
  }
}
person.sayHi(); //"Hi"
//等同于
const person = {
    
    
  sayHi: function(){
    
    
    console.log("Hi");
  }
}
person.sayHi(); //"Hi"

4.2 对象的拓展运算符

//复制对象,浅拷贝,改变第一层就有影响
let person = {
    
    name: "Amy", age: 15};
let someone = {
    
     ...person };
console.log(someone);  //{name: "Amy", age: 15}

//可用于合并两个对象,浅拷贝,改变更深层次有影响
let age = {
    
    age: 15};
let name = {
    
    name: "Amy"};
let person = {
    
    ...age, ...name};
console.log(person);  //{age: 15, name: "Amy"}

4.3 新增方法

4.3.1 Object.is()

比较两个值是否严格相等,与严格比较运算符(===)不同之处只有两个

Object.is(+0, -0)   // false
Object.is(NaN, NaN) // true
4.3.2 Object.assign()

合并对象,浅拷贝,改变更深层次有影响

const target = {
    
     a: 1 };
const source1 = {
    
     b: 2 };
const source2 = {
    
     c: 3 };

Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}

如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
4.3.3 Object.getOwnPropertyDescriptor()

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为

获取该属性的描述对象,描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性

let obj = {
    
     foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo') {
    
    
  value: 123,        //属性值
  writable: true,    //属性值为true,说明属性是可以重写的
  enumerable: true,  //属性值为true,说明属性是可以被枚举的
  configurable: true //属性值为true,说明属性是可以被删除或可以被再次修改的
}

有四个操作会忽略enumerable为false的属性:

  1. for…in循环:只遍历对象自身的和继承的可枚举的属性
  2. Object.keys():返回对象自身的所有可枚举的属性的键名
  3. JSON.stringify():只串行化对象自身的可枚举的属性
  4. Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性
4.3.4 Object.defineProperty()

定义或修改一个属性

Object.defineProperty(object, propertyName, attributesObject)
第一个参数是属性所在的对象
第二个参数是属性名
第三个参数是属性的描述对象

let o = Object.defineProperty({
    
    }, 'p', {
    
    
  value: 123,
  writable: false,
  enumerable: true,
  configurable: false
});
console.log(o.p) // 123
o.p = 246;
console.log(o.p) // 123

// 因为writable为false,所以无法改变该属性的值
4.3.5 __proto__属性

读取或设置当前对象的prototype对象

let obj = {
    
    
  money: 5000
}
let son = {
    
    }
son.__proto__ = obj;    //是浅拷贝
console.log(son.money); //5000
4.3.6 Object.keys() Object.values() Object.entries()
  1. Object.keys()

    • 返回一个数组,,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
    let arr = {
          
           foo: 'bar', baz: 42 };
    console.log(Object.keys(arr));// ["foo", "baz"]
    
  2. Object.values()

    • 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值
    let arr = {
          
           foo: 'bar', baz: 42 };
    console.log(Object.values(arr));// ["bar", 42]
    
  3. Object.entries()

    • 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
    let arr = {
          
           foo: 'bar', baz: 42 };
    console.log(Object.entries(arr)); // [ ["foo", "bar"], ["baz", 42] ]
    

5、箭头函数

5.1 使用方法

代码块只有一句时可以省略 {}

5.1.1 一个参数
const f = v => v;

// 等同于
const f = function (v) {
    
    
  return v;
};
5.1.2 没有参数
const f = () => console.log('我是箭头函数');

// 等同于
const f = function () {
    
    
  console.log('我是箭头函数');
};
5.1.3 两个或以上参数
const sum = (num1, num2) => num1 + num2;

// 等同于
const sum = function(num1, num2) {
    
    
  return num1 + num2;
};

5.2 注意点

5.2.1 返回对象处理

由于大括号被解释为代码块,必须在对象外面加上括号,否则会报错

// 报错
let getTempItem = id => {
    
     id, name: "Temp" };

// 不报错
let getTempItem = id => ({
    
     id, name: "Temp" });
5.2.2 this 指向

箭头函数的 this 就是定义时所在的对象,而不是使用时所在的对象

扩展:看外层是否有函数(作用域),如果有,最近的外层函数(作用域)的this指向就是箭头函数的this指向

function Timer() {
    
    
  this.s1 = 0;
  this.s2 = 0;

  // 箭头函数,this 指向 Timer() 函数
  setInterval(() => this.s1++, 1000);

  // 普通函数
  setInterval(function () {
    
    
    this.s2++;
  }, 1000);
}
let timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3000);

setTimeout(() => console.log('s2: ', timer.s2), 3000);
// s1: 3
// s2: 0

//上面代码中,前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)
5.2.3 其他注意点
  1. 不可以当作构造函数
  2. 不可以使用arguments对象
    • 该对象在函数体内不存在。如果要用,可以用 rest 参数代替

5.3 应用场景

当把一个函数当做参数传递给另一个函数的时候,应用场景最广

setTimeout(() => {})

6、三点运算符

6.1 rest 参数

用来取代 arguments ,比 arguments 灵活,只能是最后部分形参参数

特点:arguments 返回的是伪数组,rest 参数返回的是真数组

function fn(...values) {
    
     //定义时前面加三个点
  console.log(values); //使用时直接用
  values.forEach(function(value, index) {
    
    
    console.log(value, index);
  })
}
fn(1, 2, 3)

6.2 扩展运算

填充数组,把 arr1 的值填充到 arr

let arr = [1, 6];
let arr1 = [2, 3, 4, 5];
arr = [1, ...arr1, 6];
console.log(arr); //[1,2,3,4,5,6]
console.log(...arr); //1,2,3,4,5,6

7、Promise对象

Promise: ES6新增的API,是一个构造函数,容器中存放了一个异步任务

Promise 本身不是异步,往往内部都是封装一个异步任务

7.1 作用

将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称“回调地狱”)

7.2 状态

  1. pending(进行中):等待状态,比如正在进行网络请求或者定时器没有到时间
  2. fulfilled (已成功):满足状态,当主动回调了 resolve 时,就处于该状态,并且回调.then()
  3. rejected(已失败):拒绝状态,当主动回调了 reject 时,就处于该状态,并且回调.catch()

Promise对象的状态改变,只有两种可能:从pending变为 fulfilled 和从pending变为rejected

7.3 语法

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署

7.3.1 创建 Promise
const promise = new Promise((resolve, reject) => {
    
    
  if (/* 异步操作成功 */) {
    
    
    //如果 true ,把容器的状态改为 resolve
    resolve(value);
  } else {
    
    
    //如果 false ,把容器的状态改为 reject
    reject(error);
  }
})

resolve函数的作用是:将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数反之;

7.3.2 then 方法

Promise实例生成以后,可以用then方法分别指定resolve状态和reject状态的回调函数

promise.then((value) => {
    
    
  // 成功的回调,接收的就是容器中的 resolve 函数
  // 容器中 resolve 函数传的是什么,这里接收就是什么
  console.log(value)
}, (error) => {
    
    
  // 失败的回调,接收的就是容器中的 reject 函数
  console.log(error)
});
7.3.3 链式写法

假设让下面三个异步操作按顺序执行(异步操作不会因代码写的顺序执行),就用 Promise 嵌套方式

//封装 Promise API
function fzPromise(isFlag,data,err) {
    
    
  return new Promise((resolve, reject) => {
    
    
    if (isFlag) {
    
    
      resolve(data)
    } else {
    
    
      reject(err)
    }
  });
}
const promiseOne = new fzPromise(true,1,'操作失败');
const promiseTwo = new fzPromise(true, 2, '操作失败');
const promiseThree = new fzPromise(false, 3, '操作失败');

promiseOne
  .then((data) => {
    
    
    console.log(data);
    //当 promiseOne 读取成功,当前函数 return 的结果就能在后面的 then 中的回调函数接收到
    return promiseTwo
  },(err) => {
    
    
    console.log(err);
  })
  //这里是 promiseTwo 的 resolve
  .then((data) => {
    
    
    console.log(data);
    return promiseThree
  },(err) => {
    
    
    console.log(err);
  })
  //这里是 promiseThree 的 resolve
  .then((data) => {
    
    
    console.log(data);
  },(err) => {
    
    
    //因为 promiseThree 是 false ,所以结果是 reject 传的 '操作失败'
    console.log(err);
  })
    
//1
//2
//操作失败

7.4 其他方法

7.4.1 Promise.resolve()
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

let thenable = {
    
    
  then(resolve, reject) {
    
    
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
    
    
  console.log(value);  // 42
});

7.4.2 Promise.reject()
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {
    
    
  console.log(s)
})
// 出错了

7.4.3 Promise.all()

用于将多个 Promise 实例,包装成一个新的 Promise 实例, 接受一个数组作为参数, 可以不是数组,但必须具有 Iterator 接口

const p = Promise.all([p1, p2, p3]);

p的状态由p1p2p3决定,分成两种情况

  1. 只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数
  2. 只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
7.4.4 Promise.race()
const p = Promise.race([p1, p2, p3]);

同样是将多个 Promise 实例,包装成一个新的 Promise 实例, 只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

7.4.5 Promise.allSettled()

Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束

8、Symbol 数据类型

ES5 中对象的属性名都是字符串,容易造成重名,污染环境

8.1 特点

  1. Symbol 属性值对应的值是唯一的,解决命名冲突问题
  2. Symbol 值不能与其它数据类型进行计算,包括同字符串拼接
  3. for in ,for of 遍历时不会遍历 Symbol
const obj = {
    
    };
const foo = Symbol('foo');
obj[foo] = 'bar';
for (let i in obj) {
    
    
  console.log(i); // 无输出
}

8.2 使用方法

Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象

8.2.1 带参数
let s1 = Symbol('foo');  //标识
let s2 = Symbol('bar');  //标识
console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
// 如果不加参数,它们在控制台的输出都是Symbol(),不利于区分

8.2.2 不带参数
let s1 = Symbol();
let s2 = Symbol();
console.log(s1) // Symbol()
console.log(s2) // Symbol()
console.log(s1 === s2) // false

8.3 内置的 Symbol 值

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法

8.3.1 Symbol.iterator

指向该对象的默认遍历器方法, 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器

const myIterable = {
    
    };
myIterable[Symbol.iterator] = function* () {
    
    
  yield 1;
  yield 2;
  yield 3;
};

for (let i of myIterable) {
    
    
  console.log(i);
}
//1
//2
//3

console.log([...myIterable]) // [1, 2, 3]

8.4 消除魔术字符串

魔术字符串指的是:在代码之中多次出现,与代码形成强耦合的某一个具体的字符串或者数值

function getArea(shape, options) {
    
    
  let area = 0;
  switch (shape) {
    
    
  case 'Triangle': // 魔术字符串
    area = .5 * options.width * options.height;
    break;
  }
  return area;
}
getArea('Triangle', {
    
     width: 100, height: 100 }); // 魔术字符串

上面代码中,字符串Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护

常用的消除魔术字符串的方法,就是把它写成一个变量

const shapeType = {
    
    
  triangle: Symbol('triangle')
};

function getArea(shape, options) {
    
    
  let area = 0;
  switch (shape) {
    
    
    case shapeType.triangle:
    area = .5 * options.width * options.height;
    break;
  }
  return area;
}

getArea(shapeType.triangle, {
    
     width: 100, height: 100 });

9、Iterator 和 for…of 循环

9.1 概念

遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

9.2 作用

  1. 为各种数据结构,提供一个统一的、简便的访问接口
  2. 使得数据结构的成员能够按某种次序排列
  3. ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费

9.3 遍历过程

  1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
  4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

例子:

function makeIterator(array) {
    
    
  let nextIndex = 0;
  return {
    
    
    next: function() {
    
    
      return nextIndex < array.length ?
        {
    
    value: array[nextIndex++], done: false} :
        {
    
    value: undefined, done: true};
    }
  };
}
var it = makeIterator(['a', 'b']);

console.log(it.next()) // { value: "a", done: false }
console.log(it.next()) // { value: "b", done: false }
console.log(it.next()) // { value: undefined, done: true }

9.4 默认有 Iterator 接口

原生具备iterator接口(即默认部署了Symbol.iterator属性),for...of循环本质上就是调用这个接口产生的遍历器

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
    
    
  console.log(v); // red green blue
}

const obj = {
    
    };
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);

for(let v of obj) {
    
    
  console.log(v); // red green blue
}

10、Generator函数

10.1 概念

Generator 函数是一个状态机,封装了多个内部状态 , 执行 Generator 函数会返回一个遍历器对象 , 可以依次遍历 Generator 函数内部的每一个状态

特征:

  1. function关键字与函数名之间有一个星号
  2. 函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)
function* helloWorldGenerator() {
    
    
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象。必须调用遍历器对象的next方法,使得指针移向下一个状态, 直到遇到下一个yield表达式(或return语句)为止

写法:

function * foo(x, y) {
    
     ··· }
function *foo(x, y) {
    
     ··· }
function* foo(x, y) {
    
     ··· } //通用
function*foo(x, y) {
    
     ··· }

10.2 yield 表达式

只能用在 Generator 函数里面,用在其他地方都会报错

与 return 的区别:

  • 相似之处在于,都能返回紧跟在语句后面的那个表达式的值
  • 区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能
  • 一个函数里面,只能执行一次 return语句,但是可以执行多次 yield表达式

位置

yield表达式如果用在另一个表达式之中,必须放在圆括号里面

console.log('Hello' + (yield));

yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号

let input = yield; 

10.3 next 方法的参数

yield表达式本身没有返回值,或者说总是返回undefinednext方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值

function* foo(x) {
    
    
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);       
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}   返回 5 + 1,即 6
a.next() // Object{value:NaN, done:false} 返回 2 * undefined / 3,即 NaN
a.next() // Object{value:NaN, done:true}  返回 5 + NaN + undefined,即 NaN

var b = foo(5);
b.next() // { value:6, done:false }   返回 5 + 1,即 6
b.next(12) // { value:8, done:false } 返回 2 * 12 / 3,即 8
b.next(13) // { value:42, done:true } 返回 5 + 24 + 13,即 42

10.4 应用

  1. 异步操作的同步化表达

    //封装异步操作
    function getNews(url) {
          
          
      $.get(url, function(res) {
          
          
        let url = 'http://localhost:8080' + res.commentsUrl; //第二次请求地址
        SX.next(url); //调用第二个 yield ,把拿到的第二次请求地址当参数传入
      })
    }
    
    function* sendXml() {
          
          
      let url = yield getNews('http://localhost:8080?id=3'); //第一次请求
      yield getNews(url); //发送第二次请求
    }
    
    let SX = sendXml();
    SX.next();
    
    
  2. 部署 Iterator 接口

    • 利用 Generator 函数,可以在任意对象上部署 Iterator 接口
    function* iterEntries(obj) {
          
          
      let keys = Object.keys(obj);
      for (let i=0; i < keys.length; i++) {
          
          
        let key = keys[i];
        yield [key, obj[key]];
      }
    }
    
    let myObj = {
          
           foo: 3, bar: 7 };
    
    for (let [key, value] of iterEntries(myObj)) {
          
          
      console.log(key, value);
    }
    
    // foo 3
    // bar 7
    
    

11、async 函数

11.1 改进

async函数对 Generator 函数的改进,体现在以下四点

  1. 内置执行器
    • 调用就执行, 不像 Generator 函数,需要调用next方法
  2. 更好的语义
    • async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果
  3. 更广的适用性
  4. 返回值是 Promise
    • Generator 函数的返回值是 Iterator 对象, async函数可以用then方法指定下一步的操作

11.2 基本用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

async function getNews(url) {
    
    
  return new Promise((resolve, reject) => {
    
    
    $.ajax({
    
    
      type: "get",
      url,
      success: data => {
    
    
        resolve(data)
      }
    });
  })
}

async function sendXml() {
    
    
  let result = await getNews('http://localhost:8080?id=3'); //第一次请求
  result = await getNews('http://localhost:8080?id=3' + result.commentsUrl); //第二次请求
}
sendXml();

12、Module (模块)

12.1 与 CommonJS 模块的差异

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

12.2 优点

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

12.3 export 与 import

  1. 变量名导出
export.js =>   //公用的 js 
//export 用于导出
export let uname = 'zhangsan';  
export let age = 18;  

import.js =>
//import 用于导入
import {
    
    uname,age} form './export.js'
console.log(`我叫${
      
      uname},今年${
      
      age}`) //我叫zhangsan,今年18

  1. 花括号导出
export.js =>   //公用的 js 
//export 用于导出
let uname = 'zhangsan';  
let age= 18; 
export {
    
    uname,age}

import.js =>
//import 用于导入
import {
    
    uname as myname,age} form './export.js'
console.log(`我叫${
      
      myname},今年${
      
      age}`) //我叫zhangsan,今年18

  1. 对象型导出
export.js =>   //公用的 js 
//export 用于导出
let obj = {
    
    
  uname : 'zhangsan'. 
  age: 18; 
} 
export {
    
    obj}
  
import.js =>
//import 用于导入
import {
    
    obj} form './export.js'
obj.age = 50;
console.log(obj) 
//
{
    
    
  uname : 'zhangsan'. 
  age: 50; 
} 

  1. script 标签使用

    //module.js
    export default function test(){
          
          
      return 'test...'
    }
    
    // index.js
    import test from './module.js';
    console.log(test())
    
    // 方法 1 : 引入module.js,然后在script标签里面调用
    <script type="module">
      import test from './module.js';
      console.log(test())
    </script>
    
    // 方法 2 : 直接引入index.js,使用src引入
    <script type="module" src="./index.js"></script>
    
    
  2. 默认导出

    export default //由导入的地方起名字
    
    

13、Set 和 Map

13.1 Set

无序的不可重复的多个 value 的集合体,似于数组

13.1.1 基本用法
  1. 创建 new Set(Array)

    let set = new Set([1,3,2,5,6,3]);
    console.log(set); //Set(5) {1,3,2,5,6}
    
    
  2. 添加 add(value)

    let set = new Set([1,3,2,5,6,3]);
    set.add(7)
    console.log(set); //Set(6) {1,3,2,5,6,7}
    
    
  3. 删除 delete(value)

    let set = new Set([1,3,2,5,6,3]);
    set.delete(3)
    console.log(set); //Set(4) {1,2,5,6}
    
    
  4. 检索 has(value)

    let set = new Set([1,3,2,5,6,3]);
    console.log(set.has(3)); //true
    console.log(set.has(8)); //false
    
    
  5. 清除 clear()

    let set = new Set([1,3,2,5,6,3]);
    set.clear();
    console.log(set); //Set(0) {}
    
    
  6. 数据长度 size

    let set = new Set([1, 3, 2, 5, 6, 3]);
    console.log(set.size); //5
    
    
13.1.2 应用

去除数组的重复成员

let arr = [1, 2, 4, 4, 1, 3];
let newArr = [...new Set(arr)]
console.log(newArr);  //[1,2,4,3]

13.2 Map

无序的 key 不重复的多个 key-value 的集合体

13.2.1 基本用法
  1. 创建 new Map(Array)

    //数组里套数组,1,2是 key,名字是 value
    let map = new Map([[1,'zhangsan'],[2,'lisi']]); 
    console.log(map); //Map(2) {1 => "zhangsan", 2 => "lisi"}
    
    
  2. 添加 set(key,value)

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ]);
    map.set(3, 'wangwu')
    console.log(map); //Map(3) {1 => "zhangsan", 2 => "lisi", 3 => "wangwu"}
    
    
  3. 检索 get(key)

    返回检索到的元素,没有返回 undefined

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ])
    console.log(map.get(2)) //lisi
    
    
  4. 检索 has(key)

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ])
    console.log(map.has(2)) //true
    
    
  5. 删除 delete(key)

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ]);
    map.delete(2)
    console.log(map); //Map(1) {1 => "zhangsan"}
    
  6. 清除 clear()

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ]);
    map.clear()
    console.log(map); //Map(0) {}
    
  7. 数据长度 size

    let map = new Map([
      [1, 'zhangsan'],
      [2, 'lisi']
    ]);
    console.log(map.size); //2
    

猜你喜欢

转载自blog.csdn.net/weixin_44257930/article/details/109012573