2 迅速搞定js 面试(1)(SY)

目录

1 值类型 vs 引用类型

2 typeof能判断哪些类型

3 何时使用===何时使用=2

4 值类型和引用类型的区别

5手写深拷贝

6 if 语句和逻辑运算 

7  如何准确判断一个变量是不是数组?

8手写一个简易的jQuery ,考虑插件和扩展性

9 class 的原型本质,怎么理解?

10 如何理解js原型 

11  instanceof实现原理:

12 作用域

13 this 的不同应用场景,如何取值

14 手写 bind 函数

15什么是闭包 实际开发中闭包的应用场景,举例说明

16 创建 10 个 a 标签,点击的时候弹出来相应的序号


值类型 vs 引用类型

  • 值类型:undefined、string、number、boolean、symbol、bigInt

  • 引用类型:Object、Array、Date、RegExp、特殊(Function:不用于存储数据、Null:指针指向为空地址)

值类型和引用类型的区别:值类型存储值,引用类型存储内存地址

* const不能声明undefied类型 必须声明有值的常量 

深入分析 为什么?

因为值类型直接赋值内存比较小,对造成的性能不会有问题,所以可以直接赋值

而引用类型的json可以是上千上万行代码,一般造成内存比较大, 因此也需要将栈和堆严格分离出来,引用类型如果像值类型一样直接存储复制值 占内存 耗时 

2 typeof能判断哪些类型

typeof 运算符

  • 识别所有值类型

  • 识别函数

  • 判断是否是引用类型(不可再细分)

// 判断所有值类型
let a;               typeof a // 'undefined'
const str = 'abc';   typeof str // 'string'  
const n = 100;   typeof n // 'number'
const b = true;   typeof b // 'boolean'  
const s = Symbol('s');   typeof s // 'symbol'  

// 判断函数
typeof console.log // 'function'
typeof function () {} // 'function'

// 识别引用类型
typeof null // 'object'
typeof ['a', 'b'] // 'object'
typeof { x: 100 } // 'object'

3 何时使用===何时使用=2

=== 绝对相等,

== 存在隐式转化的相等值类型

除了 == null 之外,其它一律用 ===

100 == '100' // true
0 == '' // true
0 == false // true
false == '' // true
null == undefined // true

// 除了 == null 之外,其它一律用 ===,例如:
const obj  = {x: 100 }
if (obj.a == null) {}
// 相当于:
if (obj.a === null || obj.a === undefined) {}

//字符串的+ 号
const a = 100 + 10 // 110
const b = 100 + '10' // '10010'
const c = true + '10' // 'true10'
const d = 100 + parseInt('10') // 110

4 值类型和引用类型的区别

5手写深拷贝

注意判断值类型和引用类型

eg.值类型是null直接返回,引用类型的话往下做一些递归遍历

注意判断是数组还是对象

递归

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }

    // 初始化返回结果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }

    for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }

    // 返回结果
    return result
}

6 if 语句和逻辑运算 

         

7  如何准确判断一个变量是不是数组?

var arr = []
arr instanceof Array // true
arr.constructor === Array // true
Object.prototype.toString.call(arr) === '[object Array]' // true
Array.isArray(arr) // true

8手写一个简易的jQuery ,考虑插件和扩展性

