前端零碎整理三js(中)

一、mouseover和mouseenter的区别
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除入素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave

二、js中的位置:
clientHeight:表示的是可视区域的高度,不包含border和滚动条;offsetHeight:表示可视区域的高度,包含了border和滚动条;
clientTop:表示边框border的厚度,在未指定的情况下一般为0;scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分;
scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

三、 js拖拽功能的实现
首先是三个事件,分别是mousedown,mousemove,mouseup
当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。
clientX,clientY标识的是鼠标的横坐标和纵坐标,我们用offsetX和offsetY来表示元素的元素的初始坐标。移动的举例是:鼠标移动时候的坐标-鼠标按下去时候的坐标。也就是说定位信息为:鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft;拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left以及top等等值。也可以通过html5的拖放(Drag 和 drop)来实现。

四、异步加载js的方法
1、defer:只支持IE如果您的脚本不会改变文档的内容,可将 defer 属性加入到 script 标签中,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。
async(异步加载,加载完就执行),HTML5属性仅适用于外部脚本,并且如果在IE中,同时存在defer和async,那么defer的优先级比较高,脚本将在页面完成时执行。

创建script标签,插入到DOM中。

五、Ajax解决浏览器缓存问题
在一些项目中,一般提交请求都会通过ajax来提交,测试时发现,每次提交后得到的数据都是一样的,经过调试,发现问题发现在前端,没有清理缓存,所以得到的还是原来的旧数据。
而我们都知道ajax能提高页面载入的速度主要的原因是通过ajax减少了重复数据的载入,也就是说在载入数据的同时将数据缓存到内存中,一旦数据被加载其中,只要我们没有刷新页面,这些数据就会一直被缓存在内存中,当我们提交 的URL与历史的URL一致时,就不需要提交给服务器,也就是不需要从服务器上面去获取数据,虽然这样降低了服务器的负载提高了用户的体验,但是我们不能获取最新的数据。为了保证我们读取的信息都是最新的,我们就需要禁止他的缓存功能。

禁止浏览器缓存功能有如下几种方法:
在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“If-Modified-Since”,“0”),或anyAjaxObj.setRequestHeader(“Cache-Control”,“no-cache”)。在URL后面加上一个随机数: “fresh=” + Math.random()。在URL后面加上时间搓:“nowtime=” + new Date().getTime()。
如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

六、js的垃圾回收机制
必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
avaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:
var a=“hello world”;
var b=“world”;
var a=b; //这时,会释放掉"hello world",释放内存以便再引用
垃圾回收的方法:标记清除、计数引用(存在内存泄漏问题,不常用)。
标记清除
这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。
垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。

七、前端模块化
前端模块化就是复杂的文件编程一个一个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(编译等处理)的工具webpack。
一个模块是能实现特定功能的文件,有了模块就可以方便的使用别人的代码,想要什么功能就能加载什么模块。

Commonjs:开始于服务器端的模块化,同步定义的模块化,每个模块都是一个单独的作用域;在服务器端,模块的加载时在运行时同步加载的,在浏览器端,模块需要提前编译打包处理(需要异步)。同步的也就是只有加载完成,才能执行后面的操作。
特点:所有代码都运行在模块作用域,不会污染全局作用域;模块可以多次加载,但只会在第一次加载时执行一次,运行结果被缓存,以后在加载直接在缓存中取结果,想让模块再次运行,必须清除缓存;模块加载的顺序,按照其在代码中出现的顺序。
模块输出,modules.exports,模块加载require()。

AMD:中文名异步模块定义的意思。requireJS实现了AMD规范,主要用于解决下述两个问题。
1.多个文件有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器;2.加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应的时间越长。因此我们可以通过异步的方式去加载js,而如果需要依赖某些,也是异步去依赖,依赖后再执行某些方法。
语法:requireJS定义了一个函数define,它是全局变量,用来定义模块。define(id?dependencies?,factory)在页面上使用模块加载函数:
require([dependencies],factory);
总结AMD规范:require()函数在加载依赖函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块加载成功,才会去执行。
因为网页在加载js的时候会停止渲染,因此我们可以通过异步的方式去加载js,而如果需要依赖某些,也是异步去依赖,依赖后再执行某些方法。
CMD:专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行;CMD整合了AMD和Commonjs的特点。

