es/6/7/8

219 阅读18分钟

1、var 、let 和 const

var 、let 、const常见区别如下:

image.png

1. 变量挂载在 window

var 声明的变量会挂载在 window 上,而 let 和 const 声明的变量不会

var a = 100; 
console.log(a, window.a);    // 100 100

let b = 10; 
console.log(b, window.b);    // 10 undefined

const c = 1; 
console.log(c, window.c);    // 1 undefined

2. 变量提升

var 声明变量存在变量提升,let 和 const 不存在变量提升

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
const c = 10;

3、块作用域

let 和 const 声明形成块作用域

if(1) { 
    var a = 100;    
    let b = 10;
    const c = 1;
}
console.log(a); // 100
console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量

4、重复声明同一个变量

同一作用域下 let 和 const 不能声明同名变量,而 var 可以

var a = 100;
console.log(a); // 100

var a = 10;
console.log(a); // 10
let a = 100;
let a = 10;

//  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。

5、暂存死区

var a = 100;

if(1){
    a = 10;
    
    //在当前块作用域中存在 a 使用 let/const 声明的情况下,给 a 赋值 10 时,
    只会在当前作用域找变量a,
    // 而这时,还未到声明时候,所以控制台 Error:a is not defined
    let a = 1;
}

6、const

  • 一旦声明必须赋值,不能使用 null 占位。
  • 声明后不能再修改
  • 如果声明的是复合类型数据,可以修改其属性或 Object.preventExtensions(阻止扩展)
const a = 100; 

const list = [];
list[0] = 10;
console.log(list);  // [10]

const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'}

如果声明的是复合型数据,不让其修改,可以使用 冻结对象 Object.freeze(obj) , 禁止为对象修改已存在的属性和方法。所有字段均只读。被冻结的对象也是不可扩展和密封的。

const info = { name: 'xxl' };
Object.freeze(info);
info.phone = '12345678';
console.log(info);  // { name: 'xxl' } phone 属性没加成功
image.png

2、箭头函数

1. 箭头函数和普通函数的区别

  • 箭头函数没有 this,函数内部的 this 来自于父级最近的非箭头函数,并且不能改变 this 的指向。

    const obj = {
        name: 'John',
        regularFunction: function() {
            console.log(this.name);
        },
        arrowFunction: () => {
            console.log(this.name);
        }
    };
    
    obj.regularFunction(); // 输出: John
    objarrowFunction(); // 输出: undefined,因为箭头函数的 this 指向全局对象(在浏览器中是 window)
    
    // 尝试改变箭头函数的 this 指向
    const newObj = { name: 'Jane' };
    const arrow = obj.arrowFunction.bind(newObj);
    arrow(); // 仍然输出: undefined,说明不能改变箭头函数的 this 指向
    
    
  • 箭头函数没有 super

    super 关键字用于访问和调用一个对象的父对象上的函数。由于箭头函数没有自己的 this 和原型链, 所以它没有 super

  • 箭头函数没有 arguments

    // `arguments` 对象是一个类数组对象,它包含了函数调用时传递的所有参数。
    // 箭头函数没有自己的 `arguments` 对象,它会继承外层函数的 `arguments` 对象。
    function regular() {
        const arrow = () => {
            console.log(arguments[0]);
        };
        arrow();
    }
    
    regular(1, 2, 3); // 输出: 1
    
    
  • 箭头函数没有 new.target 绑定。

    new.target 是一个元属性,在构造函数中使用时,它指向被调用的构造函数。由于箭头函数不能使用 new 来调用,所以它没有 new.target 绑定。

  • 箭头函数不能使用 new

    箭头函数不能使用 new 关键字来创建对象实例,因为它没有自己的 this 和 prototype

    const Arrow = () => {};
    try {
        const instance = new Arrow(); // 抛出 TypeError
    } catch (error) {
        console.error(error.message); // 输出: Arrow is not a constructor
    }
    
  • 箭头函数没有原型

    每个函数都有一个 prototype 属性,用于实现原型继承。箭头函数没有 prototype 属性。

    const arrow = () => {};
    console.log(arrow.prototype); // 输出: undefined
    
    
  • 箭头函数不支持重复的命名参数。

    在严格模式下,普通函数和箭头函数都不允许有重复的命名参数。

    // 严格模式
    'use strict';
    
    // 普通函数
    function regular(a, a) {
        console.log(a);
    }
    // 会抛出 SyntaxError: Duplicate parameter name not allowed in this context
    
    // 箭头函数
    const arrow = (a, a) => {
        console.log(a);
    };
    // 会抛出 SyntaxError: Duplicate parameter name not allowed in this context
    
    

