JavaScript ES6语法学习笔记 02、ES6语法扩展

举报
长路 发表于 2022/11/28 21:32:02 2022/11/28
【摘要】 文章目录前言一、剩余参数(多参=>数组,也有对象情况在对象解构赋值中)1.1、认识与使用剩余参数1.2、箭头函数中使用剩余参数(代替arguments)1.3、注意事项(3个)二、展开运算符(数组=>多参,也有对象情况)2.1、认识展开运算符2.2、针对数组(4个实用案例)2.3、针对对象(语法与合并案例)三、Set对象3.1、Set的基本方法与使用(四个属性、一个方法)3.2、Set

@[toc]

前言

本篇博客是关于javascript的ES6语法扩展,若文章中出现相关问题,请指出!

所有博客文件目录索引:博客目录索引(持续更新)

一、剩余参数(多参=>数组,也有对象情况在对象解构赋值中)

1.1、认识与使用剩余参数

语法...变量名。剩余参数正常使用是永远都是数组,除非在对象解构赋值中使用会变为对象(称为剩余元素)。

实际简单应用

//1、将调用函数传入的所有参数出存储在args数组中
const f = (...args) => console.log(args);
//2、将剩余的参数传入到args数组中
const f1 = (x, y, ...args) => console.log(args);

//测试
//1、无传入参数时,默认为空数组
f();
//2、传入指定数量参数,存储到数组中
f1(1, 2, 3, 4, 5);

image-20210619151148104



1.2、箭头函数中使用剩余参数(代替arguments)

引出箭头函数中使用剩余参数

我们可以在箭头函数中使用剩余参数来代替普通函数中的arguments,此时我们就有个疑问:箭头函数中没有arguments吗

  • 答案是正确的,在箭头函数里里没有this,其实也就没有了arguments,不过我们可以使用剩余参数来代替它,并且使用剩余参数比arguments参数更加强大,方法更多。(因为arguments是一个对象,其原型链中没有数组;而剩余参数是数组,自然也有就有了很多方法)
  • ES6之后,完全可以使用剩余参数来替代arguments了!

测试一下箭头函数中没有arguments参数:

const f = () => console.log(arguments);

image-20210619151637059


实际案例

需求:在箭头函数中使用剩余参数进行参数的相加。

解决方案1:简单使用遍历来实现累加

//函数使用剩余参数实现相加
const add = (...args) => {
    let sum = 0;
    for (let i = 0; i < args.length; i++) {
        sum += args[i];
    }
    console.log(sum);
};

add(1, 2, 3);//6

解决方案2:使用数组的reduce方法来进行运算。

// reduce使用
const fun = (...args) => {
    //回调函数中的第一个参数是上一次的返回值,第二个参数是当前遍历的值
    return args.reduce((pre, value) => {
        return pre + value;
    }, 0);//第一次起始值为0
};

console.log(fun(1, 2, 3, 4, 5));//15


1.3、注意事项(3个)

1、箭头函数中若是只有一个参数为剩余参数,其不能省略()。如:(...args) => console.log(args)

2、剩余参数的位置必须是在参数的最后一个位置,否则会抛出异常。

3、在进行对象解构赋值中使用剩余参数,实际上会形成一个对象

//在对象解构赋值中,...args表示获取剩余的所有键值形成对象
const { x, y, ...args } = {
    a: 1,
    x: 1,
    z: 2,
    t: 3
};
console.log(x, y, args);

image-20210619152809401



二、展开运算符(数组=>多参,也有对象情况)

2.1、认识展开运算符

语法...数组{...对象}。前者可以将数组转为多个参数,后者可以将对象中的属性转为多个参数。

小测试一波:

image-20210619160218097

注意点:若是想将展开的多个参数存储到数组中,就需要使用[]包裹,如[...[1,2,3]],这样才能够构成数组。



2.2、针对数组(4个实用案例)

语法

  • 展开数组:...数组
  • 展开数组元素到数组中:[...数组]

数组的展开运算符功能

  1. 复制数组。实现浅拷贝。
  2. 合并数组。不再使用数组的concat()方法进行合并。
  3. 字符串快速转数组。不再使用字符串的split()方法。
  4. 类数组转为数组。让原本在类数组的元素转移到数组中,拥有数组的功能!
