[关闭]
@octopus 2020-08-06T13:50:55.000000Z 字数 15119 阅读 373

ES6

es6


进度:2.18-2.26_52studyit.com

1. var / let / const

  1. var a = 1
  2. b = 2
  3. window.c = 3
  4. let d = 4
  5. const e = 4
  1. // 例一
  2. function test(){
  3. var a = 1
  4. if(a===1){
  5. var b = 2
  6. }
  7. console.log(a+b) // 3
  8. }

因为变量提升,上述代码实际被编译成:

  1. function test(){
  2. var a = 1
  3. var b
  4. if(a===1){
  5. b = 2
  6. }
  7. console.log(a+b) // 3
  8. }

所以最后能取到b,打印出 a+b 的值。

  1. // 例二
  2. function test(){
  3. var a = 1
  4. if(a===1){
  5. let b = 2
  6. }
  7. console.log(a+b) // b is not defined
  8. }

let 声名的变量是块级作用域,仅在 {}中生效,不存在变量提升,所以外层获取不到 b

  1. // 例三
  2. const b
  3. b = 1 // Missing initializer in const declaration

常量在初始化时必须赋值

2. Array

数组遍历的n种方式

for

  1. //1
  2. var arr = [1,2,3,4]
  3. for(let i = 0; i<arr.length ; i++){
  4. if(arr[i]===2){
  5. continue
  6. }
  7. console.log(arr[i])
  8. }

forEach

  1. //2
  2. var arr = [1,2,3,4]
  3. arr.forEach(function (item) { // 此方法不支持 continue 与 break,只能完全遍历
  4. console.log(item)
  5. })

every

  1. //3
  2. var arr = [1,2,3,4]
  3. arr.every(function (item) {
  4. if(item !== 2){
  5. console.log(item)
  6. }
  7. return true // 只有 return true 才能继续遍历
  8. })

for in

  1. //4
  2. var arr = [1,2,3,4]
  3. for(let index in arr){
  4. if(arr[index]===2){
  5. continue
  6. }
  7. console.log(arr[index]);
  8. }

for of

  1. //5
  2. var arr = [1,2,3,4]
  3. for(let item of arr){
  4. console.log(item)
  5. }

for in 的坑

坑1:for in 不仅能打印数组值,还能打印属性。

for in 不是为数组准备的遍历功能,是为遍历对象而生,因为数组是对象,所以也可以用 for in 遍历。

数组是对象,所以也可以为它加属性:

  1. var arr = [1,2,3,4]
  2. arr.a = 8 // 加上自定义属性 a
  3. for(let index in arr){
  4. console.log(index, arr[index]);
  5. }
  6. 输出:
  7. 0 1
  8. 1 2
  9. 2 3
  10. 3 4
  11. a 8

坑2:for(let index in arr) 中的 index 是字符串类型

  1. var arr = [1,2,3,4]
  2. for(let index in arr){
  3. if(index === 1){
  4. continue
  5. }
  6. console.log(arr[index]);
  7. }
  8. 输出:1,2,3,4
  9. var arr = [1,2,3,4]
  10. for(let index in arr){
  11. if(index*1 === 1){ // *1强制转化为数字后即可
  12. continue
  13. }
  14. console.log(arr[index]);
  15. }

for of

es6及其以后可以自定义可遍历结构,也就是不止数组是可遍历对象,这时就不能用 for、forEach、every、for in等。

for of 就是为包括自定义的可遍历对象而生的

伪数组如何转换成数组

Array.from

  1. {0:"a",1:"b",length:2}
  2. {length:5} // 可以理解为5个索引元素的值都是空
  1. es5: [].slice.call(arrayLike)
  2. es6: Array.from(arrayLike, mapFunc, thisArg)

集合/nodeList 都是伪数组,满足上述两种特性,看起来像数组但用不了数组的api

  1. // 获取页面中所有的 img,返回一个 modeList
  2. document.querySelectorAll("img")
  3. NodeList [img]length: 10: imgalt: ""src: "http://localhost:8080/es2019.jpg"...
  4. // 转换为数组
  5. es5:
  6. let imgs = [].slice.call(document.querySelectorAll("img"))
  7. es6:
  8. let imgs = Array.from(document.querySelectorAll("img"))

