2021前端必问面试题及答案

web前端面试题【持续更新】

推荐使用网页查看,可以点击问题跳转到解析,持续更新中,祝大家都能找到合适的工作~
【个人学习笔记,包含各种前端,及工作中遇到的问题,欢迎大家关注我
会持续更新基本每天都更新
(╹▽╹) 笔记地址地址:十二的前端笔记-语雀

js基础

原型链和继承

在这里插入图片描述
原型链:js对象独有的__proto__属性,当访问一个对象的属性时,如果该对象内不存在这个属性,会去它的__proto__属性所指向的那个对象(父对象)里找,直到null
proto:对象都有私有属性__proto__(),从对象指向实例原型
prototype:函数独有的属性,从一个函数指向一个对象,包含所有实例可共享的属性和方法,任何函数创建时,会默认创建该函数的prototype对象
constructor:实例的构造函数(constructor)属性,指向实例
所有函数和对象最终都是由Function构造函数得来,所以constructor属性的终点就是Function这个函数。

  1. prototype指向的原型对象又有一个属性constructor,这个属性也是一个指针,指回原构造函数,即这个方法。
  2. __proto__和constructor属性是对象所独有的,prototype属性是函数所独有的。
  3. JS中函数也是一种对象,所以函数也拥有__proto__和constructor属性
  4. 为什么有prototype,如果没有,每次新建对象都会继承构造函数的所有属性,方法,浪费性能,用了prototype后,属性每个对象的值相同性不高,写在构造函数里,而方法通常是通用的,使用prototype可以让每个对象共享同一个方法,而不用每次都copy一个,而且能实时更新
  5. https://www.cnblogs.com/tylerdonet/p/9595436.html
  6. 为什么使用prototype
浅拷贝和深拷贝

基本数据类型:名字和值都存在栈中
引用数据类型:名字在栈中,值在堆中,栈内存会提供一个引用地址,指向堆内存中的值
浅拷贝:1.for只遍历第一层 2.assign 3. =直接赋值
深拷贝:1.递归遍历所有层级 2.利用JSON对象【JSON.stringfy() JSON.parse()】 3.通过jQuery的extend方法实现深拷贝 4.lodash函数库实现深拷贝 5.用slice实现对数组的深拷贝,slice() 方法可从已有的数组中返回选定的元素。6.使用扩展运算符实现深拷贝 8.Reflect法 9.用concat实现对数组的深拷贝 10.直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。11.手动实现深拷贝 7.如对象的value是基本类型,可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象
assign第一层是深拷贝,第二层以后是浅拷贝

function deepClone2(obj) {
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
} // 无法实现对对象中方法的深拷贝,会显示为undefined

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝

let result = _.cloneDeep(test)

栈和堆

js中的堆和栈
  • 栈(stack):简单地数据段,存放在栈中,有固定大小的内存(自动分配),自动释放
    • 基本数据类型:number,string,boolean,undefined,null
    • 栈存储了什么:变量名,基本数据类型值,地址
    • 全局作用域,私有作用域,都属是栈内存,理论上,存储的越少,运行速度越快
    • 先进后出
    • 栈内存回收:作用域销毁(立即销毁,不销毁,不立即销毁)
      • 全局作用域销毁:一般情况不销毁,页面关闭,整个作用域销毁
      • 私有作用域销毁 :
        • 不销毁
        • 销毁
        • 不立即销毁
  • 堆(heap):动态分配内存,大小不定也不会自动释放
    • 引用类型:栈中存放地址,指向堆中的对象,当我们要获取(函数,数组,对象等)的时候,先从栈中获取地址,然后从堆中获取数据
    • 先进先出
    • 堆存储了什么:引用数据类型的值
    • 内存回收:GC垃圾回收机制
      • chrome:标记法,每隔一段时间对所有的空间地址检测,如果没有被占用,立即回收
      • ie和火狐:计数法,空间地址被占用一次+1,空闲一次空间地址-1,如果为0 被回收
