面试题 之 JavaScript

1.js的数据类型以及存储上的差别?

基本类型:
Number
String
Boolean
Undefined
null
symbol

引用类型
Object
Array
Function

其他类型
Date RegExp Map Set

总结:
声明变量时不同的内存地址分配:
简单类型的值存放在栈中,在栈中存放的是对应的值
引用类型对应的值存储在堆中,在栈中存放的是指向堆内存的地址
不同的类型数据导致赋值变量时的不同:
简单类型赋值,是生成相同的值,两个对象对应不同的地址
复杂类型赋值,是将保存对象的内存地址赋值给另一个变量

2.说说你了解的js数据结构?

数组
栈:
遵循后进先出原则的有序集合
队列:
遵循先进先出原则的一组有序的项
链表
字典:
以键值对存储数据的数据结构
散列表:
哈希表,散列表插入删除和取用数据很快


3.DOM常见的操作有哪些?

创建节点
查询节点
更新节点
添加节点
删除节点

4.BOM的理解?常见的BOM对象你了解哪些?

BOM是浏览器对象模型,提供独立于内容与浏览器窗口进行交互的对象,核心对象是window

loaction
navigator
history

5. == 和 === 区别?

在java Script中存在隐式转换,==在比较中会先进行类型转换再确定操作数是否相等, ===类型相同值也相同

6.typeof 与 instanceof区别?

typeof 会返回一个变量的基本类型, instanceof 返回的是一个布尔值
instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型,type可以判断基础数据类型

7.js原型,原型链?

原型:所有的函数默认都有一个“prototype”这样公有且不可枚举的属性,它会指向另一个对象,这个对象就是原型。
原型链:当访问对象的属性或方法时,首先对象会从自身去找,找不到就会往原型中去找,也就是它构造函数的“prototype”中,如果原型中找不到,即构造函数中也没有该属性,就会往原型后面的原型上去找,这样就形成了链式的结构,称为原型链。

8.说说对作用域链的理解?

作用域即变量和函数能被访问的区域。
作用域分成
1️⃣全局作用域:声明的变量可以在程序的任意位置访问
2️⃣函数作用域:也就是局部作用域,只能在函数内部访问
3️⃣块级作用域:let和const变量声明在块级作用域,大括号外不能访问这些变量

9.js中关于this指向的问题

1.全局对象中的this指向指向的是window
2.全局作用域或者普通函数中的this指向全局window
3.this永远指向最后调用它的那个对象在不是箭头函数的情况下
4.new 关键词改变了this的指向
5.apply,call,bind可以改变this指向
6.箭头函数中的this它的指向在定义的时候就已经确定了箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window
7.匿名函数中的this永远指向了window,匿名函数的执行环境具有全局性,因此this指向window

10.说说new操作符具体干了什么?

new操作符用于创建构造函数的实例对象。
工作流程:
创建一个新的对象obj
将对象与构建函数通过原型链连接起来
将构建函数中的this 绑定到新建的对象 obj上
根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理

11.bind、call、apply区别?

bind、call、apply作用是改变函数执行时的上下文,改变函数运行时this指向。
区别:
三者都可以改变函数的this 对象指向
三者第一个参数如果为空默认指向window
三者都可以传参,但是 apply 是数组,而 call 是参数列表,且 apply 和call 是一次性传入参数,而bind 可以分为多次传入
bind 是返回绑定this之后的函数,apply 、call 则是立即执行

12.js中执行上下文和执行栈是什么?

执行上下文分为:
1️⃣全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象
2️⃣函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
3️⃣Eval 函数执行上下文: 指的是运行在 eval 函数中的代码

执行上下文周期:
1️⃣创建阶段
2️⃣执行阶段
3️⃣回收阶段

执行栈:
具有后进先出结构,用于存储在代码执行期间创建的所有执行上下文,当js引擎开始执行第一行脚本代码时就会创建一个全局执行上下文然后将它压到执行栈中,每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中,当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

13.说说js中的事件模型?

事件模型分为三种:
原始事件模型:事件绑定监听函数
标准事件模型:有三个过程事件捕获阶段,事件处理阶段,事件冒泡阶段
IE事件模型:有两个过程事件里处阶段,事件冒泡阶段

14.什么是事件代理?应用场景?

元素响应事件的函数委托到另一个元素,事件流有三个阶段捕获阶段,目标阶段,冒泡阶段,事件委托在冒泡阶段
事件有:click mousedown mouseup keydown keyup

15.普通函数与箭头函数的区别