requireJS的例子:
//定义模块
define(['dependency'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
//加载模块
require(['myModule'], function (my){
my.printName();
}

requirejs定义了一个函数define,它是全局变量,用来定义模块:define(id?dependencies?,factory)
在页面上使用模块加载函数:require([dependencies],factory);
总结AMD规范:require()函数在加载依赖函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块加载成功,才会去执行。

八、js new 操作符做了那些事情
new 共经历了四个阶段:创建一个空对象–>设置原型链–>让Func中的this指向obj并执行Func函数体–>判断Func的返回值类型,若是值类型返回obj,若是引用类型法案会引用类型对象。var obj = new Object(); —>obj.proto =Func.prototype -->Func.call(obj)

九、setTimeout、setInterval和requestAnimationFrame之间的区别
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔,
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。
RAF采用的是系统时间间隔,不会因为前面的任务,不会影响RAF,但是如果前面的任务多的话,
会响应setTimeout和setInterval真正运行时的时间间隔。
特点(1)requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
(2)在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
(3)requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

十、 js怎么控制一次加载一张图片,加载完后再加载下一张

方法一:
<script type="text/javascript">
   var obj=new Image();
   obj.src="http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg";
  obj.onload=function(){ //onload事件会在页面或者对象加载完后立即发生,
      alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height);
      document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />";
    }
 </script>
<div id="mypic">onloading……</div>
方法二:
<script type="text/javascript">
 var obj=new Image();
   obj.src="http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg";
   obj.onreadystatechange=function(){
   if(this.readyState=="complete"){
		alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height);
		document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />";
 	}
}
</script>
<div id="mypic">onloading……</div>

十一、 代码的执行顺序
macro-task(ScriptJobs)队列真实包含任务:script(主程序代码),setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task(PromiseJobs)队列真实包含任务:process.nextTick, Promises, Object.observe, MutationObserver
macro-task:a,b,c;micro-task:d,e,f,==>adefbc。由此我们得到的执行顺序应该为:
script(主程序代码)—>process.nextTick—>Promises(.then部分)——>Object.observe——>MutationObserver——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
注意:在定义promise的时候,promise构造部分是同步执行的

十二 实现一个promise

var p=new Promise(function(resolve,reject){
    setTimeout(function(){
       resolve("success")
    },1000);
    console.log("创建一个新的promise");
})
p.then(function(x){

十三、Function.proto(getPrototypeOf)是什么
获取一个对象的原型,在chrome中可以通过_proto_的形式,或者在ES6中可以通过Object.getPrototypeOf的形式。
那么Function.proto是什么么?也就是说Function由什么对象继承而来,我们来做如下判别。
Function.proto==Object.prototype //false
Function.proto==Function.prototype//true
我们发现Function的原型也是Function。
在这里插入图片描述
十四、JS实现跨域
JSONP:通过动态创建script,再请求一个带参网址实现跨域通信。document.domain + iframe跨域:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
location.hash + iframe跨域:a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
window.name + iframe跨域:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。
postMessage跨域:可以跨域操作的window属性之一。
CORS:服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求,前后端都需要设置。
代理跨域:启一个代理服务器,实现数据的转发
跨域的原理:跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制,那么只要协议、域名、端口有任何一个不同,都被当作是不同的域。跨域原理,即是通过各种方式,避开浏览器的安全限制。

十五、重排和重绘
重绘(repaint或redraw):当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。
触发重绘的条件:改变元素外观属性。如:color,background-color等。
注意:table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是我们尽量避免使用table布局页面的原因之一。
重排(重构/回流/reflow):当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。所以,重排必定会引发重绘,但重绘不一定会引发重排。

十六、this的指向 哪几种
默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。
【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。

十七、AngularJS双向绑定原理
Angular将双向绑定转换为一堆watch表达式,然后递归这些表达式检查是否发生过变化,如果变了则执行相应的watcher函数(指view上的指令,如ng-bind,ng-show等或是{{}})。等到model中的值不再发生变化,也就不会再有watcher被触发,一个完整的digest循环就完成了。
Angular中在view上声明的事件指令,如:ng-click、ng-change等,会将浏览器的事件转发给 s c o p e 上 相 应 的 m o d e l 的 响 应 函 数 。 等 待 相 应 函 数 改 变 m o d e l , 紧 接 着 触 发 脏 检 查 机 制 刷 新 v i e w 。 w a t c h 表 达 式 : 可 以 是 一 个 函 数 、 可 以 是 scope上相应的model的响应函数。等待相应函数改变model,紧接着触发脏检查机制刷新view。 watch表达式:可以是一个函数、可以是 scopemodelmodelviewwatchscope上的一个属性名,也可以是一个字符串形式的表达式。$watch函数所监听的对象叫做watch表达式。watcher函数:指在view上的指令(ngBind,ngShow、ngHide等)以及{{}}表达式,他们所注册的函数。每一个watcher对象都包括:监听函数,上次变化的值,获取监听表达式的方法以及监听表达式,最后还包括是否需要使用深度对比(angular.equals())

十八、简单介绍一下symbol
Symbol是ES6 的新增属性,代表用给定名称作为唯一标识,这种类型的值可以这样创建,let id=symbol(“id”)
Symbl确保唯一,即使采用相同的名称,也会产生不同的值,我们创建一个字段,仅为知道对应symbol的人能访问,使用symbol很有用,symbol并不是100%隐藏,有内置方法Object.getOwnPropertySymbols(obj)可以获得所有的symbol。也有一个方法Reflect.ownKeys(obj)返回对象所有的键,包括symbol。所以并不是真正隐藏。但大多数库内置方法和语法结构遵循通用约定他们是隐藏的,

十九、介绍一下promise,及其底层如何实现
解决的问题:回调地狱
Promise规范:promise有三种状态,等待(pending)、已完成(fulfilled/resolved)、已拒绝(rejected).Promise的状态只能从“等待”转到“完成”或者“拒绝”,不能逆向转换,同时“完成”和“拒绝”也不能相互转换。promise 必须提供一个 then方法以访问其当前值、终值和拒因。promise.then(resolve, reject),resolve 和 reject是可选参数。若 resolve 或reject 非函数,则被忽略。then 方法必须返回一个 promise 对象.
使用:实例化promise对象需要传入函数(包含两个参数),resolve和reject,内部确定状态.resolve和reject函数可以传入参数在回调函数中使用.
resolve和reject都是函数,传入的参数在then的回调函数中接收。
Promise是一个对象,保存着未来将要结束的事件,她有两个特征:
1、对象的状态不受外部影响,Promise对象代表一个异步操作,有三种状态,pending进行中,fulfilled已成功,rejected已失败,只有异步操作的结果,才可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也就是promise名字的由来
2、一旦状态改变,就不会再变,promise对象状态改变只有两种可能,从pending改到fulfilled或者从pending改到rejected,只要这两种情况发生,状态就凝固了,不会再改变,这个时候就称为定型resolved,Promise的基本用法,

class PromiseM {
constructor (process) {
this.status = 'pending'
this.msg = ''
process(this.resolve.bind(this), this.reject.bind(this))
return this
}
resolve (val) {
this.status = 'fulfilled'
this.msg = val
}
reject (err) {
this.status = 'rejected'
this.msg = err
}
then (fufilled, reject) {
if(this.status === 'fulfilled') {
fufilled(this.msg)
}
if(this.status === 'rejected') {
reject(this.msg)
}
}
}

二十、Generator函数:
generator函数使用:
1、分段执行,可以暂停 2、可以控制阶段和每个阶段的返回值 3、可以知道是否执行到结尾

function* g() {
var o = 1;
yield o++;
yield o++;
}
var gen = g();
console.log(gen.next()); //  Object {value: 1, done: false}
var xxx = g();
console.log(gen.next()); // Object {value: 2, done: false}
console.log(xxx.next()); // Object {value: 1, done: false}
console.log(gen.next()); // Object {value: undefined, done: true}

generator和异步控制:
利用Generator函数的暂停执行的效果,可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield语句下面,反正要等到调用next方法时再执行。所以,Generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数。
async和异步:
用法:
async 表示这是一个async函数,await只能用在这个函数里面。await 表示在这里等待异步操作返回结果,再继续执行。
await 后一般是一个promise对象。
示例:async用于定义一个异步函数,该函数返回一个Promise。如果async函数返回的是一个同步的值,这个值将被包装成一个理解resolve的Promise,等同于return Promise.resolve(value)。await用于一个异步操作之前,表示要“等待”这个异步操作的返回值。await也可以用于一个同步的值。

let timer = async function timer(){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('500');
},500);
});
}
timer().then(result => {
console.log(result);  //500
}).catch(err => {
console.log(err.message);
});
//返回一个同步的值
let sayHi = async function sayHi(){
let hi = await 'hello world';
return hi;  //等同于return Promise.resolve(hi);
}
sayHi().then(result => {
console.log(result);
});

