小胖墩集结号

2022.3.10

1.数组是特殊的对象

2.数组与对象的区别:

数组使用数字索引,对象使用命名索引

3.数组的创建:

let arr=[];
let arr2=new Array();

new 关键词只会使代码复杂化。它还会产生某些不可预期的结果:

var points = new Array(40, 100);  // 创建包含两个元素的数组(40 和 100)

假如删除其中一个元素会怎么样?

var points = new Array(40);       // 创建包含 40 个未定义元素的数组!!!

4.数组,添加数据的方法:

push、unshift 、length

5.识别数组的方式:

1)运算符 typeof 返回 "object"

 2)ECMAScript 5 定义了新方法 Array.isArray()============>此方案的问题在于 ECMAScript 5 不支持老的浏览器

3)创建您自己的 isArray() 函数以解决此问题:

function isArray(x) {
    return x.constructor.toString().indexOf("Array") > -1;
}

  假如对象原型包含单词 "Array" 则返回 true。

4)假如对象由给定的构造器创建,则 instanceof 运算符返回 true:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
 
fruits instanceof Array     // 返回 true

2022.3.11

数组方法:

1.转字符串

1).JavaScript 方法 toString() 把数组转换为数组值(逗号分隔)的字符串

var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.toString(); 

Banana,Orange,Apple,Mango //结果

2)join() 方法也可将所有数组元素结合为一个字符串,它的行为类似 toString(),但是您还可以规定分隔符

var fruits = ["Banana", "Orange","Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.join(" * "); 

Banana * Orange * Apple * Mango  //结果

2.添加

1)首端

unshift() 方法(在开头)向数组添加新元素,并“反向位移”旧元素

unshift() 方法返回新数组的长度。

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon");    // 返回 5

2)末端

push() 方法(在数组结尾处)向数组添加一个新的元素:

push() 方法返回新数组的长度

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi");       //  向 fruits 添加一个新元素

shift() 方法返回被“位移出”的字符串

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.shift();             // 返回 "Banana"

length 属性提供了向数组追加新元素的简易方法

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits[fruits.length] = "Kiwi";          // 向 fruits 追加 "Kiwi"
console.log(fruits)  //['Banana', 'Orange', 'Apple', 'Mango', 'Kiwi']

3.删除

1)首端

shift() 方法会删除首个数组元素,并把所有其他元素“位移”到更低的索引。

2)末端 

pop() 方法从数组中删除最后一个元素

pop() 方法返回“被弹出”的值

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var x = fruits.pop();      // x 的值是 "Mango"

既然 JavaScript 数组属于对象,其中的元素就可以使用 JavaScript delete 运算符来删除

var fruits = ["Banana", "Orange", "Apple", "Mango"];
delete fruits[0];           // 把 fruits 中的首个元素改为 undefined

使用 splice() 来删除元素

第一个参数(0)定义新元素应该被添加(接入)的位置。

第二个参数(1)定义应该删除多个元素。

其余参数被省略。没有新元素将被添加。

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(0, 1);        // 删除 fruits 中的第一个元素
console.log(fruits )  // ['Orange', 'Apple', 'Mango']

4.更改元素

通过使用它们的索引号来访问数组元素:

数组索引(下标)以 0 开始。[0] 是第一个数组元素,[1] 是第二个,[2] 是第三个 ..

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits[0] = "Kiwi";        // 把 fruits 的第一个元素改为 "Kiwi"


(4) [empty, 'Orange', 'Apple', 'Mango']1: "Orange"2: "Apple"3: "Mango"length: 4[[Prototype]]: Array(0)

5.拼接数组

splice() 方法可用于向数组添加新项

第一个参数(2)定义了应添加新元素的位置(拼接)。

第二个参数(0)定义应删除多少元素。

其余参数(“Lemon”,“Kiwi”)定义要添加的新元素。

splice() 方法返回一个包含已删除项的数组

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");
console.log(fruits )  // ['Banana', 'Orange', 'Lemon', 'Kiwi', 'Apple', 'Mango']

6.合并(连接)数组

concat() 方法通过合并(连接)现有数组来创建一个新数组

合并两个
var myGirls = ["Cecilie", "Lone"];
var myBoys = ["Emil", "Tobias", "Linus"];
var myChildren = myGirls.concat(myBoys);   // 连接 myGirls 和 myBoys       // 删除 fruits 中的第一个元素
console.log(myChildren )  // ['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus']

concat() 方法不会更改现有数组。它总是返回一个新数组