箭头函数的this是定义时决定的,普通函数是看调用方法。
箭头函数不能成为构造函数
箭头函数不能使用call、apply、bind来修改this指向
箭头函数不绑定arguments ,…剩余参数
箭头函数不具有prototype原型对象,不具有super,不有new

16.闭包函数的理解?

函数内嵌套函数,内部函数被外部函数返回并且保存下来时,就会产生闭包。闭包可以访问外部的变量,但外部的变量不能访问内部的,闭包可以保持对定义时的作用域的引用,使之不能被销毁。
特点:可以重复利用变量,并且这个变量不会被污染全局的一种机制,这个变量是一直保存在内存中,不会被垃圾回收机制和回收。
缺点:闭包多的时候,会消耗内存,导致页面性能的下降,在IE浏览器中会导致内存泄露。
作用:就是保护变量,防止命名冲突,保护作用域
使用场景:防抖,节流,函数嵌套函数避免全局污染。

17.防抖和节流,应用场景

防抖和节流都是防止某一时间频繁触发,但是原理却不一样。
防抖是将多次执行变为只执行一次,节流是将多次执行变为每隔一段时间执行。
防抖(debounce):
search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
节流(throttle):
鼠标不断点击触发,mousedown(单位时间内只触发一次)
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

18. var let const区别

变量提升:
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined,let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错