如何初始化一个长度n,值都是1的数组?

Array.from() & Array.fill()

es5的老办法:

  1. let arr = Array(n);
  2. for(let i = 0; i<arr.length; i++){
  3. arr[i] = 1
  4. }

es6:

  1. let arr = Array.from({length:n}, function () {return 1})
  2. let arr = Array(n).fill(1)

如何生成新数组

es5:

  1. var arr = Array()
  2. var arr = []

es6:

  1. let arr = Array.of(1,2); // [1,2]
  2. let arr = Array(5).fill(1)

Array.of

  1. Array(7); // [ , , , , , , ]
  2. Array.of(7); // [7]
  3. Array.of(1, 2, 3); // [1, 2, 3]
  4. Array(1, 2, 3); // [1, 2, 3]

Array.fill()

可以填充数组,也可以批量改变数组的值。

  1. // 填充数组
  2. let arr = Array(5).fill(1)
  3. // 批量改变数组值
  4. let arr = [1,2,3,4,5,6]
  5. let arr2 = arr.fill(8,1,3) // 将第1-3(包含头不包含尾)的元素值改成8
  6. console.log(arr2) // [1, 8, 8, 4, 5, 6]

如何查找数组中值为n的元素?

Array.find() & Array.findIndex()

es5:

  1. // 将 return true 的所有元素以数组格式返回,缺点是,如果只想知道是否存在一个元素,filter找到后依然会遍历所有元素,这并不高效
  2. Array.filter(function(){})

es6:

  1. // 将 return true 的第一个值返回,关注的是有或没有,找到了就返回值,没找到就返回undefined
  2. Array.find(function(){})
  3. // 返回第一个 return true 的元素位置
  4. Array.findIndex(function(){})

举个例子:

  1. // filter
  2. let arr = [1,2,3,4,5,4]
  3. let find = arr.filter(function (item) {
  4. return item === 4
  5. })
  6. console.log(find) // [4, 4]
  7. // find
  8. let arr = [1,2,3,4,5,4]
  9. let find = arr.find(function (item) {
  10. return item === 4
  11. })
  12. console.log(find) // 4
  13. // findIndex
  14. let arr = [1,2,3,4,5,4]
  15. let find = arr.findIndex(function (item) {
  16. return item === 4
  17. })
  18. console.log(find) // 3

3. Class

如何初始化一个类?

es5:

  1. let Animal = function (type) {
  2. this.type = type
  3. this.eat = function () {
  4. console.log(this.type+"正在吃...")
  5. }
  6. }
  7. let dog = new Animal("dog");
  8. let cat = new Animal("cat");

new 发生了什么?

1. 隐式地创建一个空对象 obj = {}
2. Animal.call(obj,type), 将 this 指向的作用域变成 obj,并初始化,则 obj 有了 Animal 初始化后的的所有属性和方法。(值拷贝)
3. obj.__proto__= Animal.prototype,将原型链指向函数,存的是引用地址。(prototype属性,可以返回对象的 原型对象 的引用。)
4. 返回obj对象

这就导致,每生成一个类,都完全复制了一份父类,使占用的空间变的很大,且 eat 本是想作为一个父类的公共方法,new 以后却变成了每个子类的"私有"方法。

什么是原型链?

对象就像是一个封装好的盲盒,盲盒里有图纸,和一张说明。图纸谁拿到了都可以修改,但是说明只有盲盒本盒才有权改(盲盒可读可写,其他人只读)。
  1. A = function(){ // 这是盲盒 A
  2. this.type = "flower" // 图纸,可以生产花
  3. }
  4. A.prototype // 这是盲盒 A 里的说明
  5. A.prototype.warning = "不可以生产蓝花" // 在说明里新增一条注意事项