闭包

闭包:https://www.yuque.com/nizhidaoba/ufw9so/no2gre
闭包函数:声明在一个函数中的函数,叫做闭包函数。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
参数和变量不会被垃圾回收机制回收

function a() {
    var name = 'Shier'
    return function(){
        return name
    }
}
var b = a()
console.log(b())
// 通过返回函数中返回的内部变量,使函数外部能够使用和访问函数内部变量
setTimeout

setTimeout有两个参数,第一个参数为一个函数,我们通过该函数定义将要执行的操作。第二个参数为一个时间毫秒数,表示延迟执行的时间。

var timer = setTimeout(function() {
    console.log('如果不清除我,我将会一秒之后出现。');
}, 1000)

clearTimeout(timer);  // 清除之后,通过setTimeout定义的操作并不会执行
for (var i=1; i<=5; i++) { 
    setTimeout( function timer() {
        console.log(i);
    }, i*1000 );
}
// 上述结果返回总为6
for (var i=1; i<=5; i++) { 
    (function(i) {
        setTimeout( (function timer() { // 或者在这里使用闭包
            console.log(i);
        })(i), i*1000 );
    })(i)
}
// 使用闭包将值存住,输出为123456

console的返回值中,会有两行,一行是一个唯一的id,其他的是输出的内容
每个setTimeout在执行时,会返回一个唯一ID。在使用时,常常会使用一个变量将这个唯一ID保存起来,用以传入clearTimeout,清除定时器。

事件委托

DOM事件流:事件捕获,目标阶段,事件冒泡
addEventListener(‘click’,function(event){触发事件}, false)默认在事件冒泡阶段触发,默认值false
事件委托:event.currentTarget:事件绑定的元素(绑定在父级元素)
event.target:触发事件的源头(所点击的子元素)target:事件目标
事件委托利用了事件冒泡和event.target,当有一系列子元素都需要绑定事件时,只需要将事件绑定在父元素即可

this指向,call/apply/bind,回调函数

a.一般函数,this指向全局对象window;
b.在严格模式下"use strict",为undefined.
c.对象的方法里调用,this指向调用该方法的对象. 【this指的是,调用函数的那个对象】
d.构造函数里的this,指向创建出来的实例.
call,apply,bind,改变函数运行时的指向,当第一个参数为null或undefind时,指向window
call:传入参数列表,改变函数指向并立即调用,第一个参数同apply,第二个参数必须是单个参数列表,不能是数组
apply:可以传入数组,第一个参数:要绑定给this的值 第二个参数:参数列表(可以是数组)
bind:改变this指向后,返回的是函数

var obj = {
    name: 'Dot'
}
function printName() {
    console.log(this.name)
}
var dot = printName.bind(obj)
console.log(dot) // function () { … }
dot()  // Dot
//bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。
//而原函数 printName 中的 this 并没有被改变,依旧指向全局对象 window。
   var a = 1
    var obj1 = {
      a:2,
      fn:function(){
        console.log(this.a)
      }
    }
    obj1.fn()//2    
//此时的this是指obj1这个对象,obj1.fn()
//实际上是obj1.fn.call(obj1),事实上谁调用这个函数,this就是谁

点击页面,依次输出:document和window对象
解析:点击页面监听click事件属于方法调用,this指向事件源DOM对象,即obj.fn.apply(obj),setTimeout内的函数属于回调函数,可以这么理解f1.call(null,f2),所以this指向window。

document.addEventListener('click', function(e){
    console.log(this);
    setTimeout(function(){
        console.log(this);
    }, 200);
}, false);
数组的常用操作

concat() 连接两个或更多的数组,并返回结果。
join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
pop() 删除并返回数组的最后一个元素
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reverse() 颠倒数组中元素的顺序。
shift() 删除并返回数组的第一个元素
slice() 从某个已有的数组返回选定的元素
sort() 对数组的元素进行排序
splice() 删除元素,并向数组添加新元素。
toSource() 返回该对象的源代码。
toString() 把数组转换为字符串,并返回结果。
toLocaleString() 把数组转换为本地数组,并返回结果。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
valueOf() 返回数组对象的原始值。