<script>
    //1、复制数组:复制出来一个新的数组(浅拷贝)
    const arr = [1, 2, 3, [1, 1]];
    console.log([...arr]);//[1, 2, 3, Array(2)]

    //2、合并数组:将多个数组进行合并  | 不需要使用concat()合并方法了
    const arr1 = [1, 2];
    const arr2 = [5, 6];
    console.log([4, 5, ...arr1, ...arr2]);//[4, 5, 1, 2, 5, 6]

    //3、字符串转为数组
    console.log(...'changlu');//仅仅是将字符串展开:c h a n g l u
    //转为数组应当放在[]中。 | 不需要再使用字符串方法split()了,转好之后直接使用数组的方法
    console.log([..."changlu"]);//["c", "h", "a", "n", "g", "l", "u"]

    //4、类数组转为数组
    //①arguments:类数组
    const f = function () {
        console.log([...arguments])
    };//将类数组转为数组后就能够使用更多方法
    f(1, 2, 3, 4);//[1, 2, 3, 4]
    //②NodeList转为数组
    console.log([...document.querySelectorAll("div a")]);;
</script>


2.3、针对对象(语法与合并案例)

介绍语法

语法:对于对象展开必须使用{}包裹,如{...对象},不能够像数组一样。

<script>
    const person = {
        name: '人',
        hobby: 'sport',
        age: '未知',
        thing: {
            name: '物件',
            mfunction: '功能'
        }
    };

    //展开对象,查看内容
    console.log({ ...person });
    //测试是浅拷贝
    console.log({ ...person } === person);
    console.log({ ...person }.thing === person.thing);
</script>

image-20210619161945223


应用:合并对象

记住一点:后面展开的对象属性若是与之前的属性重复会覆盖前面的属性!

<script>
    //下面两个对象的name与hobby重复
    const person = {
        name: '人',
        hobby: 'sport',
        age: '未知'
    };

    const student = {
        name: 'changlu',
        hobby: 'play',
        sex: '男'
    };

    //合并对象:后面展开的对象属性若是与前一个相同就会覆盖
    console.log({ height: 180, ...person, ...student });
    console.log({ height: 180, ...student, ...person });
</script>

image-20210619162255506



三、Set对象

3.1、Set的基本方法与使用(四个属性、一个方法)

Set:不能有重复的元素,没有下标表示对应的元素(也就意味不能使用下标来访问元素),是无序的。

image-20210620165706624

包含四个方法与一个属性

  • 四个方法:add()delete()clear()foreach()
  • 属性:size
<script>
    var s = new Set();
    //三个方法
    //add():添加一个元素,不能添加重复的值(基本类型就是比较值;引用类型比较地址)
    s.add(1);
    s.add(1);//不能重复添加
    s.add({});
    s.add({});//可以添加,因为这两个对象是不同引用地址
    //delete():删除指定元素
    s.delete(1);//成功删除数字1
    //clear():清除容器中的所有元素
    s.clear();

    //一个属性
    //size:获取到当前set容器中存储的元素数量
    console.log(s.size);
    console.log(s);
</script>

foreach()方法单独测试:需传入一个回调函数作为第一个参数,第二个参数对回调函数的this对象,默认为window对象。

  • 回调函数可传入三个参数:第一个参数为当前访问的值;第二个参数为当前值的索引;第三个值为整个操作对象。
<script>
    var s = new Set([1, 2, 3, 3, 4]);
    //箭头函数与普通函数在回调函数中的this默认是window
    s.forEach((currentvalue, index, s) => {
        console.log("当前值:" + currentvalue, "当前索引:" + index, "操作集合:" + s, "this:" + this)
    });//第二个参数可作为起始参数

    //设置this对象,即设置foreach的第二个参数即可!
    s.forEach(function (currentvalue, index, s) {
        console.log(this)
    }, document);
</script>

重点说明:使用forEach()方法按照成员添加进集合中的顺序来进行遍历的。



3.2、Set构造函数的参数

参数可传入:数组、字符串、类数组如argumentsNodeListSet集合。

说明:对于自己本身set对象作为参数,实际上得到的值为浅拷贝!

<div>
    <a href="">1</a>
    <a href="">2</a>
    <a href="">3</a>