说明上都记录着什么呢?
  1. console.log(A.prototype)
  2. // 结果:
  3. warning: "不可以生产蓝花"
  4. constructor: ƒ ()
  5. length: 0
  6. name: "A"
  7. arguments: null
  8. caller: null
  9. prototype: {constructor: ƒ}
  10. __proto__: ƒ ()
  11. [[FunctionLocation]]: VM64:1
  12. [[Scopes]]: Scopes[2]
  13. __proto__:
  14. constructor: ƒ Object()
  15. __defineGetter__: ƒ __defineGetter__()
  16. __defineSetter__: ƒ __defineSetter__()
  17. hasOwnProperty: ƒ hasOwnProperty()
  18. __lookupGetter__: ƒ __lookupGetter__()
  19. __lookupSetter__: ƒ __lookupSetter__()
  20. isPrototypeOf: ƒ isPrototypeOf()
  21. propertyIsEnumerable: ƒ propertyIsEnumerable()
  22. toString: ƒ toString()
  23. valueOf: ƒ valueOf()
  24. toLocaleString: ƒ toLocaleString()
  25. get __proto__: ƒ __proto__()
  26. set __proto__: ƒ __proto__()
记录着涂鸦(warning),盲盒本身(指针指向外层)(constructor) ,盲盒来源的说明的地址(__proto__)

有了盲盒,就有了可以使用盲盒生产东西的工厂,开工厂就一个条件,要有使用的盲盒说明的地址。
现在有一个工厂 a 想用图纸 A 生产花,生产红色的花,于是 a 打开了盲盒,复印并修改了盲盒图纸,同时按照要求挂上了使用的盲盒说明的地址。
  1. let a = new A()
  2. a.type = "red flower"
  3. consloe.log(a);
  4. // 打印结果:
  5. type: "red flower" // 工厂生产的东西
  6. __proto__: // 盲盒的说明
  7. warning: "不允许狗进入"
  8. constructor: ƒ () // 盲盒本身
  9. length: 0
  10. name: "A"
  11. arguments: null
  12. caller: null
  13. prototype: {warning: "不允许狗进入", constructor: ƒ} // 盲盒的说明
  14. __proto__: ƒ ()
  15. [[FunctionLocation]]: test.js:1
  16. [[Scopes]]: Scopes[2]
  17. __proto__: // 盲盒的来源的说明
  18. ...
所以假如 a 不禁想修改图纸,还想修改说明上的涂鸦,让所有工厂都改变这个涂鸦,就要联系盲盒本盒:

a.constructor.prototype.warning = "允许狗进入"

因为当获取一个属性,而本身找不到时,就会自动去来源处寻找,所以 a 本身并没有constructor方法,程序会自动去 __proto__ 中找到,父级依然没有的话,会一直向上找。

了解了原型链后,该如何解决公共方法的问题?—— 将共有属性和方法,放在原型链中,实例化时不会拷贝,调用时会顺着 __proto__ 指向的地址去找
  1. let Animal = function (type) {
  2. this.type = type
  3. }
  4. Animal.prototype.eat = function () {
  5. console.log(this.type+"正在吃...")
  6. }
  7. let dog = Animal("dog");
  8. let cat = Animal("cat");

es6:

  1. class A {
  2. constructor (type) {
  3. this.type = type
  4. }
  5. eat(){
  6. console.log(this.type+"正在吃...")
  7. }
  8. }
  9. let dog = new A("dog");
  10. let cat = new A("cat");
  11. console.log(dog);
  12. A {type: "dog"}
  13. type: "dog"
  14. __proto__:
  15. eat: ƒ eat()
  16. constructor: class A
  17. __proto__: Object

打印 dog 以后会发现,结果和上面讲的原型链一模一样,所以其实 es6 的 class 就是 es5 原型链写法的语法糖,自动帮我们实现了挂载prototype的操作而已。

如何设置私有属性?

在es5中设置私有属性几乎是不可能实现的,外部很容易就对私有属性进行了修改:

  1. let A = function (type) {
  2. this.type = type
  3. }
  4. let a = new A("dog")
  5. console.log(a.type) // dog
  6. a.type = "cat"
  7. console.log(a.type) // cat