2. 箭头函数作用域

传统 function 函数的 this 指向在函数调用的时候决定,a 调用指向 a,b 调用指向 b

箭头函数不是在调用的时候决定this,而是在箭头函数 申明 的时候,就指定了this,指向上层 父作用域 的this,如果父作用域没有this,则依次往上

window下 申明,window下调用func

let c = {a:123}
window.a = 321
// func 在 window 下申明,this 指向父作用域 this,window
let func = () => { console.log(this.a) }
c.b = function(){
  func()
}
c.b() //321

再次强调 箭头函数的 this 在箭头函数申明时就已经绑定到内部,不会被外部影响改变, call 和 apply 方法对箭头函数无效

window.a = 312
let func = () => {
    console.log(this.a)
}
let c = { 
    a:123,
    func
}
func()   // 312
c.func() // 312
 
func.apply(c) //312
func.call(c)  //312

3、函数参数默认值

在ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:

function config (data) {
    var data = data || 'data is empty'
}

这样看起来也没有问题,但是如果参数的布尔值为 false 时就会出问题, 例如我们这样调用 config:

config(0)config('') 那么结果就永远是后面的值

如果我们用函数参数默认值就没有这个问题,写法如下:

const config = (data = 'data is empty') => {}

3、模板字符串 ${name}

在ES6之前,如果我们要拼接字符串,则需要像这样:

var name = 'kris'
var age = 24
var info = 'My name is ' + this.name + ', I am ' + this.age

但是在ES6之后,我们只需要写成以下形式:(用反引号包含内容、用 ${} 引用数据)

const name = 'kris'
const age = 24
const info = `My name is ${name}, I am ${age}`

4、扩展操作符 ...

a. 二维数组转一维数组

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

b. 复制数组

arr 数组中的元素扩展成为单独元素被分配到 arr2 中。现在可以随意改变 arr2 数组,且都不会对源数组 arr 产生影响

这是因为,arr 数组值被扩展后添加到 arr2 数组中,我们设置 arr2 等于 arr 的值,而不是其本身。我们可以关注没有扩展运算符时发生事情,就能理解了。

var arr = [ 'a', 'b', 'c'];
var arr2 = [...arr];
console.log(arr2);  // [ 'a', 'b', 'c']

arr2.push('8')
console.log(arr)    // [ 'a', 'b', 'c']
console.log(arr2)   // [ 'a', 'b', 'c', '8']

c. 拼接数组

使用扩展运算符可以代替 concat() 来拼接数组。

#  concat() 来拼接数组
var arr = [‘a’, ‘b’, ‘c’];  
var arr2 = [‘d’, ‘e’, ‘f’];

arr1 = arr.concat(arr2);  
console.log(arr);  // [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]


# 使用扩展运算符
var arr = [‘a’, ‘b’, ‘c’];  
var arr2 = [‘d’, ‘e’, ‘f’];  
arr = [...arr, ...arr2];  
console.log(arr); // [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]

d. Math

也可以使用 math 函数连同扩展运算符。如这个例子中,将使用 Math.max()

Math.max()将返回一组数最大值。

Math.max();   // -Infinity  
Math.max(1, 2, 3);   // 3  
Math.max(100, 3, 4);   // 100

扩展运算符做同样事情

var arr = [2, 4, 8, 6, 0];  
var max = Math.max(...arr);  
console.log(max);  // 8

e. 字符串转数组

使用扩展运算符将字符串转换为数组。

var str = “hello”;  
var chars = […str];  
console.log(chars);  // [‘h’, ‘e’,’ l’,’ l’, ‘o’]

5、对象属性简写

但是在ES6里我们就方便很多:

let cat = 'Miaow'
let dog = 'Woof'
let bird = 'Peet peet'
let someObject = {
  cat,
  dog,
  bird
}
console.log(someObject) //{ cat: "Miaow",dog: "Woof", bird: "Peet peet"}

6、Symbol

symbol 是一种基本数据类型,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。
它的静态属性会暴露几个内建的成员对象;
它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:“new Symbol()”。

每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。

例子如下:

const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');

console.log(typeof symbol1); // "symbol"
console.log(symbol3.toString()); // "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo')); // false

8、Set

a. 理解Set

  • Set 本身是一个构造函数,用来生成 Set 数据结构。
  • 它类似于数组,但里面的成员是唯一的,不重复的。
  • 向 Set 加入值时,不会发生类型转换,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为 NaN 等于自身,而精确相等运算符认为 NaN 不等于自身。
  • Set 可以接收一个数组做为参数,用来初始化

b. set 数组去重

const arr = new Set([1, 1, '2', 2, 3, 4, 5])
console.log(arr)  // [ 1, '2', 2, 3, 4, 5]

c. set 字符串去重

let str = 'sssuuunnn'
let res = [...new Set(str)].join('')
console.log(res)  // sun

d. set 实例的属性

属性 size: size 属性表示 set 集合中有多少个元素

new Set([1, 2]).size  // 2

e. set 实例的方法

方法

# add(value):添加某个值,返回Set结构本身
const arr = new Set()
arr.add(1).add(2).add('zs')
console.log(arr)

# delete(value):删除某个值,返回一个布尔值表示是否删除成功
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.delete('zs')
console.log(a)
console.log(arr)

# has(value):返回一个布尔值,表示参数是否为Set的成员
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.has('zs')
console.log(a)

#clear():清除所有成员,没有返回值
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.clear('zs')
console.log(arr)

f. set 的遍历方法 for ... of ...

keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
for…of…

let setArr = new Set([1, 6, 6, 'sun', {name: 'sun'}])
for(let item of setArr.keys()) {
  console.log(item);
   // 1 6 sun {name: 'sun'}
}
for(let item of setArr.values()) {
  console.log(item);
  // 1 6 sun {name: 'sun'}
}
for(let item of setArr.entries()) {
  console.log(item);
  // [1, 1] [6, 6] [sun, sun] [{name: 'sun'}, {name: 'sun'}] 
}
for(let item of setArr) {
  console.log(item);
   // 1 6 sun {name: 'sun'}
}

g. set 实例循环遍历总结

set 生成的 数据结构 不能用 for 循环遍历

let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
console.log(arr1.size);
for (var i = 0; i < arr1.size; i++) {
    console.log(arr1[i].value)    
}

报错: 
# index.html:29 Uncaught TypeError: Cannot read property 'value' of undefined

set 生成的数据结构能用 forEach 循环遍历

let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
arr1.forEach(item => console.log(item))
// 好好, 恩恩, 哦哦, 吃饭饭, 睡觉觉, 亲亲

set 生成的数据结构能用 for of 循环遍历

let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
for (let i of arr1.keys()) {
    console.log(i) // 好好, 恩恩, 哦哦, 吃饭饭, 睡觉觉, 亲亲
}

7、模块化(Module)

在ES6之前,JS并没有模块化的概念,有的也只是社区定制的类似CommonJS和AMD之类的规则。例如基于CommonJS的NodeJS:

// circle.js
// 输出
const { PI } = Math
exports.area = (r) => PI * r ** 2
exports.circumference = (r) => 2 * PI * r