</div>

<script>
    //1、数组
    const s = new Set([1, 2, 1]);
    console.log(s);

    //2、字符串
    const s1 = new Set("changlu");
    console.log(s1);

    //3、类数组
    //arguments
    function fun() {
        console.log(new Set(arguments));
    }
    fun(6, 66, 6);
    //NodeList
    console.log(new Set(document.querySelectorAll("div a")));;

    //4、set对象
    var s2 = new Set([1, 2]);
    console.log(new Set(s2));
    console.log(new Set(s2) === s2);//相当于进行浅拷贝
</script>


3.3、注意事项(2个)

1、判断重复的方式:Set对于重复值的判断基本遵循严格相等(===),有一个很特殊的值就是NaN,尽管NaN!==NaN,在Set中同样不会出现两个NaN!

const s = new Set([NaN, 1, NaN]);
console.log(new Set(s));//Set(2) {NaN, 1}

2、何时使用Set

①数组或字符串去重时。

②为了使用Set的提供的方法与属性时。



3.4、实际应用(3个小示例)

1、数组去重(最终存储到数组)

//数组通过set去重后再转为数组
const arr = [1, 2, 3, 3, 5, 5, 4, 6];
//通过使用数组展开式(普通的就是通过使用forEach一个个遍历push到数组里,不过这种方式更加方便)
console.log([...new Set(arr)]);//[1, 2, 3, 5, 4, 6]

2、字符串去重

<script>
    const str = "chhhannngllu";
    //首先去重后展开到数组,接着使用数组的join()方法合并为字符串
    console.log([...new Set(str)].join(""));
</script>

3、对多个dom元素设置样式

思路:使用forEach()方法进行遍历。

image-20210620171045634

<div>
    <a href="">1</a>
    <a href="">2</a>
    <a href="">3</a>
</div>

<script>
    //获取三个a元素
    var lists = document.querySelectorAll("div a");
    //通过forEach的方式来进行统一设置颜色(其实也可直接通过数组的forEach方法进行)
    new Set(lists).forEach((ele) => {
        ele.style.color = "red";
        ele.style.backgroundColor = "yellow";
    });
</script>


四、Map对象

4.1、Map与对象的区别?

Map对象都是键值对的集合,那么它们都有什么区别呢?

  • Map:其键可以设置任意类型,如基本类型、引用类型都可以。
  • 对象:其键只能是字符串,若是传入[]对象,依旧会自动调用toString()转为字符串的!

示例:测试将对象插入到Map与对象中作为键

<script>
    const o = {
        name: 'changlu',
        age: 18
    };
    //对象:对象的键一定是字符串,若是传入对象依旧会自动调用toString()转为字符串
    const obj = {
        [{}]: "hello",
        [o]: '对象'  //设置对象o为键
    };
    console.log(obj);
    console.log({}.toString());//{}转为字符串形式就是"[object Object]"

    //Map对象:Map的键可以为基本类型与引用类型,任意
    const map = new Map();
    map.set({}, "hello").set(o, "对象");
    console.log(map);
</script>

image-20210620181711485



4.2、Map的方法与属性

image-20210620182155188

方法:set()、get()、has()、delete()、clear()、forEach()。

  • get():若是获取不存在的成员,则会得到undefined。
  • delete():若是删除不存在的成员,什么都不会发生。

属性:size。

<script>
    const m = new Map();
    //方法测试
    //set():需要传入键值对,键可以是任意类型,若是相同时后面插入的值会覆盖前面一个
    m.set("name", "changlu").set("name", "liner").set(undefined, "null");
    //get():通过指定key来获取到value
    const val = m.get(undefined)
    console.log("获取key为undefined的值:", val);
    //hash():传入key,测试是否包含这个键值对,不包含返回false,包含返回true
    console.log(m.has(null));
    console.log(m.has("name"));
    //delete():传入key,删除指定键值对。若是没有指定键值对则无其他效果
    m.delete(undefined);
    m.delete(null);
    //clear():清除所有元素
    m.clear();
    //forEach():遍历所有键值对。传入的回调函数以及第二个参数与set一致不用多说
    m.set("name", "changlu").set("age", 18);
    m.forEach((val, key, m) => {
        console.log(val, key, m, "this:" + this);
    }, document);

    //属性测试
    //size:获取当前集合中的元素数量
    console.log(m.size);
    console.log(m);