合并三个
var arr1 = ["Cecilie", "Lone"];
var arr2 = ["Emil", "Tobias", "Linus"];
var arr3 = ["Robin", "Morgan"];
var myChildren = arr1.concat(arr2, arr3);   // 将arr1、arr2 与 arr3 连接在一起
console.log(myChildren )  // ['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus', 'Robin', 'Morgan']

concat() 方法也可以将值作为参数

var arr1 = ["Cecilie", "Lone"]; 
var myChildren = arr1.concat(["Emil", "Tobias", "Linus"]);
console.log(myChildren ) //['Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus']

7.裁剪数组

slice() 方法用数组的某个片段切出新数组。

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1); 
console.log(citrus ) //['Orange', 'Lemon', 'Apple', 'Mango']

slice() 可接受两个参数,比如 (1, 3)。

该方法会从开始参数选取元素,直到结束参数(不包括)为止。

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3); 
console.log(citrus ) // ['Orange', 'Lemon']

如果结束参数被省略,比如第一个例子,则 slice() 会切出数组的剩余部分。

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(2);
console.log(citrus ) //  ['Lemon', 'Apple', 'Mango']

8.自动 toString()

如果需要原始值,则 JavaScript 会自动把数组转换为字符串。下面两个例子将产生相同的结果: 

方法1:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits.toString(); 
方法2:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = fruits; 
结果均为:Banana,Orange,Apple,Mango

2022.3.12

数组排序

1)sort() 方法以字母顺序对数组进行排序:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();            // 对 fruits 中的元素进行排序
console.log(fruits)  
// 0: "Apple"
// 1: "Banana"
// 2: "Mango"
// 3: "Orange"

2)数字排序

默认地,sort() 函数按照字符串顺序对值进行排序。

该函数很适合字符串("Apple" 会排在 "Banana" 之前)。

不过,如果数字按照字符串来排序,则 "25" 大于 "100",因为 "2" 大于 "1"。

正因如此,sort() 方法在对数值排序时会产生不正确的结果。

我们通过一个比值函数来修正此问题

补充:

比较函数的目的是定义另一种排序顺序。

比较函数应该返回一个负,零或正值,这取决于参数

function(a, b){return a-b}

当 sort() 函数比较两个值时,会将值发送到比较函数,并根据所返回的值(负、零或正值)对这些值进行排序。

反转数组

reverse() 方法反转数组中的元素。

您可以使用它以降序对数组进行排序

var fruits = ["Banana", "Orange", "Apple", "Mango"];
let aa=fruits.sort(); 
console.log(aa)     //['Apple', 'Banana', 'Mango', 'Orange']       
let bb=aa.reverse();        
console.log(bb)  //['Orange', 'Mango', 'Banana', 'Apple']

3)以随机顺序排序数组

var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return 0.5 - Math.random()}); 

查找最高、最低值

 对数组使用Math.max()

 您可以使用 Math.max.apply 来查找数组中的最高值

let arr=[1,4,9,45,23]
function myArrayMax(arr) {     
    return Math.max.apply(null, arr); 
    }  
console.log(myArrayMax(arr))  //45

Math.max.apply([1, 2, 3]) 等于 Math.max(1, 2, 3)

对数组使用Math.min()

您可以使用 Math.min.apply 来查找数组中的最低值

let arr=[1,4,9,45,23]
function myArrayMin(arr) {
    return Math.min.apply(null, arr);
}
console.log(myArrayMin(arr))  //1

Math.min.apply([1, 2, 3]) 等于 Math.min(1, 2, 3)。

自制Min/Max js方法实现值的查找

 排序对象数组

 即使对象拥有不同数据类型的属性,sort() 方法仍可用于对数组进行排序。

 解决方法是通过比较函数来对比属性值:

cars.sort(function(a, b){return a.year - b.year});
var cars = [
{type:"Volvo", year:2016},
{type:"Saab", year:2001},
{type:"BMW", year:2010}];
let res=cars.sort(function(a, b){
	  var x = a.type.toLowerCase();
	  var y = b.type.toLowerCase();
	  if (x < y) {return -1;}
	  if (x > y) {return 1;}
	  return 0;
});
console.log(res)

结果:

2022.2.13

数组迭代

1.Array.forEach()

forEach() 方法为每个数组元素调用一次函数(回调函数)。

注释:该函数接受 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.forEach(),除了 Internet Explorer 8 或更早的版本:

2.Array.map()

map() 方法通过对每个数组元素执行函数来创建新数组。

map() 方法不会对没有值的数组元素执行函数。

map() 方法不会更改原始数组

请注意,该函数有 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.map(),除了 Internet Explorer 8 或更早的版本:

3.Array.filter()

filter() 方法创建一个包含通过测试的数组元素的新数组。