es6中设置私有属性:

  1. class A {
  2. get number(){
  3. return 1
  4. }
  5. }
  6. let a = new A()
  7. console.log(a.number) // 1
  8. a.number = 2
  9. console.log(a.number) // 1

get 后的函数名,是类的私有变量,返回值不会在外部被改变。同理,还有 set 可以在内部改变私有属性

  1. let _number = 1
  2. class A {
  3. get number(){
  4. return _number
  5. }
  6. set number(val){
  7. if(val<10){
  8. _number = val
  9. }
  10. }
  11. }
  12. let a = new A()
  13. console.log(a.number) // 1
  14. a.number = 2
  15. console.log(a.number) // 2
  16. a.number = 11
  17. console.log(a.number) // 1
  18. console.log(a._number) // undefined

注意,在 set 中,不可以写 this.number = xxx 这样就形成了死循环,调用了 set ,set中再调用set...
所以只能用一个别名变量来存储私有变量的值,并且别名变量要在 class 外部,这样就不属于类的属性,实例不会获取到。

如何声明一个静态方法?

静态方法是类方法,实例不可以调用,要用类名调用。

es5:

  1. let A = function () {
  2. }
  3. A.eat = function () {
  4. console.log("eating...")
  5. }
  6. let a = new A();
  7. a.eat(); // x 报错:a.eat is not a function
  8. A.eat(); // 正确

es6:

  1. class A {
  2. constructor (type) {
  3. this.type = type // constructor声明的是私有属性和方法
  4. }
  5. eat(){ // 原型链上的父类方法
  6. console.log(this.type+"正在吃...")
  7. }
  8. static talk(){ // static 的是静态方法
  9. console.log("正在说话...")
  10. }
  11. }
  12. A.talk()

如何继承一个类?

es5:

  1. let A = function (type) {
  2. this.type = type
  3. this.walk = function () {
  4. console.log("walking")
  5. }
  6. }
  7. A.prototype.eat = function () {
  8. console.log("eating")
  9. }
  10. let B = function () {
  11. A.call(this, "B") // 先执行父类的构造函数,把父类的东西挪到自己身上
  12. }
  13. B.prototype = A.prototype // 和父类公用一个原型链
  14. let b = new B();
  15. console.log(b) // 成功继承

es6:

  1. // es6 的继承很简单,需要关键字 extends
  2. class A {
  3. constructor (type) {
  4. this.type = type
  5. }
  6. eat(){
  7. console.log(this.type+"正在吃...")
  8. }
  9. static talk(){
  10. console.log("正在说话...")
  11. }
  12. }
  13. class B extends A{ // 继承 A
  14. }
  15. let b = new B("b");
  16. b.eat() // 即可调用父类方法
  17. B.talk() // 父类静态方法

当子类需要实现自己的构造函数时,需要显示调用父类构造方法。

  1. class B extends A{
  2. constructor (type, voice) {
  3. super(type); // 显示调用父类构造方法
  4. this.voice = voice
  5. }
  6. }
  7. let b = new B("b","wangwang");
  8. b.eat()
  9. B.talk()

4. function 函数

如何设置函数参数的默认值?

es5:

  1. function test (a, b, c) {
  2. if (b === undefined){
  3. b = 1
  4. }
  5. if (c === undefined){
  6. c = 2
  7. }
  8. return a + b + c
  9. }
  10. console.log(test(0)) // 3

es6:

  1. function test (a, b=1, c=2) {
  2. return a + b + c
  3. }
  4. console.log(test(0)) // 3

问题:如果只想传 a , c ,还是让 b 保持默认值怎么办呢?

用 undefined 解决,回头看 es5 的方法,就会理解,当传入undefined,函数会认为是缺省,则会触发缺省值

  1. function test (a, b=1, c=2) {
  2. return a + b + c
  3. }
  4. console.log(test(0, undefined, 10)) // 11

如何获取函数参数个数?