暂时性死区:
var 不存在暂时性死区
let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
块级作用域
var 不存在块级作用域
let和const存在块级作用域
重复声明:
var允许重复声明变量
let和const在同一作用域不允许重复声明变量
修改声明的变量:
var和let可以
const一旦声明常量的值就不能改变(实际上保证的并不是常量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动

19.js是如何实现继承?

1.原型链继承
让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。
优点:写法简单易理解
缺点:对象实例共享所有继承的属性和方法。无法向父类构造函数传参
2.构造函数继承
在子类型构造函数的内部调用父类型构造函数,使用apply()或call()方法将父对象的构造函数绑定在子对象上。
优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。
缺点:借用构造函数的缺点是方法都在构造函数中定义, 因此无法实现函数复用。
在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。
3.组合继承
将原型链和构造函数的组合到一块,使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例的继承。这样,既通过了原型在定义方法实现了函数复用,又能保证每一个实例都有自己的属性。
优点:解决了原型链继承和构造函数继承造成的影响
缺点:无论在什么情况下,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部
4.ES6、Class实现继承
class通过extends关键字实现继承,其实质是创造出父类的this对象,然后用子类的构造函数修改this子类的构造方法中必须调用super 方法,且只有在调用了super 之后才能使用this, 因为子类的this对象是继承父类的this对像,然后对其进行加工,而super方法表示的是父类的构造函数,用来新建父类的this对象。

20.promise的使用场景

处理异步回调
多个异步函数同步处理
异步依赖异步回调
封装统一的入口办法或者错误处理

21.promise的状态和方法

Promise 有三种状态:
pending 进行中
fulfilled 已成功
rejected 已失败

Promise 方法:
1️⃣ Promise 构造函数用于创建一个新的 Promise 对象。它接受一个函数作为参数,该函数有两个参数 resolve 和 reject,分别表示异步操作成功和失败时的回调函数。
2️⃣ Promise.then() 方法用于注册异步操作成功时的回调函数。它接受一个回调函数作为参数,该回调函数的参数是异步操作成功时返回的数据
3️⃣Promise.catch() 方法用于注册异步操作失败时的回调函数。它接受一个回调函数作为参数,该回调函数的参数是异步操作失败时返回的错误
4️⃣Promise.all() 方法用于同时处理多个 Promise 对象。它接受一个 Promise 对象数组作为参数,返回一个新的 Promise 对象。当所有的 Promise 对象都成功时,新的 Promise 对象才会成功;当任何一个 Promise 对象失败时,新的 Promise 对象就会失败
5️⃣Promise.race() 方法用于处理多个 Promise 对象,它接受一个 Promise 对象数组作为参数,返回一个新的 Promise 对象。当任何一个 Promise 对象成功或失败时,新的 Promise 对象就会成功或失败

22.WebSocket的原理

WebSocket 是一种全双工通信协议,通过建立持久性的连接,客户端和服务器可以随时发送和接收消息。连接建立后,双方可以直接发送消息,不需要频繁的握手过程。

23.WebSocket 工作原理

WebSocket 的工作原理可以分为三个阶段:握手、数据传输和断开连接
握手:客户端发起 WebSocket 连接时,通过向服务器发送一个特殊的 HTTP 请求头来建立连接。服务器检查请求头中的特定字段,确认支持 WebSocket 协议后,发送特殊的 HTTP 响应头进行握手确认。握手成功后,双方建立了 WebSocket 连接,可以进行后续的数据传输。
数据传输:一旦建立了 WebSocket 连接,客户端和服务器可以通过该连接进行双向的实时数据传输。双方可以发送和接收消息,消息以帧的形式进行传输。WebSocket 协议定义了不同类型的帧,如文本帧和二进制帧,用于传输不同类型的数据。
断开连接:当连接不再需要时,客户端或服务器可以发起关闭连接的请求。双方会交换特殊的关闭帧,以协商关闭连接,并确保双方都接收到了关闭请求。

24.WebSocket技术的应用场景

实时通信:WebSocket技术可以实现实时通信,比如在线聊天、实时游戏等。
数据推送:WebSocket技术可以在服务器端主动向客户端推送数据,比如股票行情、天气预报等。
实时监控:WebSocket技术可以实现实时监控,比如视频监控、设备状态监控等

25.WebSocket技术的使用

WebSocket客户端:WebSocket客户端是指使用WebSocket技术的浏览器或应用程序。
WebSocket服务器:WebSocket服务器是指提供WebSocket服务的服务器。
WebSocket URL:WebSocket URL是指WebSocket服务器的地址,格式为ws://或wss://。
在使用WebSocket技术时,需要先创建一个WebSocket对象,然后通过该对象与服务器进行通信。WebSocket对象有以下几个常用的方法:
WebSocket.open():打开WebSocket连接。
WebSocket.send():向服务器发送数据。
WebSocket.close():关闭WebSocket连接。

25. 0.1+0.2==0.3?为什么会出现计算精度丢失的问题?

不等于,等于0.30000000000000004
JavaScript采用的是双精度浮点数表示法导致的
解决方法:
1️⃣同时扩大倍数再除以相同的倍数
0.1 +0.2 // 0.30000000000000004 (0.1 *10 + 0.2 *10) / 10 // 0.3
2️⃣pnpm add mathjs 使用插件

26.JS微任务和宏任务

微任务:Promise 回调函数,宏任务:setTimeout 回调函数
微任务和宏任务的执行顺序不同,微任务是指在当前任务执行结束后立即执行的任务,宏任务只有在所有微任务执行完毕后才会执行。将一些耗时的操作放入宏任务队列中,从而避免阻塞当前任务的执行,这样可以使页面在执行这些代码的同时仍然保持响应,提高用户体验

27.什么是深拷贝和浅拷贝

基本数据类型:string、number、boolean、undefined、null、Symbol(ES6,符号类型)
引用数据类型:object、array、function
JS数据类型分为基本数据类型和引用数据类型,基本数据类型保存的是值,引用类型保存的是引用地址(this指针)。浅拷贝共用一个引用地址,深拷贝会创建新的内存地址。

28.数组常用的方法?哪些方法会改变原数组,哪些不会

会改变原数组:
pop (删除数组的最后一个元素并返回删除的元素)
push(向数组的末尾添加一个或更多元素,并返回新的长度)
shift(删除并返回数组的第一个元素)
unshift(向数组的开头添加一个或更多元素,并返回新的长度)
reverse(反转数组的元素顺序)
sort(对数组的元素进行排序)
splice(用于插入、删除或替换数组的元素)
不会改变原数组:
concat—连接两个或更多的数组,并返回结果。
every—检测数组元素的每个元素是否都符合条件。
some—检测数组元素中是否有元素符合指定条件。
filter—检测数组元素,并返回符合条件所有元素的数组。
indexOf—搜索数组中的元素,并返回它所在的位置。
join—把数组的所有元素放入一个字符串。
lastIndexOf—返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
map—通过指定函数处理数组的每个元素,并返回处理后的数组。
slice—选取数组的的一部分,并返回一个新数组。
valueOf—返回数组对象的原始值

29.前端的内存泄漏理解?

JS里已经分配内存地址的对象,但由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源大幅度的浪费,最终导致运行速度变慢,甚至崩溃的情况。
垃圾回收机制
因素:一些为生命直接赋值的变量,一些未清空的定时器,过度的闭包

30.cookie,sessionstorage和localstroage的区别?

Cookie在浏览器和服务器间来回传递,默认关闭浏览器后失效
Sessionstorage仅在当前网页下有效,关闭页面或者浏览器就会被清除
Localstorage需要手动清除,否则将会永久保存
Sessionstorage和loaclstorage的存储空间更大
Sessionstorage和loaclstorage有更多丰富易用的接口
Sessionstorage和loaclstorage各自独立的存储空间

31.js同源策略

同源策略指的是协议,域名,端口相同,同源策略是一种安全协议。一段脚本只能读取来自同一来源的窗口和文档的属性

32.http与https区别

http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
http和https使用的是完全不同的链接方式,端口号也不一样前者是80后者是443
http连接很简单,是无状态的,https协议是由ssl+http协议构建的可进行加密传输,身份认证的网络协议,比http协议安全

33.es6特性

1、let 和 const
let 表示申明变量。const 表示申明常量
常量定义了就不能改了。对象除外,因为对象指向的地址没变。
两者都为块级作用
2、模板字符串,定义多行字符串,或者在字符串中嵌入变量。
3、解构,可以将数组或对象“拆包”至一系列变量中
6、箭头函数
7、for of
for of遍历的是键值对中的值
for in遍历的是键值对中的键
8、class类,原型链的语法糖表现形式
9、导入导出
导入improt
导出export default
10、promise
Promise 用于更优雅地处理异步请求。
11、async/await
比promise更好的解决了回调地狱
12、Symbol,新的基本类型
13、Set集合
存储任何类型的唯一值,即集合中所保存的元素是不重复的。类数组结构。
let arrNew = new Set(待去重的数组)
14、Object.keys()方法,获取对象的所有属性名或方法名
15、Object.assign ()原对象的属性和方法都合并到了目标对象

34.ES6数组

1.forEach()
1)对数组进行遍历循环,对数组中的每一项运行给定函数。
2)这个方法没有返回值。参数都是function类型,默认有传参,参数分别为:遍历的数组内容;第对应的数组索引,数组本身。
2.map()
1)指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
2)必须要return,返回一个新数组
3.filter()
1)“过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。
4.some()
1)判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