</script>

image-20210620183123691



4.3、Map构造函数的参数

介绍与引出Map转数组效果

构造函数中的参数可传入:数组、SetMap等等。

  • 数组:二维数组,其中的一维数组放置键值对。
  • Set:其中的每个元素应该是一个数组,数组中包含键值对。
  • Map:相当于进行复制,就是浅拷贝。

首先在传入数组到构造函数中我们先来进行一个测试,看看将Map展开得到什么:

<script>
    //Map转数组(实际上转为二维数组,其中的一维数组装着键值对)
    const m = new Map();
    m.set("name", "changlu").set("age", 18);
    console.log(...m);//得到两个数组
    console.log([...m]);//将数组放置在数组中就得到了一个二维数组
</script>

image-20210620183727306

OK此时我们大概心里有数了,传入的数组应当是二维数组了。


测试构造函数中的参数为:数组、Set、Map

<script>
    //1、数组
    const arr = [
        ['name', "changlu"],
        ['age', 18]
    ];
    var m = new Map(arr);
    console.log(m);

    //2、Set:集合中的每个元素应当都是一个一维数组,一维数组中为键值对
    const s = new Set(arr);
    var m = new Map(s);
    console.log(m);

    //3、Map:进行浅拷贝
    const arr1 = [
        ['name', "changlu"],
        ['thing', {
            name: '东西'
        }]
    ];
    var m = new Map(arr1);
    var m1 = new Map(m);
    console.log(m);
    console.log(m.get('thing') === m.get('thing'));//使用拷贝后的与拷贝前的进行严格等于若是为true表示浅拷贝

</script>

image-20210620184422639



4.4、Map注意事项(2个)

1、判断键名是否相同的方式:对于NaN,在Map中也会认为其是相等的所以当添加多个Nan作为键的只能取最后一个。

const arr = [
    [NaN, '1'],
    [NaN, '2']
];
//对于NaN,在Map中也只取一个
const m = new Map(arr);
console.log(m);//Map(1) {NaN => "2"}

2、什么时候使用Map

从概念上来看:Map我们可以看做是容器,而对象则是用来描述模拟现实世界的实体;

从使用上:需要key、value结构来存储多个数据或者需要字符串以外类型的值作为键,我们可以使用Map!



4.5、实际应用(2个)

示例1

需求:对多个p元素的文字颜色进行设置,要求使用map结构来进行统一设置。

<script>
    const [p, p1, p2] = document.querySelectorAll("div a");
    //统一添加到map中
    const map = new Map();
    map.set(p, "green").set(p1, "red").set(p2, "blue");
    //使用for each来快速遍历赋样式
    map.forEach((color, ele) => {
        ele.style.color = color;
    });
</script>

image-20210620190022162


示例2:在示例1的基础上,现在我们不仅仅添加一个属性了,而是多个属性,同样使用map来解决。

分析:将多个属性放置在对象中作为指定dom的值,之后通过进行遍历每个键值对时再遍历对象中的属性对dom元素进行样式赋值!

<script>
    const [p, p1, p2] = document.querySelectorAll("div a");
    //统一添加到map中
    const map = new Map();
    map.set(p, {
        color: "red",
        backgroundColor: "yellow",
    }).set(p1, {
        color: "blue",
        backgroundColor: "green",
    }).set(p2, {
        color: "white",
        backgroundColor: "black",
    });
    //使用for each来快速遍历赋值样式
    map.forEach((styles, ele) => {
        //对象进行遍历,styleName是对象中每个键值对的键
        for (const styleName in styles) {
            //这样就实现了多个属性同时赋值
            ele.style[styleName] = styles[styleName];
        }
    });
</script>

image-20210620190630420



五、遍历器iteractor与for…of循环

5.1、遍历器iteractor(ES6新增属性symbol,为for…of作铺垫)

5.1.1、iteractor三提问:什么?哪里?如何获取?

什么是iteractoriteractor在哪里?怎么获取?

  • iteractor是一个遍历器(或称迭代器),能够进行遍历获取集合中的值。
  • 其存在与数组、类数组、字符串等除了自定义对象。(自定义对象可以自定义)
  • 通过调用[Symbol.iterator]()这个函数方法(其实就是values()方法)获取到指定对象或集合的迭代器。