二十一、JS中string的startwith和indexof两种方法的区别
JS中startwith函数,其参数有3个,stringObj,要搜索的字符串对象,str,搜索的字符串,position,可选,从哪个位置开始搜索,如果以position开始的字符串以搜索字符串开头,则返回true,否则返回false;Indexof函数,indexof函数可返回某个指定字符串在字符串中首次出现的位置,

二十二、es6新特性
S6在变量的声明和定义方面增加了let、const声明变量,有局部变量的概念,赋值中有比较吸引人的结构赋值,同时ES6对字符串、 数组、正则、对象、函数等拓展了一些方法,如字符串方面的模板字符串、函数方面的默认参数、对象方面属性的简洁表达方式,ES6也 引入了新的数据类型symbol,新的数据结构set和map,symbol可以通过typeof检测出来,为解决异步回调问题,引入了promise和 generator,还有最为吸引人了实现Class和模块,通过Class可以更好的面向对象编程,使用模块加载方便模块化编程,当然考虑到 浏览器兼容性,我们在实际开发中需要使用babel进行编译重要的特性:
块级作用域:ES5只有全局作用域和函数作用域,块级作用域的好处是不再需要立即执行的函数表达式,循环体中的闭包不再有问题
rest参数:用于获取函数的多余参数,这样就不需要使用arguments对象了,
promise:一种异步编程的解决方案,比传统的解决方案回调函数和事件更合理强大
模块化:其模块功能主要有两个命令构成,export和import,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能