35.有哪些可能引起前端安全的问题?

跨站脚本 (Cross-Site Scripting, XSS): 一种代码注入方式, 为了 与 CSS 区分所以被称作 XSS。早期常⻅于网络论坛, 起因是网站没 有对用户的输入进行严格的限制, 使得攻击者可以将脚本上传到帖 子让其他人浏览到有恶意脚本的⻚面, 其注入方式很简单包括但不 限于 JavaScript / CSS / Flash 等;
iframe 的滥用: iframe 中的内容是由第三方来提供的,默认情况下 他们不受控制,他们可以在 iframe 中运行JavaScirpt 脚本、Flash 插件、弹出对话框等等,这可能会破坏前端用户体验;
跨站点请求伪造(Cross-Site Request Forgeries,CSRF): 指攻击 者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信 息或设定信息等某些状态更新,属于被动攻击
恶意第三方库: 无论是后端服务器应用还是前端应用开发,绝大多数 时候都是在借助开发框架和各种类库进行快速开发,一旦第三方库被 植入恶意代码很容易引起安全问题。

36.如何解决跨域问题?

①JSONP 原理:前后台约定回调函数,后台以函数参数的形式将数据返回。
②iframe标签:src请求接口把数据请求回放入iframe的body里。
③设置代理服务器
④通过修改document.domain来跨子域
⑤使用window.name来跨域
⑥CORS (cross-origin resource sharing)
⑦使用HTML5新引进的window.postMessage来跨域进行传递数据

37. 字符串操作

对象转字符串 json.stringify
字符串转对象 json.parse
数组转字符串 toString()
字符串转数字 parsint()

38.js种字符串操作

Concat()将两个或多个字符的文本组合起来,返回一个新的字符串
Indexof()
Match()检查一个字符串是否匹配一个正则表达式
Substr()
Substring()传入的参数是起始位置和结束位置
Slice()提取字符串的一部分,返回一个新字符串
Replace()使用新的字符串代替匹配到的字符串
Search()执行一个正则表达式匹配查找
tolowerCase()
toUpperCase()

39.DOM和BOM

DOM:文档对象模型 document
BOM:浏览器对象模型 window

40.json与jsonp

json是一种轻量级数据交换格式
Jsonp是一种数据调用的方法

41.说说你对作用域及作用域链的理解?

作用域:变量和函数可访问到的范围,也就是全局和局部
作用域链:保证执行环境里有权访问的变量和函数都是有序的,作用域链的变量只能向上访问,变量访问到window对象被禁止

42.从域名到页面展示步骤

在浏览器的地址栏种敲入url
域名解析
服务器处理请求
浏览器处理
绘制页面

43.未声明和未定义

未声明的变量是程序中不存在且未声明的变量,如果程序尝试读取未声明变量的值,则会遇到运行时的错误,未定义的变量是在程序中声明但尚未给出任何值的变量,如果程序尝试读取未定义变量的值,则返回未定义的值