es5: 在函数内部通过 arguments 获取传进来的参数 ( 但是 es6 已经被禁止使用 )

  1. function test (a=0, b=1, c=2) {
  2. console.log(arguments)
  3. return a + b + c
  4. }
  5. test(10,10)
  6. 结果:
  7. // 是一个 Arguments 对象
  8. Arguments(2) [1, undefined, callee: (...), Symbol(Symbol.iterator): ƒ]
  9. callee: (...)
  10. 0: 10
  11. 1: 10
  12. length: 2
  13. Symbol(Symbol.iterator): ƒ values()
  14. get callee: ƒ ()
  15. set callee: ƒ ()
  16. __proto__: Object

可见 Arguments 对象有长度,有索引,所以——

  1. function test (a=0, b=1, c=2) {
  2. let arg = Array.from(arguments) // 将伪数组转换为数组
  3. console.log(arg) // [10, 10]
  4. return a + b + c
  5. }
  6. test(10,10)

所以通过 arguments 可以轻松获取到函数 传入参数 的个数和值 (不是定义的参数的个数和值)

es6:

函数名.length 可以获取到函数定义参数,且没有默认值的参数个数

  1. function test (a=0, b=1, c=2) {
  2. console.log(test.length) // 0 因为三个全是有默认值的
  3. return a + b + c
  4. }
  5. test(10,10)

析构与解构

...nums... 表示将所有参数写到 nums 数组中

  1. function sum (...args) {
  2. let res = 0
  3. args.forEach(function (item) {
  4. res += item
  5. })
  6. return res
  7. }
  8. console.log(sum(10,10)) // 20

同理, ... 能把 n 个参数放进一个变量数组里,也能把变量数组,拆分到n个参数里

  1. function sum (x, y, z) {
  2. return x + y + z
  3. }
  4. let nums = [1,2,3]
  5. let res = sum(...nums) // 6

注意: ...atgs 只能在函数的参数括号中使用,用来聚合和解构数组,其他地方使用会报错

  1. let a,b,c = ...[1,2,3] // xxxxxx 这是错的!!!

箭头函数

()=>{}

es5声明一个函数:

  1. let a = function () {
  2. console.log("hello world")
  3. }
  4. a()

es6 箭头函数:

  1. let a = () => {
  2. console.log("hello world")
  3. }
  4. a()

箭头函数的参数

当没有参数,和有两个及其以上参数的时候,必须带(),当只有一个参数时,可以不加()

  1. let a = () => {
  2. console.log("hello world")
  3. }
  4. let a = (x,y) => {
  5. console.log(x,y)
  6. }
  7. let a = x => {
  8. console.log(x)
  9. }

箭头函数的返回值

箭头函数的 => 后,可以是一个函数体,可也以是一句话表达式

  1. // 一句话表达式,不用加函数体 {},也不用写 return,会自动计算返回
  2. let a = (x, y) => x + y
  3. // 等同于:
  4. let a = (x, y) => {
  5. return x + y
  6. }
  7. // 利用一句话表达式直接返回一个数组
  8. let a = (x,y) => [x,y]

如果想返回一个对象呢?

  1. // 这是错的
  2. let a = (x, y) => { // 程序会把 {} 认为是函数体的开始和结束符号
  3. "x" : x, // 这是啥?程序会报错
  4. "y" : y
  5. }
  6. // 这是对的
  7. let a = (x,y) => ( // () 可以认为是一个表达式的孵化器,像 (x+y)*2 一样,只是给必要的表达式提供一个环境
  8. {
  9. "x" : x,
  10. "y" : y
  11. }
  12. )
  13. // 最笨的办法
  14. let a = (x, y) => {
  15. return {
  16. "x" : x,
  17. "y" : y
  18. }
  19. }

箭头函数的作用域

es5 的普通函数:

  1. let test = {
  2. name : "test",
  3. func : function () {
  4. console.log(this.name)
  5. }
  6. }
  7. test.func() // test

输出了 test ,因为 func 内的 this 指向的是调用者的作用域,就是 test 对象

es6 的箭头函数:

  1. let test = {
  2. name : "test",
  3. func : () => {
  4. console.log("name:" + this.name)
  5. }
  6. }
  7. test.func() // undefined