// index.js
// 输入
const circle = require('./circle.js')
console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`)


在ES6之后我们则可以写成以下形式:


/ circle.js
// 输出
const { PI } = Math
export const area = (r) => PI * r ** 2
export const circumference = (r) => 2 * PI * r

// index.js
// 输入
import {area} = './circle.js'
console.log(`半径为 4 的圆的面积是: ${area(4)}`)

14、Proxy/Reflect

Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 Proxy 的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

Proxy跟Reflect是非常完美的配合,例子如下:

const observe = (data, callback) => {
      return new Proxy(data, {
            get(target, key) {
                return Reflect.get(target, key)
            },
            set(target, key, value, proxy) {
                  callback(key, value);
                  target[key] = value;
                    return Reflect.set(target, key, value, proxy)
            }
      })
}

const FooBar = { open: false };
const FooBarObserver = observe(FooBar, (property, value) => {
  property === 'open' && value 
          ? console.log('FooBar is open!!!') 
          : console.log('keep waiting');
});
console.log(FooBarObserver.open) // false
FooBarObserver.open = true // FooBar is open!!!

当然也不是什么都可以被代理的,如果对象带有configurable: false 跟writable: false 属性,则代理失效。

16、Math对象的扩展

•二进制表示法 : 0b或0B开头表示二进制(0bXX或0BXX)

•二进制表示法 : 0b或0B开头表示二进制(0bXX或0BXX)

•八进制表示法 : 0o或0O开头表示二进制(0oXX或0OXX)

•Number.EPSILON : 数值最小精度

•Number.MIN_SAFE_INTEGER : 最小安全数值(-2^53)

•Number.MAX_SAFE_INTEGER : 最大安全数值(2^53)

•Number.parseInt() : 返回转换值的整数部分

•Number.parseFloat() : 返回转换值的浮点数部分

•Number.isFinite() : 是否为有限数值

•Number.isNaN() : 是否为NaN

•Number.isInteger() : 是否为整数

•Number.isSafeInteger() : 是否在数值安全范围内

•Math.trunc() : 返回数值整数部分

•Math.sign() : 返回数值类型(正数1、负数-1、零0)

•Math.cbrt() : 返回数值立方根

•Math.clz32() : 返回数值的32位无符号整数形式

•Math.imul() : 返回两个数值相乘

•Math.fround() : 返回数值的32位单精度浮点数形式

•Math.hypot() : 返回所有数值平方和的平方根

•Math.expm1() : 返回e^n - 1

•Math.log1p() : 返回1 + n的自然对数(Math.log(1 + n))

•Math.log10() : 返回以10为底的n的对数

•Math.log2() : 返回以2为底的n的对数

•Math.sinh() : 返回n的双曲正弦

•Math.cosh() : 返回n的双曲余弦

•Math.tanh() : 返回n的双曲正切

•Math.asinh() : 返回n的反双曲正弦

•Math.acosh() : 返回n的反双曲余弦

•Math.atanh() : 返回n的反双曲正切

17、for …of

for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

例子如下:

const array1 = ['a', 'b', 'c'];

for (const element of array1) {
      console.log(element)
}

// "a"
// "b"
// "c"

18、Promise

juejin.cn/post/711002…

19. es6 map 与 原生对象区别

区别 object 和 Map 存储的都是键值对组合。但是:
object 的键的类型是 字符串
map 的键的类型是 可以是任意类型
另外注意,object 获取键值使用Object.keys(返回数组)
Map 获取键值使用 map变量.keys() (返回迭代器)

示例代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>js es6 map 与 原生对象区别</title>
    </head>
    <body>
        <script type="text/javascript">
            let a = {
                o: 1
            };
            // string
            console.log(typeof Object.keys(a)[0]);
            let map = new Map();
            map.set(a, 'content');
            // 输出是object 也可以是任何类型
            console.log(map.keys().next());
        </script>

    </body>
</html>

6、解构赋值 [ ]

JS 的解构赋值是 ES6 新增的一种赋值方法,一般分为对象解构与数组解构两种形式;

a. 对象解构赋值

对象解构赋值 : 对象按照属性解构赋值,对象的属性没有次序,变量必须与属性同名,才能取到正确的值

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
    details: {
        nickName: "光脚丫思考",
        address: "中国北京",
        signature: "勿以善小而不为,勿以恶小而为之"
    }
}
const { userName, blog, details: { signature } } = user;
console.info(userName);    // 光脚丫思考
console.info(blog);        // https://blog.csdn.net/gjysk
console.info(signature);   // 勿以善小而不为,勿以恶小而为之

更深入的对象嵌套, 深层次的嵌套的对象也是可以通过解构赋值来获取属性值的,再深层次的也是可以正常获取的

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
    details: {
        nickName: "光脚丫思考",
        address: {
            domicileAddress: "户籍地",
            abodePlace: "居住地"
        },
        signature: "勿以善小而不为,勿以恶小而为之"
    }
}
const { userName, blog, details: { signature, address: { domicileAddress, abodePlace } } } = user;
console.info(userName);     // 光脚丫思考
console.info(blog);         // https://blog.csdn.net/gjysk
console.info(signature);    // 勿以善小而不为,勿以恶小而为之
console.info(domicileAddress);  // 户籍地
console.info(abodePlace);       // 居住地

b. 设置默认值

在某种特殊或意外的情况下,比如后端写接口的大侠忘记返回这个状态的值了,除了让后端的大侠正确的补充上这个状态值以外,我们还可以给它设置一个默认值,比如默认值离线状态 offline。代码如下:

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
    status: undefined
}
const { userName, blog, status = "offline" } = user;
console.info(userName);  // 光脚丫思考
console.info(blog);     // https://blog.csdn.net/gjysk
console.info(status);   // offline

另外一种情况就是直接就没有这个属性,缺少这个属性,设置默认值的办法同样好使,示例代码如下:

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
}
const { userName, blog, status = "offline" } = user;
console.info(userName);  // 光脚丫思考
console.info(blog);     // https://blog.csdn.net/gjysk
console.info(status);   // offline

无论是返回的属性值为undefined,还是直接把这个属性值干没了,解构赋值设置的默认值都很好使

在使用默认值的时候,应该注意区分 undefined 和 null,只有 undefined 的时候才会使用设置的默认值,null 是不会使用默认值的。可以看到address使用的是设置的默认值,而signature的值则继续保留为null了。如下代码所示:

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
    address: undefined,
    signature: null,
}
const { userName, blog, address = "中国北京", signature = "默认签名信息" } = user;
console.info(`userName=${userName}`);  // userName=光脚丫思考
console.info(`blog=${blog}`);          // blog=https://blog.csdn.net/gjysk
console.info(`address=${address}`);     // address=中国北京
console.info(`signature=${signature}`); // signature=null

c. 使用别名

另外一个使用解构赋值必须得面临的一个问题:变量命名冲突的问题,该如何解决呢?

前面的那些示例代码中,解构赋值中的变量名和对象中的属性名是完全一致的,如果已经定义了同名的变量该怎么办呢?岂不是会发生命名冲突的情况。此时,使用别名就能很好的解决这个问题了。示例代码如下:

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
}
const { userName: name, blog: url } = user;
console.info(name);
console.info(url);

d. 定义新变量

解构赋值还可以基于对象的属性值创建新的变量,还是先来看一个示例:

const user = {
    userName: "光脚丫思考",
    blog: "https",
}
const { userName, blog, message = `我是${userName},我的博客地址是:${blog}` } = user;
console.info(userName); // 光脚丫思考
console.info(blog);     // https
console.info(message);  // 我是光脚丫思考,我的博客地址是:https

请留意上面的代码,解构赋值中的 message 变量并非 user 对象的某个属性名称,而是由变量 userName 和 blog 拼接到一起的字符串变量。

需要特别强调一点的是,新定义的变量 message 中使用到的 userName 和 blog 并非user 中的属性名,而是解构赋值中定义的 userName 和 blog,这 2 个变量接收了 user 对象中同名的属性值。

因此,如果我们把解构赋值中的 userName 和 blog 移除掉的话,代码就废掉了。

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
}
const { message = `我是${userName},我的博客地址是:${blog}` } = user;
console.info(message); // Uncaught ReferenceError: userName is not defined

如果使用别名的方式就能更加说明这一点了。下面的代码中,新定义的变量 message 中拼接的变量名称就是别名,而并非 user 对象中的属性名,表明它所使用的是解构赋值中定义的变量名,而并非对象中的属性名。

const user = {
    userName: "光脚丫思考",
    blog: "https:/",
}
const { userName: name, blog: url, message = `我是${name},我的博客地址是:${url}` } = user;
console.info(name);         // 光脚丫思考
console.info(url);          // https:/
console.info(message);      // 我是光脚丫思考,我的博客地址是:https:/

e. 动态名称属性

在实际的开发过程中,我们通常会通过接口API来获取数据,而这些数据不仅仅内容是动态的,甚至对象的属性键名也是动态的,再或者我们一开始连属性的名称都可能不知道。这样的属性值要如何获取呢?如果不使用解构赋值,可以通过下标[]的方式来获取属性值,那解构赋值又是如何做到的呢?请看示例。

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
};
function getValue(data, key) {
    const { [key]: value } = data;
    return value;
}
let userName = getValue(user, "userName");
let blog = getValue(user, "blog");
console.info(userName);
console.info(blog);

可以看到,解构赋值代码也是通过下标[]的方式来获取对象的属性值的,下标中 key 的内容就是属性的名称。

f. 函数中的解构赋值

aa. 解构赋值传参

使用对象解构赋值将属性值作为参数传递给函数。

const user = {
    userName: "光脚丫思考",
    blog: "https://blog.csdn.net/gjysk",
};
function display({userName, blog}) {
    let message = `大家好,我是${userName},我的博客地址是:${blog}`;
    console.info(message);
}
display(user);

bb. 解构赋值返回结果

如果函数返回一个对象,可以将属性值直接解构为变量,如下代码所示:

function getUSer() {
    const user = {
        userName: "光脚丫思考",
        blog: "https://blog.csdn.net/gjysk",
    };
    return user;
}
const { userName, blog } = getUSer();
let message = `大家好,我是${userName},我的博客地址是:${blog}`;
console.info(message);

g. 循环中的解构赋值

接下来我们再看看在循环中如何使用解构赋值。示例代码如下:

代码中,我们在 for 循环的内部使用了解构赋值语法,成功的从每个 user 对象中获取到了 userName 和 blog 的数据。

let users = [
    {
        userName: "光脚丫思考1",
        blog: "https://blog.csdn.net/gjysk",
    },
    {
        userName: "光脚丫思考2",
        blog: "https://blog.csdn.net/gjysk",
    },
    {
        userName: "光脚丫思考3",
        blog: "https://blog.csdn.net/gjysk",
    },
];
for (user of users) {
    const { userName, blog } = user;
    let message = `大家好,我是${userName},我的博客地址是:${blog}`;
    console.info(message);
}

也算是最基本的玩法了,下面的方式则更加的简洁一些。

在 for 循环的 {} 中不包含解构赋值的代码,而是直接放到了 () 中,输出的结果和前面的代码是一样的。

for ({ userName, blog } of users) {
    let message = `大家好,我是${userName},我的博客地址是:${blog}`;
    console.info(message);
}

h. 数组结构赋值

数组按照顺序解构赋值, 先来看一个简单的数组解构赋值的代码,如下:

let [a, b] = [1, 2];
console.info(a); // 1
console.info(b); // 2

就像上面的示例一样,数组解构赋值的过程中,只要把每个解构的部分一一对应起来,就可以层层解构赋值。比如下面的代码:

请留意[b]这个语句,它对应的是实际数组中的[2,3],因此这个语法解析的便是[2,3]中的元素,因此获得的应该是2这个数值,如下图所示:可以看到这次的变量b输出的就是[2,3]这个数组了。

let [a, [b], d] = [1, [2, 3], 4];
console.info(a);  // 1
console.info(b);  //  2
console.info(d); // 4

我们把上述的代码稍微做点改变,输出的结果就会大不一样。代码如下:

let [a, b, d] = [1, [2, 3], 4];
console.info(a); // 1
console.info(b); // [2, 3]
console.info(d); // 4

I. 字符串解构

// 当作数组结构
var [q,w] = '12'; // q 1; w 2
      
// 当作对象结构
var { length}= '12';// length 2

j. 解构规则

ES6的解构赋值遵循一个规则:要左右两边的模式相同,就可以进行合法赋值。如下面的示例代码:

let [a, b, c] = [1, 2, 3];
let [d, [[e], f]] = [1, [[2], 3]];

如果解构不成功,变量值等于undefined,比如下面的代码:

let [a, b] = [1];
console.info(a); // 1
console.info(b); // undefined