<script>
    //在数组原型链对象中的"Symbol.iterator"是一个函数叫做values()
    //调用[Symbol.iterator]()相当于调用values()方法返回一个Iteractor对象
    console.log([1, 2][Symbol.iterator]);
    console.log([1, 2][Symbol.iterator]());
</script>

image-20210620201958962



5.1.2、iteractor初使用+快速遍历

初次认识iteractor对象的next()方法

既然说它是一个遍历器,那么我们如何来使用iteractor来遍历数组中的元素呢?

  • 通过使用遍历器的next()方法来进行遍历。
<script>
    //获取到[1,2]数组的迭代器
    const m_iteractor = [1, 2][Symbol.iterator]();
    //next():返回一个对象,包含value与done属性,value就是对应数组中的元素值,done表示是否遍历结束,没有为false
    console.log(m_iteractor.next());;
    console.log(m_iteractor.next());;
    //若是没有元素再进行遍历了,那么value值为undefined,done为true,表示结束了
    console.log(m_iteractor.next());;
    console.log(m_iteractor.next());;
</script>

image-20210620202900178


快速遍历数组:利用next()方法获取到的两个值来进行

分析:现在外层调用next()获取对象,接着使用while来进行遍历通过判断对象中的done是否为true作为条件!

<script>
    //获取到[1,2]数组的迭代器
    const m_iteractor = [1, 2][Symbol.iterator]();
    //首先获取到第一次得到的next()函数执行后返回的对象
    let f_next = m_iteractor.next();
    console.log(f_next);
    while (!f_next.done) {//一旦为true,则停止遍历
        console.log(f_next.value);
        f_next = m_iteractor.next();//继续进行遍历
    }
</script>

image-20210620203629596



5.1.3、iteractor的用途

遍历数组for循环和调用forEach()方法。

遍历对象for in循环遍历得到key

此时我们思考一下对于数组、其他对象集合是不是缺了一种遍历的方式呢?

  • 此时iteractor不就来了,其是一个统一的遍历方式。

应用场景:真正实际场景中我们并不会使用iteractor来进行遍历的,但是很多方法或遍历方式都是在iteractor之上进行封装的如for...of、展开运算符底层就是使用了iteractor



5.2、for…of遍历方法

5.2.1、for…of使用(搭配break、continue)

本部分就拿数组下手,下面是使用for…of遍历数组以及搭配break、continue的案例:

<script>
    const arr = [1, 2, 3, 4, 5];
    console.log("for...of遍历:")
    //val就是值
    for (const val of arr) {
        console.log(val);
    }

    //搭配break、continue使用
    //需求:跳过值为2不输出,输出3就结束
    console.log("搭配break、continue测试:");
    for (const val of arr) {
        if (val === 2) {
            continue;
        } else if (val === 4) {
            break;
        }
        console.log(val);
    }
</script>


5.2.2、for…of取得数组值与索引(单独值、单独索引、索引与值)

使用的是数组原型链中的方法:这些方法的返回值都是iteractor,所以都能够使用for...of方法进行遍历

  • 单独值:values()arr[Symbol.iterator]()
  • 单独索引:keys()
  • 索引与值:entries()
<script>
    const arr = [1, 2, 3, 4, 5];
    //获取迭代器(两种方式):执行函数都能够获取到迭代器,迭代器中调用next就是获取到的值
    console.log(arr[Symbol.iterator]());
    console.log(arr.values());
    //获取数组中的值:values()
    for (const val of arr.values()) {  //使用arr.values与arr的效果一致
        console.log(val);
    }

    //获取数组中的索引:keys()
    console.log(arr.keys());//返回值同样是数组迭代器:IterableIterator<number>
    for (const index of arr.keys()) {
        console.log(index);
    }

    //获取值与索引:entries()
    console.log(arr.entries());//同样也是一个迭代器:IterableIterator<[number, number]>
    //for (const entry of arr.entries()) { //可以更加优化,直接进行解构赋值
    for (const [index, val] of arr.entries()) {
        //entry是一个数组,装有索引与值
        console.log(entry[0], entry[1]);
    }
    1 3 5 => 0 1 2
    1=>5  2356 