由于简单对象(非函数)是没有执行上下文的,所以上例中只能到最外层 windows 中找name属性,结果是 undefined。

  1. var x = 11;
  2. var obb = {
  3. x: 222,
  4. y: {
  5. x:333,
  6. obc: function f() {
  7. console.log(this)
  8. var x = 111;
  9. var obj = {
  10. x: 22,
  11. say: () => {
  12. console.log(this.x);
  13. }
  14. }
  15. obj.say()
  16. }
  17. }
  18. }
  19. obb.y.obc() // 333

此处一直向上找有上下文的this,终于在函数中找到了,而函数中的 this 指向的是调用它的对象。

传统函数:this指向调用它的对象。 链接
箭头函数:this指向被定义时的上下文中的this。

5. 对象

属性的简写

es5:

  1. let a = 1;
  2. let b = 2;
  3. let obj = {
  4. a : a,
  5. b : b
  6. }
  7. console.log(obj) // {a: 1, b: 2}

es6:

  1. let a = 1;
  2. let b = 2;
  3. let obj = {
  4. a,
  5. b
  6. }
  7. console.log(obj) // {a: 1, b: 2}

当变量名是 key 时,可以简写。

key 表达式

当key是动态生成的,或是一个变量的值,es6支持将变量/表达式作为 key进行解析

es5:

  1. let c = "123"
  2. let obj = {
  3. a : "a",
  4. b : "2"
  5. }
  6. obj[c] = "3"
  7. console.log(obj) // {123: "3", a: "a", b: "2"}

es6:

  1. let c = "123"
  2. let obj = {
  3. a : "a",
  4. b : "2",
  5. [c] : "3"
  6. }
  7. console.log(obj) // {123: "3", a: "a", b: "2"}
  8. // 也可以是表达式
  9. let a = 1;
  10. let b = 2;
  11. let obj = {
  12. [a+b] : "3"
  13. }
  14. console.log(obj) // {3: "3"}

对象中函数的简化

es5:

  1. let obj = {
  2. hello : function(){
  3. console.log("hello");
  4. }
  5. }
  6. obj.hello()

es6:

  1. let obj = {
  2. hello(){
  3. console.log("hello");
  4. }
  5. }
  6. obj.hello()

6. Set

set 是 es6 新增的一种数据结构,存储的成员是唯一的,不可重复。set有增删查的成员方法,没有修改方法,如果想修改建议先删除,再添加。

  1. // 初始化
  2. let s = new Set();
  3. // 初始化并赋值,值不仅可以是数组,凡是可遍历对象都可以
  4. let s = new Set([1,2,3,4]);

add

向set中添加数据

  1. let s = new Set();
  2. s.add("hello");
  3. // 可以链式操作,因为元素唯一性,最终只有一个www
  4. s.add("www").add("aaa").add("www");
  5. console.log(s); // Set(3) {"hello", "www", "aaa"}

delete

删除元素,返回 true/false

  1. s.delete("hello"); // Set(2) {"www", "aaa"}

clear

全部清空(删除)

  1. s.clear(); // Set(0) {}

has

元素是否存在

  1. let s = new Set([1,2,3,4]);
  2. let res = s.has(2); // true
  3. let res = s.has(10); // false

size

元素个数

  1. let s = new Set([1,2,3,4]);
  2. let size = s.size // 4

遍历元素

  1. let s = new Set(["a","b","c","d"]);
  2. let keys = s.keys () // SetIterator {"a", "b", "c", "d"}
  3. let values = s.values() // SetIterator {"a", "b", "c", "d"}
  4. let entries = s.entries() // SetIterator {"a" => "a", "b" => "b", "c" => "c", "d" => "d"}

可以看到,本质上也是一个对象,拥有键值

keys 返回了 set 的所有key的可遍历对象(SetIterator)
values 返回了 set 的所有值的可遍历对象
entries 返回了 set 的键值对的可遍历对象

7. Map

es6新增的一种数据结构,用来存储键值对。任何类型都可以作为键,比如函数。