set和weakset,map和weakmap

set:不重复的值得集合【let set = new Set([1, 2, 2, 3]) // [1, 2, 3]
add(value):添加某个值,返回 Set 结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。—
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
weakSet:成员只能是对象
map

typeof原理

instanceOf,Object.prototype.toString.call()的区别

0.1+0.2 === 0.3吗,为什么

不等于,因为浮点数计算是不精确的

前端安全 xss 和 csrf
说明BFC及其使用
js基本数据类型

【基本类型 5】string、number(浮点数,整数,NAN)、boolean、null、undefined
【引用类型 1】object(data,function,array)
【es6 1】symbol
【bigInt】Javascript 中的任意精度整数,可以安全存储和操作大整数。即始超出 Number 能够表示的安全整数范围。是 chrome 67中的新功能。

循环

for:for(let i=0; i<10; i++)i:下标 arr[i]:值
for…each: arr.forEach((item,index) => {}) 遍历数组,不能使用break,contintue,return
for…in:for (var i in arr){ // i是下标(索引)} i:下标 arr[i]:值 原型链上的所有属性都将被访问 arr.hasOwnProperty(i)可以判断是否在实例上,在实例上才会被返回
for…of: 只能遍历数组
map: 有返回值,可以返回结果数组,不能遍历对象,只能遍历数组或对象数组
var arr = [‘星期一’, ‘星期二’, ‘星期三’];
var a = arr.map(function(item){
console.log(item)
return item === ‘星期二’
})
console.log(a)

Js数组都有哪些方法及其作用、用法、返回值?详细说了一下splice()
Js数组去重

1.new Set(arr)
2.for嵌套,两层循环,如果第二个等于第一个,删掉第二个,用splice方法
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
注释:该方法会改变原始数组。
3.indexOf:建一个空数组,循环目标数组,判断新数组中是否有当前单参数,没有就push,有就跳过
4. includes:查找数组中是否有某个元素

说明冒泡排序、插入排序实现的思想、步骤、每趟的结果等
什么是二分查找
HTTP协议相关:请求头、响应头、状态码(5大类)、报文格式,一次http完整的过程,详细说一下Accept - Encoding的作用,和性能有关系?http有哪些请求方式?Get和post的区别?
Ajax相关:如何实现,用jQuery实现一个ajax,有没有看过jQuery内部是如何实现的?说说链式调用
什么是Cookie和Session?他们的区别?Js实现cookie和session两者有联系吗?是什么?localStorage、sessionStorage, cookie
垂直居中布局 4中
浮动引起的问题,如何清除浮动【4种

高度塌陷:
父元素在文档流中高度默认是被子元素撑开的,当子元素脱离文档流以后,将无法撑起父元素的高度,也就会导致父元素的高度塌陷。父元素的高度一旦塌陷, 所有标准流中元素的位置将会上移,导致整个页面的布局混乱
解决方法:
(1)浮动元素后添加

添加清除浮动样式,使用这种方式会在页面中添加多余的结构。
.clear{
clear:both
}

(2)使用after伪类,向父元素后添加一个块元素,并对其清除浮动。该种方式的原理和方法一原理一样,但是不用向页面中添加多余的结构。
#div::after {
content: “”;
display: block;
clear: both
}

(3)开启父元素的BFC,为父元素添加样式
overflow:hidden;

(4)手动为父元素添加高度。

postion和z-index的关系?

position四种定位方式:
static:默认值,不接受top等参数
fixed:依据窗口定位(fixed定位在IE7和IE8下需要描述!DOCTYPE才能支持。)
relative:相对于自身的位置
absolute:相对于最近的定位的父元素,如果都没有,相对于html
sticky:固定一部分内容,类似于吸顶的效果
z-index的作用:z轴上的层级问题