44.window。Onload与$(document).ready()区别?

Ready事件的触发,表示文档结构已经加载完成(不包含图片等非文字媒体文件)
Onload事件触发表示页面包含图片等文件在内的所有元素都加载完成

45.简述事件委托。

又叫事件代理,原理就是利用事件冒泡的机制来实现。
事件委托是把每个子元素事件绑定到父元素身上,只需要给元素的父级绑定一个监听器,当触发子元素时,事件会冒泡到父元素上,监听器就会被激发。
阻止事件冒泡:event.stopPropagation()
addEventListener(click,函数名,true/false)默认是false事件冒泡。true事件捕获
好处就是减少内存占用

46.IE与DOM事件流的区别?

this指向问题
执行顺序不一样
参数不一样
事件加不加on

47.浏览器是如何渲染页面的?

解析html文件,创建DOM树,自上而下
解析css,将css与DOM树合并构建渲染树
布局和绘制

48.什么是SSR(服务端渲染),原理是什么? 好处有哪些?

ssr全称server side render, 前端页面的产生是由服务器端生成的,我们就称之为服务端渲染。
对比客户端渲染?(client side render, CSR)
CSR执行流程:浏览器加载html文件 -> 浏览器下载js文件 -> 浏览器运行vue代码 -> 渲染页面
SSR执行流程:浏览器加载html文件 -> 服务端装填好内容 -> 返回浏览器渲染
使用SSR的好处?(何时该使用SSR?):
对SEO有利:搜索引擎的爬虫爬取你的页面信息,因为大多数爬虫并不支持等待前端获取数据后再爬取数据的,而有了SSR以后,这些抓取工具就可以立刻得到完整的HTML结构化数据,从而被纳入搜索引擎。
更短的白屏时间:服务端渲染并不需要加载和执行大量的js脚本, 直接渲染服务端给出的html字符串, 从而缩短首屏加载时间
不好的地方: 前后端分工搭配复杂, 原本一个页面, 同时由前后端绘制填充

49.重排和重绘是什么,区别?

浏览器的重绘(repaint)和重排(reflow)是指浏览器对网页进行重新渲染的过程。重排是指重新计算网页布局的过程,而重绘则是根据新的布局信息重新绘制网页的过程。
区别:重排会导致元素的尺寸、位置、内容等属性的变化,需要重新计算布局信息;
重绘则是在元素的位置和尺寸等属性不变的情况下,重新绘制元素的样式。

50.解释一下JavaScript中的严格模式(Strict Mode)是什么,以及它的作用?

严格模式(Strict Mode)是JavaScript中的一种执行模式,它可以通过在脚本或函数的顶部添加特定语句来启用。严格模式引入了一些限制和变化,以帮助开发者编写更规范、更安全的JavaScript代码。
严格模式的作用如下:
消除了一些不合理或不安全的语法和行为:在严格模式下,一些以前被视为有效但容易导致错误的语法或行为会被禁止,从而帮助开发者避免潜在的问题。
提升代码的可读性和维护性:严格模式要求变量声明必须使用关键字(如var、let或const),这样可以避免意外创建全局变量,提高代码的可读性和可维护性。
阻止使用一些不推荐的功能:在严格模式下,一些过时的或不推荐使用的功能被废弃或禁止,例如使用with语句、使用arguments.callee访问函数自身等。
提升JavaScript引擎的优化能力:严格模式下的代码通常比非严格模式下的代码更容易进行静态分析和优化,这可以使JavaScript引擎更好地执行代码,提高性能。
要在整个脚本中启用严格模式,可以在脚本的顶部添加如下语句
“use strict”;

51.null和undefined的区别

null:一般是复杂数据类型,表示不存在,转为数值时为0
undefined:一般是简单数据类型,表示此处应该有个值,但是当前尚未赋值,转为数值时为NaN

52.实现深拷贝的方法

深拷贝:在堆内存中开辟一个存储空间来存储一个一模一样的克隆对象。
浅拷贝:相反不在堆内存中重新开辟空间,仅仅复制栈内存中的引用地址,本质上依然指向的同一块存储空间
1.JSON.stringify()
2.递归方式
3.第三方库lodash的cloneDeep()方法
4.JQ的extend()

53.ES6中数组新增了哪些扩展?

扩展运算符的应用
es6通过扩展运算符…, 通过扩展运算符实现的浅拷贝

构造函数新增的方法
Array.from()用来对每个元素进行处理,将处理后的值放入返回的数组
Array.of()用于将一组值转换为数组
实例对象新增的方法
空值处理
sort()排序算法稳定性

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiojio冲冲冲

能帮助你是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值