初始化时传值为一个可遍历对象,对象的各个值要有 键和值

  1. let m = new Map();
  2. let m = new Map([ ["a",1], ["b",2] ]); // {"a" => 1, "b" => 2}

set

添加/修改键值对

  1. let m = new Map();
  2. m.set("a", 1);
  3. m.set("b", 2); // Map(2) {"a" => 1, "b" => 2}
  4. // set 不仅可以添加,还可以用来修改
  5. m.set("a", "aaa"); // Map(2) {"a" => "aaa", "b" => 2}

delete

删除键值对,传入key,返回 true/false

  1. m.delete("a")
  2. console.log(m) // Map(1) {"b" => 2}

clear

全部清空(删除)

  1. m.clear(); // Map(0) {}

size

元素个数

  1. let m = new Map([ ["a",1], ["b",2] ]);
  2. let size = m.size // 2

has

查询 key 是否存在

  1. let m = new Map([ ["a",1], ["b",2] ]);
  2. m.has("c") // false
  3. m.has("a") // true

get

  1. let m = new Map([ ["a",1], ["b",2] ]);
  2. m.get("c") // undefined
  3. m.has("a") // 1

遍历元素

  1. let m = new Map([ ["a",1], ["b",2] ]);
  2. let keys = m.keys () // MapIterator {"a", "b"}
  3. let values = m.values() // MapIterator {1, 2}
  4. let entries = m.entries() // MapIterator {"a" => 1, "b" => 2}

keys 返回了 Map 的所有key的可遍历对象(SetIterator)
values 返回了 Map 的所有值的可遍历对象
entries 返回了 Map 的键值对的可遍历对象

  1. for( let [key, v] of m ){
  2. console.log(key, v);
  3. }
  4. // a 1 b 2

8. 对象拷贝

  1. const target = {}
  2. const source = {"a":1,"b":2}
  3. Object.assign(target, source)
  4. console.log(target) // {"a":1,"b":2}

9. templete

es5

  1. const a = 1;
  2. const b = 2;
  3. const res = 'res is '+(a+b)+' .'; // "res is 3 ."

es6

  1. const a = 1;
  2. const b = 2;
  3. const c = 'hello world'
  4. const res = `${c} res is ${a+b}` // "hello world res is 3"

函数模板

功能实现:当a=1时,输出“单价为1”,当a=2时,输出“单价为2”

es5

  1. function echoPrice(a){
  2. if(a===1){
  3. return "单价为1"
  4. }else if(a===2){
  5. return "单价为2"
  6. }
  7. }
  8. console.log( echoPrice() );

es6

  1. function Price(strings, a){
  2. let temp = strings[0]
  3. return temp+a;
  4. }
  5. let res = Price`单价为${1}` // "单价为1"
  6. let res = Price`单价为${2}` // "单价为2"

函数名后接模板,会将由变量分割的字符串数组作为第一个参数传入函数,之后的参数依次是变量。

10. 解构赋值

  1. let arr = ["hello", "world", "1"];
  2. let [a, b, c] = arr;
  3. console.log(a, b, c) // "hello", "world", "1"
  4. let [a, , c] = arr; // // "hello", "1"

解构不仅可以对数组,凡是可遍历对象都可以

  1. let [a,b] = 'hello'
  2. console.log(a, b) // h,e
  3. let [a,b] = new Set([1,2,3]);
  4. console.log(a, b) // 1,2

解构赋值还可以修改对象值

  1. let obj = {"a":1, "b":2}; // 这里结束要加分号,与解构语句隔开
  2. [obj.a, obj.b] = [3,4]
  3. console.log(obj) // {a: 3, b: 4}

将解构用到遍历对象上

  1. let obj = {"a":1, "b":2};
  2. for( let [key,v] of Object.entries(obj) ){
  3. console.log(key,v);
  4. }

收集其他变量

  1. let arr = ["hello", "world", "1",2,3,4];
  2. let [a, b, ...others] = arr
  3. console.log(others) // ["1", 2, 3, 4]

获取对象值