DOM操作:获取、增、删、查、改等操作

创建:
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
添加:appendChild()
移出:removeChild()
替换:replaceChild()
插入:insertBefore()
复制:cloneNode(true)
查找:
getElementsByTagName() //通过标签名称
getElementsByClassName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性

JS交换两个节点如何实现?
a b
tcp三次握手四次挥手
如何设置一个元素不可见 4中

1)opacity:0;不显示,占据空间
2)visibility: hidden; 属性会继承,如果子元素想可见,需要visibility:visible
3)display: none; 盒模型不生成
4)z-index:-999

什么是跨域问题,有哪些跨域方式
JS 异步解决方案的发展历程以及优缺点
行内元素和块元素区别,image 标签属于哪种
eval

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
a=[1,3,5,9]
r=eval(a.join(’+’))
var numbers = [65, 44, 12, 4];

function getSum(total, num) {
return total + num;
}
function myFunction(item) {
document.getElementById(“demo”).innerHTML = numbers.reduce(getSum);
}

Object.assign()

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

reduce 求和

arr.reduce(callback,[initialValue])
callback (执行数组中每个值的函数,包含四个参数)

1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)

initialValue (作为第一次调用 callback 的第一个参数。)
//简单用法:求和求积
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x,y)=>x+y)
var mul = arr.reduce((x,y)=>x*y)
console.log( sum ); //求和,10
console.log( mul ); //求乘积,24
//高级用法
//(1)计算数组中每个元素出现的次数
//(2)数组去重
//(3)将二维数组转化为一维
//(4)将多维数组转化为一维
//(5)、对象里的属性求和

普通函数和构造函数

普通函数:无返回值,person()调用,
构造函数:返回实例对象,let per = new Person()调用,内部用this来构造属性和方法
构造函数流程:
1.立刻在堆内存中创建一个对象
2.将新建的对象设置为函数中的this
3.逐个执行函数中的代码
4.将新建对象作为返回值
function Person(name,job,age)
{
this.name=name;
this.job=job;
this.age=age;
this.sayHi=function()
{
alert(“Hi”)
}
}

ES6

let,const

1)let和const不存在变量提升
2)let:块级作用域
3)const:声明的变量不允许改变,声明的时候必须赋值
4)对于复合类型的变量(如数组,对象),const保存的只是地址,里面的内容是可以改变的,想要整个对象都不允许改变,可以使用Object.freeze()方法
5)一切用var声明的全局变量都是window的属性
6)有声明和没有声明的全局变量都会成为window的属性,有什么区别呢?
没有声明的变量可以被删除,而声明的不可以
7)用let ,const 和 calss声明的全局变量不归window所有

解构赋值

数组解构:可以设置默认值,可以赋值给新数组(修改新数组不会改变老数组)

let a = [0,1,2,3]
let b = [...a]
b.push(4)
console.log(a) // [0,1,2,3]
console.log(b) // [0,1,2,3,4]

对象解构:对象的解构赋值是根据key值进行匹配

let {name="swr",age} = {age:28} // 默认值

给函数传不确定参数数量时,是通过arguments来获取的

function sum(...args){ // 使用...扩展运算符,arg要放在最后一个参数
    //使用原始的arguments。是个伪数组,不利于操作,...args是数组方便操作
    console.log(args) // [ 1, 2, 3, 4, 5, 6 ] args是一个数组
    return eval(args.join('+'))
}

console.log(sum(1,2,3,4,5,6)) // 21

// 但是可以用Array.from把伪数组转为数组
let likeArr = { "0":1,"1":2,"length":2 }
let arr = Array.from(likeArr)
console.log(arr) // [1,2]
set、weakSet、map、weakMap
proxy
generator
reflect
async、await
class
promise
箭头函数

不适合使用箭头函数的场景

  1. 对象中的方法
 const obj = {
    x: 1,
    print: () => {
        console.log(this === window); // => true
        console.log(this.x); // undefined
    }
};