</script>

image-20210620225523281



5.2.3、原生可遍历与非可遍历(有哪些)

介绍可遍历是什么以及有哪些?

什么是可遍历?只要有Symbol.iteractor方法或者其他方法生成的可遍历对象,就都是可遍历的!

那么也就是说只要生成的是iteractor对象就能够使用for...of循环来统一遍历!

允许for…of遍历的:数组、字符串、SetMapargumentsNodeList

非原生可遍历:对象(自定义的)。


示例(可遍历与非可遍历)

可遍历示例:上面所提及的允许遍历的都是原型链中具有Iteractor对象(可调用方法获取的):

<script>
    //数组
    console.log("遍历数组:");
    for (const val of [1, 2, 3]) {
        console.log(val);
    }

    //字符串
    console.log("遍历字符串:");
    for (const ch of "changlu") {
        console.log(ch);
    }

    //遍历Set
    console.log("遍历Set:");
    for (const val of new Set([1, 2])) {
        console.log(val);
    }

    //遍历Map
    console.log("遍历Map:");
    for (const entry of new Map([["name", "changlu"], ["age", 18]])) {
        //entry是一个一维数组,存放了键与值
        console.log(entry);
    }

    //遍历类数组arguments
    function fun() {
        //arguments实际是类数组
        for (const val of arguments) {
            console.log(val);
        }
    }
    console.log("遍历类数组arguments:");
    fun(1, 1);
</script>

非可遍历示例:普通对象与类数组两种自定义迭代器

针对于普通对象:

<script>
    const obj = {
        name: 'changlu',
        age: 18
    };
    console.log(obj);//自定义对象本身并没有iterator
    //自定义symbol.iterator,此时就能够支持for...of
    obj[Symbol.iterator] = () => {
        let index = 0;
        //返回一个对象,对象中包含next()方法,该方法返回一个对象value与done
        return {
            next() {
                index++;
                if (index === 1) {
                    return {
                        value: obj.name,
                        done: false
                    };
                } else if (index === 2) {
                    return {
                        value: obj.age,
                        done: false
                    };
                } else {
                    return {
                        value: undefined,
                        done: true
                    };
                }

            }
        };
    };
    //原生遍历
    const iter = obj[Symbol.iterator]();
    console.log(iter.next());;
    console.log(iter.next());;
    console.log(iter.next());;

    //for...of来遍历自定义对象
    for (const val of obj) {
        console.log(val);
    }
</script>

image-20210620234424311

类数组:有length和索引属性的对象

<script>
    //类数组中的包含索引对应属性以及一个length
    const obj = {
        0: 'changlu',
        1: 'liner',
        2: '爱情',
        length: 3
    };
    console.log(obj);//自定义对象本身并没有iterator
    //自定义Symbol.iterator函数变量,调用返回一个对象包含next()方法,根据索引来遍历
    obj[Symbol.iterator] = () => {
        let index = 0;
        return {
            next() {
                if (index === obj.length) {
                    return {
                        value: undefined,
                        done: true
                    };
                } else {
                    return {
                        value: obj[index++],
                        done: false
                    };
                }
            }
        };
    }
    //原生遍历
    const iter = obj[Symbol.iterator]();
    console.log(iter.next());;
    console.log(iter.next());;
    console.log(iter.next());;
    console.log(iter.next());;

    //for...of来遍历自定义对象
    for (const val of obj) {
        console.log(val);
    }
</script>

image-20210620235820667



5.3、实际使用iterator场合

1、数组、字符串、Set等的展开元素符,自定义对象不能进行展开(除非自定义遍历器)。

<script>
    //类数组中的包含索引对应属性以及一个length
    const obj = {
        0: 'changlu',
        1: 'liner',
        2: '爱情',
        length: 3
    };
    console.log({ ...obj });//对于自定义对象使用...若是包裹在{}是可以进行复制的
    console.log(...obj);//直接使用...obj,由于自定义对象是没有遍历器所以会报错,除非自定义遍历器为自定义对象
</script>

image-20210621000531702

2、数组以及其他可遍历类型进行解构赋值使用到了iterator

3、SetMap的构造函数传入的参数也使用到了iterator

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。