解构中的变量名默认为对象key,若要新起一个变量名,要写全 key:new_name

  1. let option = {
  2. "a" : "aa",
  3. "b" : "bb",
  4. "c" : "cc"
  5. };
  6. let {a:a_value, b, c} = option;
  7. console.log(a_value, b, c) // aa bb cc

获取复杂对象值

解构时要和被解构变量保持一致的结构

  1. let res = {
  2. "code" : 200,
  3. "data" : [
  4. {
  5. "name" : "zhang",
  6. "age" : "20"
  7. }
  8. ]
  9. }
  10. let {code, data:[{name, age}]} = res
  11. console.log(code, name, age) // 200 "zhang" "20"

11. export

导出变量

使用 export 可以导出任何结构,如变量,方法

  1. // 1.js
  2. export const name = "hello"
  3. export let addr = "beijing"
  4. export let arr = [1,2,3]
  5. // 2.js
  6. import { name,addr,arr } from './1.js'
  7. console.log(name,addr,arr) // hello, beijing, [1,2,3]

多个待导出变量/方法一起导出

  1. let a = "1";
  2. let b = "2";
  3. export{
  4. a,
  5. b
  6. }

默认导出

使用 default 来默认导出,导入时不需要放到花括号中。每个模块只可以有一个默认导出。由于只有一个默认导出,所以导入时可以随便给默认变量起名字。

  1. // 1.js
  2. const name = "hello"
  3. export default name;
  4. // 2.js
  5. import name from './1.js'
  6. import name2 from './1.js' // 也可以更换变量名
  7. -----
  8. // 1.js
  9. const name = "hello";
  10. let a = "1";
  11. let b = "2";
  12. export default name;
  13. export {
  14. a,
  15. b
  16. }
  17. // 2.js
  18. import name,{a,b} from './1.js'

如果非默认导出变量也像改名,那么可以用 as

  1. // 1.js
  2. let a = "1";
  3. let b = "2";
  4. export {
  5. a,
  6. b
  7. }
  8. // 2.js
  9. import {a as a2, b as b2} from './1.js'

导出方法

  1. // 1.js
  2. export function say(){
  3. console.log("hi");
  4. }
  5. export function run(){
  6. console.log("run");
  7. }
  8. export default function eat(){
  9. console.log("eat");
  10. }
  11. // 2.js
  12. import eat,{say,run} from './1.js'
  13. say();
  14. run();
  15. eat();

同理也可以把函数放在一起导出

  1. const eat = () =>{
  2. console.log("eat");
  3. }
  4. const run = () =>{
  5. console.log("run");
  6. }
  7. export{
  8. eat,
  9. run
  10. }

导出对象

  1. // 这样做是错的,导出的最外层也是一个对象,要求值是 key-value形式,而里面是个对象,就会报错
  2. export {
  3. {
  4. xxx:xxx
  5. xxx:xxx
  6. }
  7. }
  8. // 解决办法1: 使用default。因为default只能导出一个,所以后面跟对象没有歧义,就是导出一个对象
  9. export default {
  10. a : 1,
  11. b : 2
  12. }
  13. import obj from './1.js' // 随便起一个变量名来引入。

如果要导出多个对象呢?

  1. // 将两个对象套进一个对象中默认导出
  2. var obj1 = {
  3. a:1
  4. }
  5. var obj2 = {
  6. b:2
  7. }
  8. export default{
  9. obj1,
  10. obj2
  11. }
  12. // 利用解构导入
  13. import obj from './1.js'
  14. let {obj1, obj2} = obj

导出类

  1. class A{
  2. constructor(){
  3. this.type = 1
  4. }
  5. }
  6. export {
  7. A
  8. }
  9. // 引入
  10. import {A} from './1.js'
  11. let a = new A();

导出默认类只需要 default 后直接写类名即可‘

  1. class A{
  2. constructor(){
  3. this.type = 1
  4. }
  5. }
  6. export default A;

导入所有变量/对象/...

  1. import * as Mod from './1.js'
  2. let a = Mod.a
  3. let res = Mod.test();
  4. let default = Mod.default // 默认导出的变量需要用 .default 获取,不能直接用名字
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注