请注意此函数接受 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.filter(),除了 Internet Explorer 8 或更早的版本:

4.Array.reduce()

reduce() 方法在每个数组元素上运行函数,以生成(减少它)单个值。

reduce() 方法在数组中从左到右工作。另请参阅 reduceRight()。

reduce() 方法不会减少原始数组

请注意此函数接受 4 个参数:

  • 总数(初始值/先前返回的值)
  • 项目值
  • 项目索引
  • 数组本身
var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduce(myFunction);

function myFunction(total, value, index, array) {
  console.log(total, value, index, array)
  return total + value;
}

所有浏览器都支持 Array.reduce(),除了 Internet Explorer 8 或更早的版本:

5.Array.reduceRight()

reduceRight() 方法在每个数组元素上运行函数,以生成(减少它)单个值。

reduceRight() 方法在数组中从右到左工作。另请参阅 reduce()。

reduceRight() 方法不会减少原始数组。

var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduceRight(myFunction);

function myFunction(total, value, index, array) {
  console.log(total, value, index, array)
  return total + value;
}

请注意此函数接受 4 个参数:

  • 总数(初始值/先前返回的值)
  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.reduceRight(),除了 Internet Explorer 8 或更早的版本:

6.Array.every()

every() 方法检查所有数组值是否通过测试。

var numbers = [45, 4, 9, 16, 25];
var allOver18 = numbers.every(myFunction);

function myFunction(value, index, array) {
  return value > 18;
}
console.log(allOver18)  //false

请注意此函数接受 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.every(),除了 Internet Explorer 8 或更早的版本:

7.Array.some()

some() 方法检查某些数组值是否通过了测试。

var numbers = [45, 4, 9, 16, 25];
var numbers = [45, 4, 9, 16, 25];
var someOver18 = numbers.some(myFunction);

function myFunction(value, index, array) {
  return value > 18;
}
console.log( someOver18)   //true

请注意此函数接受 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

所有浏览器都支持 Array.some(),除了 Internet Explorer 8 或更早的版本:

8.Array.indexOf()

indexOf() 方法在数组中搜索元素值并返回其位置;

如果未找到项目,Array.indexOf() 返回 -1。

如果项目多次出现,则返回第一次出现的位置。

array.indexOf(item, start)
item必需。要检索的项目。
start可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到结尾。
var fruits = ["Apple", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");
var b=fruits.indexOf("ff");
console.log( a)   //0
console.log(b) //-1

所有浏览器都支持 Array.indexOf(),除了 Internet Explorer 8 或更早的版本:

9.Array.lastIndexOf()

array.lastIndexOf(item, start)
item必需。要检索的项目。
start可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到开头。

Array.lastIndexOf() 与 Array.indexOf() 类似,但是从数组结尾开始搜索。

var fruits = ["Apple", "Orange", "Apple", "Mango"];
var a = fruits.lastIndexOf("Apple");
var b=fruits.lastIndexOf("frffg")
console.log( a)   //2
console.log(b) //-1

10.Array.find()

find() 方法返回通过测试函数的第一个数组元素的值。

var numbers = [4, 9, 16, 25, 29];
var first = numbers.find(myFunction);

function myFunction(value, index, array) {
  return value > 18;
}
console.log(first)  //25

请注意此函数接受 3 个参数:

  • 项目值
  • 项目索引
  • 数组本身

老旧的浏览器不支持 Array.find()。下面列出了完全支持此方法的首个浏览器版本:

11.Array.findIndex()

老旧的浏览器不支持 Array.findIndex()。下面列出了完全支持此方法的首个浏览器版本:

findIndex() 方法返回通过测试函数的第一个数组元素的索引。

var numbers = [4, 9, 16, 25, 29];
var first = numbers.findIndex(myFunction);

function myFunction(value, index, array) {
  return value > 18;
}
console.log(first)  //3

2022.3.14

ES6常用语法和方法总结

字符串扩展

1.at()

// 参数传入角标,返回值为角标对应的字符
let a='abc'.at(0)
let b='吉塔'.at(1)  
console.log(a) //'a'
console.log(b)  // '塔'
// 与ES5中charAt()不同之处,汉字的话ES5会返回对应Unicode编码,js内部用UTF-16

2.includes(), startsWith(), endsWith()

  • includes(),返回值为布尔值,表示是否找到参数的字符串
  • startsWith(),返回值为布尔值,表示参数字符串是否在原字符串的头部
  • endsWith(),返回布尔值,表示参数字符串是否在原字符串的尾部
  • 这三个方法都支持第二个参数,表示开始搜索的位置。endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束
let str = 'Hello World'
str.includes('Hello')   // true
str.startsWith('Hello') // true
str.endsWith('d')   // true
str.startsWith('world', 6) // true
str.endsWith('Hello', 5) // true
str.includes('Hello', 6) // false

3.repeat()

'x'.repeat(3) // "xxx"

注意:参数不能传负数和Infinity,参数NaN为0,参数为字符串会先转换为数字

4.padStart(),padEnd()

参数两个,第一个为位数,第二个是用什么补全,省略第二个参数时默认为空格补全。这两个更多的用途是补全指定位数

let a='1'.padStart(10, '0') 
let b='12'.padStart(10, '0')
let c='123456'.padEnd(10, '0')
console.log(a)  // "0000000001"
console.log(b)  // "0000000012"
console.log(c)   // "1234560000"

数组扩展

1.Array.from()

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)