obj.print();
//解析:print 方法用了箭头函数,其内部的 this 指向的还是上下文 window
//上下文中并没有定义 x,所以 this.x 输出为 undefined。
//解决办法:用 ES6 的短语法,或者传统的函数表达式print(){}都可以。
  1. 原型中的方法
function Cat (name) {
    this.name = name;
}
Cat.prototype.sayCatName = () => {
    console.log(this === window); // => true
    return this.name;
};
const cat = new Cat('Miao');
cat.sayCatName(); // => undefined
// 使用箭头函数会导致运行时的执行上下文错误
Cat.prototype.sayCatName = function () {
    console.log(this === cat); // => true
    return this.name;
};
// sayCatName 变回传统的函数表达式之后,被调用时的执行上下文就会指向新创建的 cat 实例。
  1. 事件的回调
  2. 构造函数
    箭头函数的用法

vue

keep-alive
mixins

https://zhuanlan.zhihu.com/p/62729974
2.写 React/Vue 项目时为什么要在组件中写 key,其作用是什么?
key 的作用是为了在 diff 算法执行时更快的找到对应的节点,提高 diff 速度。vue 和 react 都是采用 diff 算法来对比新旧虚拟节点,从而更新节点。在 vue 的 diff 函数中。可以先了解一下 diff 算法。
在交叉对比的时候,当新节点跟旧节点头尾交叉对比没有结果的时候,会根据新节点的 key 去对比旧节点数组中的 key,从而找到相应旧节点(这里对应的是一个 key => index 的 map 映射)。如果没找到就认为是一个新增节点。而如果没有 key,那么就会采用一种遍历查找的方式去找到对应的旧节点。一种一个 map 映射,另一种是遍历查找。相比而言。map 映射的速度更快。

r o u t e 和 route和 routerouter的区别

$route: 正在跳转的路由对象,可以从里面获取name,path,params,query等
r o u t e r : 是 v u e R o u t e r 的 实 例 , 相 当 于 一 个 全 局 的 路 由 对 象 , 包 含 很 多 属 性 和 子 对 象 , 例 如 h i s t o r y 对 象 , t h i s . router:是vueRouter的实例,相当于一个全局的路由对象,包含很多属性和子对象,例如history对象,this. router:vueRouterhistorythis.router.push()

react

有状态组件和无状态组件

性能更高,因为他就是一个函数
由于是无状态组件,所以,无论props会否变更,都会重新刷新这个组件
https://segmentfault.com/a/1190000016774551
const head = (props) => {
return

{props.name}

}

immutable.js

https://www.jianshu.com/p/825b7b4c401d

生命周期函数
react哪些生命周期可以执行setState
高阶组件

https://segmentfault.com/a/1190000019834626
https://www.jianshu.com/p/0aae7d4d9bc1

setState

在this.setState({})之后打印信息,会出现延迟,想要同步需要在this.setState({},()=>{回调函数}),在回调函数中打印数据,可以同步

pureCompoent 和 compoent

https://www.jianshu.com/p/c41bbbc20e65

hook和class对比

https://www.jianshu.com/p/b666ac2407b0

redux

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html

打包和优化

npm和npx

npm常用操作
https://www.nowcoder.com/ta/front-end

重绘和重排

https://www.cnblogs.com/soyxiaobi/p/9963019.html

__dirname 路径名 __filename 文件名

如果没有传入 path 片段,则 path.resolve() 会返回当前工作目录的绝对路径。
console.log(__filename);
// 打印: /Users/mjr/example.js
console.log(__dirname);
// 打印: /Users/mjr

webpack官网
Webpack打包原理,如何实现等
优化vue

1)source-map:false:不生成.map文件
2)路由中配置reslove 按需加载
3)大的三方包:echert等,用《script标签引入,webpack中去掉这些打包

前端如何处理十万级别的大量数据

worker:https://juejin.im/post/6844903821278199822?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com