class jQuery {
    constructor(selector) {
        const result = document.querySelectorAll(selector)
        const length = result.length
        for (let i = 0; i < length; i++) {
            this[i] = result[i]
        }
        this.length = length
        this.selector = selector
    }
    get(index) {
        return this[index]
    }
    each(fn) {
        for (let i = 0; i < this.length; i++) {
            const elem = this[i]
            fn(elem)
        }
    }
    on(type, fn) {
        return this.each(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
    // 扩展很多 DOM API
}

// 插件
jQuery.prototype.dialog = function (info) {
    alert(info)
}

// “造轮子”
class myJQuery extends jQuery {
    constructor(selector) {
        super(selector)
    }
    // 扩展自己的方法
    addClass(className) {

    }
    style(data) {

    }
}

// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))

9 class 的原型本质,怎么理解?

JS本身是基于原型继承的语言  问题的 本质————原型 和原型链

何用 class 实现继承

class

  • constructor

  • 属性

  • 方法

继承

  • extends(继承)

  • super(执行父类构造函数)

  • 扩展或重写方法

class 继承(extends,super)

10 如何理解js原型 

  1. 原型链本质是特殊的链表

  2. 链表用 next 连接,原型链用 __protp__ 连接

  3. 原型链最终指向 Object.prototype

  4. instanceof 本质是遍历链表

每个class都是由显示原型的,每个实例都有隐式原型,隐式原型指向显示原型;

基于原型的执行规则:

1,获取实例的方法或者实例的属性时

2,现在自身属性和方法里寻找

3,找不到的时候则自动去__proto__里寻找

class People {

    constructor (name, number) {

       this.name = name

       this.num = number

    }

    sayHi () {

        console.log(`早上好${this.name}, 学号:${this.num}`)

    }

}

const person1 = new People('刘备', 1212)

const person2 = new People('诸葛亮', 1213)



console.log(person1.__proto__ === People.prototype) // true



class Student extends People {

    constructor (name, number) {

       super(name, number)

    }

    eat () {

        console.log('吃饭啦')

    }

}

const p1 = new Student('张飞', 1209)

const p2 = new Student('赵云', 1200)

console.log(p1.__proto__ === Student.prototype, p1.prototype === Student.prototype) // false

console.log(p1.__proto__ === p2.__proto__) // true  两个实例的隐式原型同时指向Student的显示原型

console.log(p1.__proto__ === People.prototype, p1.__proto__ === Object.prototype) // false 实例的隐式原型指向的是父级类,没有指向父级以上的类原型

console.log(Student.prototype.__proto__ === People.prototype) // true 类的原型的隐式原型指向父级类的原型,这个可类比实例的隐式原型

p1.eat()

/**

 * instanceof实现原理:

 * 下面代码展示了instanceof实现判断数据类型的流程,

 * instanceof沿着数据的原型链一级一级往上找,最后一个

 * 判断是否为Array的返回false是由于再p1的原型链上没有Array

*/

console.log(p1 instanceof Student) // true

console.log(p1 instanceof People) // true

console.log(p1 instanceof Object) // true

console.log(p1 instanceof Array) // false

11  instanceof实现原理:

 * 下面代码展示了instanceof实现判断数据类型的流程,

 * instanceof沿着数据的原型链一级一级往上找,最后一个

 * 判断是否为Array的返回false是由于再p1的原型链上没有Array

原型链:

  • 每个构造函数都有 prototype(显式原型)

  • 每个实例对象都有 __proto__ / [[prototype]](隐式原型)

  • 实例对象__proto__ (隐式原型) 指向构造函数的 prototype(显式原型)

12 作用域

作用域: 一个变量的合法使用范围

作用域种类:

  1. 全局作用域

  2. 函数作用域

  3. 块级作用域(es6的语法,在{ }内用let,const声明的变量),块级作用域:在if、while、for循环里面使用

// 花括号作用域,if,for
if(true){
    let a = 100
}
for(let a=0; a<10; a++){
    let b = 200
    console.log(a)
    console.log(b)
}
// 此时所有的a,b只能在块级作用域内使用,外部引用则报错

自由变量查找方式:

  1. 在函数当前的作用域开始查找

  2. 向上级作用域,一层一层依次往上查找,找到为止。没找到则报错

  3. 如果到全局作用域都没找到,则报错:xxx is not defined
     

13 this 的不同应用场景,如何取值

this

应用场景:

  • 作为普通函数 --> window

  • 使用bind、call、apply --> 传入的对象

  • 作为对象方法被调用 --> 调用的对象

  • 在 class 方法中调用 --> 实例对象

  • 箭头函数 --> 上级作用域

注意:this的取值是在函数执行时确定的,不是函数定义的时候确定的

const zhangsan = {
    name: '张三',
    sayHi(){
        console.log(this.name)
    },
    wait(){
        // 定时器的回调是匿名函数,匿名函数默认指向window
        setTimeout(function() {
            console.log(this.name)   // 打印undefind
        }, 1000);
        
        /*
        // 箭头函数可以解决这个问题,让匿名函数指向当前对象
        setTimeout(() => {
            console.log(this.name)
        }, 1000);
        */
    }
}


// 执行函数的几种情况

zhangsan.sayHi()          //打印张三

let ls =  {name:'lisa'}
zhangsan.sayHi.call(ls)   //打印lisa,调用call,bind,apply改变内部的this指向

zhangsan.wait()           //打印undefind,定时器回调是匿名函数,匿名函数默认指向window

let say = zhangsan.sayHi  //打印undefind意料之中,因为执行的时候let say变量定义在window
say()                     //所以say的this是window,window对象没有变量name


// 解决一个怪异的面试题
const obj = {
    x:1,
    // 创建obj对象时,这个箭头函数不受当前obj{}作用域限制,跳到window对象了,this属于window
    print1:()=>{
        console.log(this.x)
    },

    // 已下两种方式等价,是属于在obj内定义的对象(不是回调),this属于obj
    print2(){
        console.log(this.x)
    },
    print25: function (){
        console.log(this.x)
    },

    // 定义时匿名函数被指向了window的作用域,所以内部this属于window
    print3: function(){
        console.log(this.x)
    }.bind(this)
}

obj.print1()   // undefind
obj.print2()   // 1
obj.print25()  // 1
obj.print3()   // undefind

        

14 手写 bind 函数

bind() 方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 -

//手写bind:
function myBind() {
  const content = [].shift.call(arguments);

  content.fn = this;
  const args = arguments;
  return () => {
    const result = content.fn(...args);
    delete content.fn;
    return result;
  };
}

 手写call、apply、bind

原理:

  • 3个方法第一个参数为新的执行环境,所以是一个对象

  • 当前执行环境赋值给环境的某个属性

  • 使用新环境调用当前执行环境,相当于一个对象调用方法,方法的this就是这个对象

  • 新环境是一个对象所以为引用类型,新增一个属性会改变自身,所以调用之后获得结果需要删除新增的属性

示例:

const obj = { a: "这是obj" };

function fn(arg1, arg2) {
  console.log(this);
}


//手写bind:
function myBind() {
  const content = [].shift.call(arguments);

  content.fn = this;
  const args = arguments;
  return () => {
    const result = content.fn(...args);
    delete content.fn;
    return result;
  };
}
Function.prototype.myBind = myBind;
fn.myBind(obj, "arg1", "arg2")(); // {a: '这是obj'}

15什么是闭包 实际开发中闭包的应用场景,举例说明

闭包

作用域应用的特殊情况,指有权访问另一个函数作用域中的变量的函数

闭包实际上是一种函数,闭包就是也是函数技术的一种;闭包能做的事情函数几乎都能做。
闭包也可认为是一种作用域。

触发方式:

  • 函数作为参数被传递

  • 函数作为返回值被返回 

2、闭包的作用:1、读取函数内部的变量;2、让这些变量始终保持在内存之中。

注意

  • 闭包的应用包括但不限于以下几个方面:

  1. 创建私有变量:闭包可以通过在函数内部定义变量,并将其作为返回值,实现创建私有变量的效果。这样可以避免全局变量的污染和冲突,提高代码的安全性和可维护性。

  2. 延长变量的生命周期:闭包可以使得变量在函数执行完成后仍然存在,并且可以在下一次调用函数时保持其值。这对于需要保留中间状态或者需要记住某些特定值的情况非常有用。

  3. 实现回调函数:闭包可以作为参数传递给其他函数,用于实现回调函数的功能。当某个条件满足时,调用该闭包函数,可以实现特定的逻辑或操作。这在事件处理、异步操作等场景中非常常见。

需要注意的是,闭包的使用需要谨慎。如果不是特定任务需要,过多地使用闭包可能导致性能下降和内存消耗增加。因此,在没有必要的情况下,最好避免在函数中创建闭包。

总之,闭包的应用包括创建私有变量、延长变量生命周期和实现回调函数等,能够提供更灵活和高效的编程方式

16 创建 10 个 a 标签,点击的时候弹出来相应的序号

for循环在很短的时间内就循环完了,i的值就变成了10,因为i的作用域是全局, 这个时候点击事件还没触发,所以再点击时所有 弹出来的都是 10

把i定义在for循环内就可以了,for循环内是一个块级作用域

JS中的 回调函数(callback)

回调函数:函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。,这句话的意思是函数b以一个参数的形式传入函数a并执行,顺序是先执行a ,然后执行参数b,b就是所谓的回调函数。

注意在回调函数调用时this的执行上下文并不是回调函数定义时的那个上下文,而是调用它的函数所在的上下文。

为什么要用到回调函数:有一个非常重要的原因 —— JavaScript 是事件驱动的语言。这意味着,JavaScript 不会因为要等待一个响应而停止当前运行,而是在监听其他事件时继续执行

回调正是确保一段代码执行完毕之后再执行另一段代码的方式

回调函数和异步操作的关系是什么?回调函数是异步么?

回调函数的本质是一种模式(一种解决常见问题的模式),因此回调函数也被称为回调模式。 

简而言之:一个函数在另一个函数中被调用。而且可以当参数传给其他函数。

回调函数和异步操作是没有关系的!!! 

callback 顾名思义  打电话回来的意思

eg1:你点外卖,刚好你要吃的食物没有了,于是你在店老板那里留下了你的电话,过了几天店里有了,店员就打了你的电话,然后你接到电话后就跑到店里买了。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

eg2:再比如,你发送一个axios 请求,请求成功之后,触发成功的回调函数,请求失败触发失败的回调函数。这里面的回调函数更像是一个工具,后台通过这个工具告诉你,你成功了抑或是失败了。这里面的所有异步操作都和回调没关系,真正的异步是then方法。

JS中的 回调函数(callback)_前端小草籽的博客-CSDN博客_js回调函数

js中的回调函数_简单的小伙子的博客-CSDN博客_回调函数js

JS同步执行、异步执行、及同步中的异步执行

首先明确两点:

1.JS 执行机制是单线程。

2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行。

 3 浏览器是单线程执行JavaScript代码的,但是浏览器实际上是以多个线程协助操作来实现单线程异步模型的,具体线程组成如下: 

1.GUI 渲染进程

2.JavaScript 引擎线程

3.事件触发线程

4.定时器触发线程

5.http 请求线程

6.其他线程

1.【主线程】:这个线程用来执行页面的渲染,JavaScript 代码的运行,事件的触发等等。

2.【工作线程】:这个线程是在幕后工作的,用来处理异步任务的执行来实现非阻塞的运行模式。

js的异步执行_理想和远方_在路上的博客-CSDN博客_js异步执行

JS的异步是怎么实现的? 

四个线程参与了JS的执行,但是永远只有JS引擎线程在执行JS脚本程序,其他三个线程只负责将满足触发条件的处理函数推进任务队列,等待JS引擎线程执行。
所以JS异步的实现靠的就是浏览器的多线程,当他遇到异步API时,就将这个任务交给对应的线程,当这个异步API满足回调条件时,对应的线程又通过事件触发线程将这个事件放入任务队列,然后主线程从任务队列取出事件继续执行
原文链接:https://blog.csdn.net/weixin_43845090/article/details/119727502

JS的异步是怎么实现的_程序员的脱发之路的博客-CSDN博客_js异步怎么实现

回调函数本身是同步代码。

JavaScript中的回 调函数结构,默认是同步的结构,由于JavaScript单线程异步模型的规则,如果想要编写异步的代码,必须 使用回调嵌套的形式才能实现,所以回调函数结构不一定是异步代码,但是异步代码一定是回调函数结构。

宏任务和微任务
宏任务: 宏任务是JavaScript中最原始的异步任务,包括setTimeout、setInterVal、AJAX等,在代码执⾏环境中按照同步代 码的顺序,逐个进⼊⼯作线程挂起,再按照异步任务到达的时间节点,逐个进⼊异步任务队列,最终按照队列中的 顺序进⼊函数执⾏栈进⾏执⾏。

微任务: 微任务是随着ECMA标准升级提出的新的异步任务,微任务在异步任务队列的基础上增加了【微任务】的概念,每 ⼀个宏任务执⾏前,程序会先检测中是否有当次事件循环未执⾏的微任务,优先清空本次的微任务后,再执⾏下⼀ 个宏任务,每⼀个宏任务内部可注册当次任务的微任务队列,再下⼀个宏任务执⾏前运⾏,微任务也是按照进⼊队 列的顺序执⾏的。

总结:在JavaScript的运⾏环境中,代码的执⾏流程是这样的:

1. 默认的同步代码按照顺序从上到下,从左到右运⾏,运⾏过程中注册本次的微任务和后续的宏任务:

2. 执⾏本次同步代码中注册的微任务,并向任务队列注册微任务中包含的宏任务和微任务

3. 将下⼀个宏任务开始前的所有微任务执⾏完毕

4. 执⾏最先进⼊队列的宏任务,并注册当次的微任务和后续的宏任务,宏任务会按照当前任务队列的队尾继续向 下排列 
 

单线程的概念

JavaScript是一门单线程语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务

为什么javascript是单线程

其实,JavaScript的单线程,与它的用途是有很大关系,我们都知道,JavaScript作为浏览器的脚本语言,主要用来实现与用户的交互,利用JavaScript,我们可以实现对DOM的各种各样的操作,如果JavaScript是多线程的话,一个线程在一个DOM节点中增加内容,另一个线程要删除这个DOM节点,那么这个DOM节点究竟是要增加内容还是删除呢?这会带来很复杂的同步问题,因此,JavaScript是单线程的。

为什么会有同步和异步

因为JavaScript的单线程,因此同个时间只能处理同个任务,所有任务都需要排队,前一个任务执行完,才能继续执行下一个任务,但是,如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,后一个任务就不得不等着,拿ajax来说,当用户向后台获取大量的数据时,不得不等到所有数据都获取完毕才能进行下一步操作,用户只能在那里干等着,严重影响用户体验

因此,JavaScript在设计的时候,就已经考虑到这个问题,主线程可以完全不用等待文件的读取完毕或ajax的加载成功,可以先挂起处于等待中的任务,先运行排在后面的任务,等到文件的读取或ajax有了结果后,再回过头执行挂起的任务,因此,任务就可以分为同步任务和异步任务

同步任务

同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务

异步任务

异步任务是指**不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,**当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务。

异步机制

那么,JavaScript中的异步是怎么实现的呢?那要需要说下回调和事件循环这两个概念啦

首先要先说下任务队列,我们在前面也介绍了,异步任务是不会进入主线程,而是会先进入任务队列,任务队列其实是一个先进先出的数据结构,也是一个事件队列,比如说文件读取操作,因为这是一个异步任务,因此该任务会被添加到任务队列中,等到IO完成后,就会在任务队列中添加一个事件,表示异步任务完成啦,可以进入执行栈啦~但是这时候呀,主线程不一定有空,当主线程处理完其它任务有空时,就会读取任务队列,读取里面有哪些事件,排在前面的事件会被优先进行处理,如果该任务指定了回调函数,那么主线程在处理该事件时,就会执行回调函数中的代码,也就是执行异步任务啦

单线程从从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有任务,就会等到,直到有新的任务,这就叫做任务循环,因为每个任务都是由一个事件触发的,因此也叫作事件循环

总的来说,JavaScript的异步机制包括以下几个步骤

  1. 所有同步任务都在主线程上执行,行成一个执行栈
  2. 主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
  4. 主线程不断的重复上面的第三步

JS同步执行、异步执行、及同步中的异步执行(promise和then)_有蝉的博客-CSDN博客_异步执行

js中的同步和异步_JosonHo的博客-CSDN博客

微任务和宏任务

1.微任务
包括Promise,process.nextTick

Promise(async/await) => Promise并不是完全的同步,在promise中是同步任务,执行resolve或者reject回调的时候,此时是异步操作,会先将then/catch等放到微任务队列。当主栈完成后,才会再去调用resolve/reject方法执行

process.nextTick (node中实现的api,把当前任务放到主栈最后执行,当主栈执行完,先执行nextTick,再到等待队列中找)

MutationObserver (创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。)

2.宏任务
包括整体代码script,setTimeout,setInterval

定时器

事件绑定

ajax

回调函数

Node中fs可以进行异步的I/O操作
 

JS执行机制(同步、异步、微任务、宏任务)_cc°  淡忘的博客-CSDN博客_js执行机制

JS同步执行、异步执行、及同步中的异步执行(promise和then)_有蝉的博客-CSDN博客_异步执行

 微观任务是不属于事件循环的,它是V8的一个实现,用来实现Promise的then/reject,以及其它一些需要同步延后的callback,本质上它和当前的V8调用栈是同步执行的,只是放到了最后面。除了Promise/MutationObserver,在JS里面发起的请求也会创建一个微观任务延后执行。
 

Script 代码段_weixin_30621711的博客-CSDN博客

Promise

Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。 1.主要是用来解决回调地狱的问题 

3.现在主流的方法是使用async 和 await 来进行解决异步问题。 
4.async 和 await 本质上是一个语法糖 使函数的返回值包含在promise中返回。

 三种状态:

        pending(等待结果)resolved(rizaov已成功) rejected(已失败)

        pending -> resolved 或 pending -> rejected

         变化不可逆

   状态的表现和变化:

        pending状态,不会触发 then 和 catch

        resolved状态,会触发后续的 then 回调函数

        rejected状态,会触发后续的 catch 回调函数、

    then 和 catch 对状态的影响

then 正常返回resolve状态的promise,如果有报错,返回的是reject

catch正常返回resolve状态的promise,如果有保持,返回的是reject

3 resolve会触发then的回调, reject会触发catch的回调
 

promise详解_土豆切成丝的博客-CSDN博客_promise详解

JavaScript 异步 实现异步的五种实现方法


1.promise 为了让异步任务顺序执行,解决地狱回调
2.window.fetch H5新增的拉取资源的 api  1.通过.then() 2.数据序列化 3.通过.then()获取数据
3.jquery.deffered  延期对象 为了让创建的deffered对象的时候和异步任务属于同步代码的结果,并且能够保证deffered(延期)和promise进行转换 def实例转化成promise实例返回
4.async和awit 实质上是对Promise()对象提供的 -语法糖-. 让代码更简洁.通过同步代码的形式来实现异步操作

5.webwork 创建分线程为了让任务在多线程去执行,防止复杂逻辑阻塞线程

JavaScript 异步 实现异步的五种实现方法_满脑子技术的前端工程师的博客-CSDN博客_js异步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值