2....运算符

扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

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

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
  • 关于函数传参的问题,如果函数直接用...传参,传入的参数实际上是个数组,且后面不能再有参数。如果函数参数定义了一个数组,用...传入,实际上参数为数组中的值
function fn(...items){}
//等同于
function fn([数组内容]){}

let items = ['a', 'b', 'c']
function fn(...items){}
// 等同于
function fn('a', 'b', 'c') {}

3. ...运算符的应用

  • 复制数组(克隆数组)
let arr1 = [1, 2, 3]
let arr2 = [...arr1] // [1, 2, 3]
  • 合并数组
const arr1 = ['a', 'b']
const arr2 = ['c']
const arr3 = ['d', 'e']
const arr4 = [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
  • 与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]
  • 将字符串转换为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]

4. Array.of(), 用于将一组值,转换为数组。

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

5. 数组实例的fill()

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

6.数组实例的 entries(),keys() 和 values()

三个方法都是遍历数组,都可以用for...of...唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"

对象扩展

对象的话,解构赋值就不说了太基础了,我用的最多的就是...运算符和Object.assgin(),好吧,实际上...底层的方法就是assign()

Symbol

js数据类型除了string,number,boolean,undefined,null,object,第七种为symbol,他的作用就是防止定义变量时出现重复的定义导致覆盖的一些问题。

Set和Map结构

  1. Set

    ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成Set数据结构。此结构不会添加重复的值(你想到了什么,一定想到了数组去重)

    // 例一
    const set = new Set([1, 2, 3, 4, 4]);
    [...set]
    // [1, 2, 3, 4]
    
    // 例二
    const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
    items.size // 5
    
    // 例三 数组去重
    [...new Set(array)]
    
  2. Map

    这个结构我个人感觉不如对象好用,没用过。实际上Map结构就是键值对的结构,里面设置和获取分别用set和get方法,我要设置的话每次都set一下,我觉得很不方便

Proxy拦截

1.基本说明

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。get()方法

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});

2. get()方法

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(即this关键字指向的那个对象),其中最后一个参数可选。

var person = {
  name: "张三"
};

var proxy = new Proxy(person, {
  get: function(target, property) {
    if (property in target) {
      return target[property];
    } else {
      throw new ReferenceError("Property \"" + property + "\" does not exist.");
    }
  }
});

proxy.name // "张三"
proxy.age // 抛出一个错误

3.set()方法

set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错

async和await

1.基本说明

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

2. await命令

正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。

async function f() {
  return await 123;
}

f().then(v => console.log(v))
// 123

class类

1.constructor()

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

class Point {
}

// 等同于
class Point {
  constructor() {}
}

 2.类继承中的super()

如果你要用类继承的话,里面一定要写super(),他是指定父类的this的,否则会报错

class A {}

class B extends A {
  constructor() {
    super();
  }
}

浏览器加载

1.defer和async

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

defer与async的区别是:defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

2.ES6的新语法

浏览器加载 ES6 模块,也使用<script>标签,但是要加入type="module"属性。浏览器对于带有type="module"的<script>,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>标签的defer属性。

<script type="module" src="./foo.js"></script>
  • ES6 模块也允许内嵌在网页中,语法行为与加载外部脚本完全一致。
<script type="module">
  import utils from "./utils.js";
  // other code
</script>

 对于外部的模块脚本(上例是foo.js),有几点需要注意。

 - 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
 - 模块脚本自动采用严格模式,不管有没有声明use strict。
 - 模块之中,可以使用import命令加载其他模块(.js后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用export命令输出对外接口。
 - 模块之中,顶层的this关键字返回undefined,而不是指向window。也就是说,在模块顶层使用this关键字,是无意义的。
 - 同一个模块如果加载多次,将只执行一次。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值