二十三、
JS的基本数据类型有字符串,数字,布尔,数组,对象,Null,Undefined,基本数据类型是按值访问的,也就是说我们可以操作保存在变量中的实际的值,
基本数据类型和引用数据类型的区别如下:
基本数据类型的值是不可变的,任何方法都无法改变一个基本类型的值,当这个变量重新赋值后看起来变量的值是改变了,但是这里变量名只是指向变量的一个指针,所以改变的是指针的指向改变,该变量是不变的,但是引用类型可以改变
基本数据类型不可以添加属性和方法,但是引用类型可以
基本数据类型的赋值是简单赋值,如果从一个变量向另一个变量赋值基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,引用数据类型的赋值是对象引用,
基本数据类型的比较是值的比较,引用类型的比较是引用的比较,比较对象的内存地址是否相同
基本数据类型是存放在栈区的,引用数据类型同事保存在栈区和堆区
NaN是JS中的特殊值,表示非数字,NaN不是数字,但是他的数据类型是数字,它不等于任何值,包括自身,在布尔运算时被当做false,NaN与任何数运算得到的结果都是NaN,党员算失败或者运算无法返回正确的数值的就会返回NaN,一些数学函数的运算结果也会出现NaN

二十四、 js对象类型
分为基本对象类型和引用对象类型
基本数据类型:按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。基本数据类型有这六种:undefined、null、string、number、boolean、symbol。
引用类型:当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。引用类型有这几种:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。

二十五、JavaScript中的轮播实现原理?假如一个页面上有两个轮播,你会怎么实现?
图片轮播的原理就是图片排成一行,然后准备一个只有一张图片大小的容器,对这个容器设置超出部分隐藏,在控制定时器来让这些图片整体左移或右移,这样呈现出来的效果就是图片在轮播了。
如果有两个轮播,可封装一个轮播组件,供两处调用

eval:将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行)eg:eval是(‘test()’)。
js监听对象属性变化:
如何实现一个私有变量,用getName方法可以访问,不能直接访问:
实现一个两列等高布局,讲讲思路为了实现两列等高,可以给每列加上 padding-bottom:9999px;margin-bottom:-9999px;同时父元素设置overflow:hidden;
自己实现一个bind函数
== === object is
用setTimeout来实现setInterval
如何实现sleep的效果
简单实现Node的Events模块
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值