后台返回大量数据(百万级)页面接收问题

tomcat的压缩机制:https://blog.csdn.net/baidu_16250655/article/details/88688299

nvm,node,npm

nvm:nodejs 版本管理工具。一个 nvm 可以管理很多 node 版本和 npm 版本。
nodejs:在项目开发时的所需要的代码库
npm:nodejs 包管理工具。
在安装的 nodejs 的时候,npm 也会跟着一起安装,它是包管理工具。
npm 管理 nodejs 中的第三方插件
关系:
nvm 管理 nodejs 和 npm 的版本
npm 可以管理 nodejs 的第三方插件

面试真题

14-22 14 (2020-12-3)
  1. es6的assign能不能深拷贝:第一层是深拷贝,第二层是浅拷贝
  2. Json.string fly能深拷贝吗有什么问题:
  3. 异步回调地狱怎么解决:promise,async/await
  4. Promise和回调函数性能问题
  5. chrome中查看内存泄漏
  6. React移除组件用哪个函数:componentWillUnmount()
  7. react更改数据的方法:this.setState()
  8. this.setstate什么时候传回调函数
  9. 加载数据在willmontd有什么问题,那应该在哪个生命周期加载
  10. React的mvvm表示哪部分代码
  11. 循环的时候使用key为什么
  12. Async 可以停止吗
11-22(2020-12-4)
  1. List item
  2. js数据类型
  3. this指向,如何修改this指向问题
  4. 跨域有几种解决方式
  5. 回调函数是什么,有什么问题,什么时候会发生内存泄露
  6. promise有几种状态,有什么静态方法
  7. js设计模式
  8. 数据结构
  9. 函数柯里化
  10. es6:泛型,proxy,reflect,迭代器
  11. ts:注释,装饰器
  12. react的super为什么要写,有什么作用
  13. 高阶函数是什么
  14. react传值问题
  15. 做一个及时聊天功能的思路
13-20 (2020-12-15)
  1. app中的桥是异步的还是同步的
  2. 异步async await方法内部是什么
  3. 还用过哪些es6方法
  4. http和https的区别,能相互请求吗
  5. 为什么选择sass ,是做什么用的
  6. app兼容性布局,除了rem还可以用什么rpx
  7. 跨域是用什么实现
  8. 前端请求中间层,axios拦截
  9. Nginx除了代理还能做什么,代理的原理是什么
  10. Webpack做过哪些配置
  11. sessionstroage localstroage cookie的区别
  12. 小程序中和vue页面中的数据不通,如何解决
  13. app中数据和vue页面数据不互通如何解决
  14. echart 底层用什么实现的,有什么坑吗
  15. spa单页面应用,如何加快首次加载的速度
  16. 更新小程序或者app包的时候,如何解决缓存问题
2019-7-14
  1. vue的虚拟dom
  2. es6与数组有关的操作
  3. ajax原生
  4. vuex相关的用法
  5. vue的子父传值
  6. 前端安全问题
  7. cookie,session,localstorage用法区别
  8. vue的路由如何传值
  9. var,let,const的区别
  10. forEach,map的区别
  11. 数组的浅拷贝和深拷贝
2019-7-15
  1. 浏览器一个http请求过程
  2. http运行js为什么是单线程的
  3. js的事件绑定,事件监听,事件委托
  4. vue生命周期以及作用
  5. es6的箭头函数
2019-7-22
  1. css如何清除浮动
  2. 浮动会带来什么问题
  3. 居中的方法
  4. 盒模型
  5. flex兼容到ie几
  6. 事件代理
  7. 数组展开
  8. 作用域
  9. var let const的区别
  10. 改变this指向
  11. react的生命周期
  12. 项目中的图片懒加载
  13. 项目中的tree组件是如何编写的
  14. 左边200px固定,右边自适应布局(清除浮动的方法)
  15. this指向
  16. 事件代理
  • 79
    点赞
  • 785
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值