【前端三剑客】JavaScript 网页脚本语言(速览)

更新日期:2022/04/10
只要我们一起大笑,可怕的东西就会跑光光了。

 


1. JavaScript 简介

JavaScript(简称 “JS”)是一种解释性脚本语言(代码不进行预编译)。在 1995 年由 Netscape 公司的 Brendan Eich,在网景导航者浏览器上首次设计实现而成。Netscape 管理层希望它外观看起来像 Java,因此取名为 JavaScript。但实际上它的语法风格与 Self 及 Scheme 较为接近。
JavaScript 的标准是 ECMAScript 。2015 年 6 月 17 日,ECMA 国际组织发布了 ECMAScript 的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为 ECMAScript 6 或者 ES2015。ECMAScript 的语言组成

  • 文档对象模型(DOM),描述处理网页内容的方法和接口。
  • 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口。

更多内容 → 菜鸟教程 - JavaScript教程

  • ECMAScript版本
版本说明
ECMAScript 1标准化了JavaScript1.1 的基本特性,并添加了一些新特性。没有标准化switch 语句和正则表达式
ECMAScript 2ECMA v1的维护版本,只添加了说明
ECMAScript 3标准化了 switch 语句、异常处理和正则表达式
ECMAScript 5添加了“严格模式”。添加了 JSON 支持。添加了 String.trim()。添加了 Array.isArray()。添加了数组迭代方法
ECMAScript 5.1编辑改变
ECMAScript 2015添加了 let 和 const 添加了默认参数值添加了 Array.find() 添加了 Array.findIndex()
ECMAScript 2016添加了指数运算符(**)。添加了 Array.prototype.includes
ECMAScript 2017添加了字符串填充。添加了新的 Object 属性。添加了异步功能。添加了共享内存
ECMAScript 2018添加了 rest / spread 属性。添加了异步迭代。添加了 Promise.finally()。增加 RegExp

2. 快速开始

HTML 中的脚本必须位于 <script></script> 标签之间。
脚本可被放置在 HTML 页面的 <body><head> 部分中。

  • 输出一段 html 代码
    注意:HTML 输出流中使用 document.write,相当于添加在原有html 代码中添加一串 html 代码。如果在文档加载后使用(如使用函数),会覆盖整个文档。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8"/>
  <link rel="icon" href="../../../static/image/icon/icon/icon_ITGodRoad.png">
  <title>ITGodRoad</title>
  <script>
      function myFunction() {
          document.write("<h1>这是一个标题</h1>");
          document.write("<p>这是一个段落</p>");
      }
  </script>
</head>
<body>
<div>
  <h1>这是一个有趣的世界</h1>
  <button type="button" onclick="myFunction()">尝试一下</button>
</div>
</body>
</html>

点击按钮,触发事件

在这里插入图片描述

覆盖了整个文档

在这里插入图片描述


2. 输出数据

JavaScript 可以通过不同的方式来输出数据:
· 使用 window.alert() 弹出警告框。
· 使用 document.write() 方法将内容写到 HTML 文档中。
· 使用 innerHTML 写入到 HTML 元素。
· 使用 console.log() 写入到浏览器的控制台。

  • window.alert()
    用 alert 弹出内容会打断页面的操作,不建议使用。

在这里插入图片描述

  • innerHTML
    是 DOM 页面元素的一个属性,代表该元素的 html 内容。可以精确到某一个具体的元素来进行更改。

在这里插入图片描述

  • console.log()
    浏览器中使用 F12 来启用调试模式

在这里插入图片描述

  • console.log()
    console.log 还可以添加显示样式(占位符 %c 表示后面字符串的样式)。

在这里插入图片描述


3. 数据类型和变量

3.1 JavaScript 数据类型

Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。

基本类型(值类型)对象类型(引用数据类型)
StringObject
Number1Array
BooleanFunction
NullRegExp
UndefinedDate
Symbol

变量的数据类型可以使用 typeof 操作符来查看:
NaN 属性是代表非数字值的特殊值,可以使用 isNaN() 函数来判断一个值是否是 NaN 值。
当数字运算结果超过了JavaScript 所能表示的数字上限(溢出),结果为一个特殊的无穷大值,以 Infinity 表示。可以使用 isFinite() 函数来判断一个值是否为有限数字。
就算变量定义的是数组格式,typeof 返回的数据类型还是 object 。可以使用 isArray() 函数来判断该对象是否为数组。

<script>
    function myFunction() {
        document.getElementById("demo").innerHTML =
            "typeof \"ouseki\" = " + typeof "ouseki" + "<br>" +
            "typeof 3.14 = " + typeof 3.14 + "<br>" +
            "typeof 123e5 = " + typeof 123e5 + "<br>" +
            "typeof Infinity = " + typeof Infinity + "<br>" +
            "isFinite(Infinity)= " + isFinite(Infinity) + "<br>" +
            "typeof NaN = " + typeof NaN + "<br>" +
            "isNaN(NaN) = " + isNaN(NaN) + "<br>" +
            "typeof (1000 / 0)= " + typeof (1000 / 0) + "<br>" +
            "typeof false = " + typeof false + "<br>" +
            "typeof [1, 2, 3, 4] = " + typeof [1, 2, 3, 4] + "<br>" +
            "Array.isArray([1, 2, 3, 4]) = " + Array.isArray([1, 2, 3, 4]) + "<br>" +
            "typeof {name: \"ouseki\", age: 25} = " + typeof {name: "ouseki", age: 25};
      }
</script>

在这里插入图片描述

3.2 JavaScript 声明变量

在 ES6 之前,JavaScript 只有两种作用域: 全局变量与函数内的局部变量。
· 全局变量在网页中所有脚本和函数均可使用,在页面关闭后被销毁;
· 局部变量在函数开始执行时创建,在函数运行后被销毁。
ES2015(ES6) 新增加了两个重要的 JavaScript 关键字 let 和 const :
· let 声明的变量只在 let 命令所在的代码块内有效;
· const 声明一个只读的常量,一旦声明,常量的值就不能改变。

声明方式变量提升(先使用再声明)暂时性死区重复声明初始值作用域
var允许不存在允许不需要非块级
let不允许存在不允许不需要块级
const不允许存在不允许需要块级

var 作用域为全局(非块级)

var x = 10;
// 这里输出 x 为 10
{ 
    var x = 2;
    // 这里输出 x 为 2
}
// 这里输出 x 为 2

let 作用域为局部(块级)

var x = 10;
// 这里输出 x 为 10
{ 
    let x = 2;
    // 这里输出 x 为 2
}
// 这里输出 x 为 10
  • HTML 代码中使用全局变量
    在 JavaScript 中, 全局作用域是针对 JavaScript 环境。
    在 HTML 中, 全局作用域是针对 window 对象。
    使用 var 关键字声明的全局作用域变量属于 window 对象(没有声明就使用的变量,也默认为全局变量,不论这个变量在哪被使用)
    使用 let 关键字声明的全局作用域变量不属于 window 对象

在这里插入图片描述


4. JavaScript 对象

JavaScript 中的所有事物都是对象:字符串、数值、数组、函数 …
对象只是带有属性和方法( name:value 集合)的特殊数据类型,JavaScript 允许自定义对象。所有的 JavaScript 对象都会从一个原型对象 prototype 中继承属性和方法。

4.1 创建 JavaScript 对象

JavaScript 是面向对象的语言,但 JavaScript 不使用类(ES6 之前),不会通过类来创建对象。它基于 prototype 而不是类,创建新对象有两种不同的方法:
1.使用 Object 定义并创建对象的实例。
2.使用对象构造器定义对象,然后创建新的对象实例。

  • 使用 Object 创建对象
    在 JavaScript 中,几乎所有的对象都是 Object 类型的实例,它们都会从 Object.prototype 继承属性和方法。Object 构造函数,会根据给定的参数创建对象,具体有以下情况:
    · 如果给定值是 null 或 undefined,将会创建并返回一个空对象。
    · 如果传进去的是一个基本类型的值,则会构造其包装类型的对象。
    · 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址。
    · 当以非构造函数形式被调用时,Object 的行为等同于 new Object()。
    请使用对象字面量 {} 代替 new Object()。
    请使用字符串字面量 "" 代替 new String()。
    请使用数组字面量 [] 代替 new Array()。
    请使用正则字面量 /()/ 代替 new RexExp()。
    请使用函数表达式 (){} 代替 new Function()。

在这里插入图片描述

  • 使用对象构造器创建对象
    首字母大写对构造器函数命名是个好习惯。
    ()=> ES6 新增箭头函数,相当于 java 中的拉姆达表达式,语法也一样。
    访问对象的方法时,如果使用 fullName 属性,不添加 (), 它会返回函数的定义,而不是函数的值。
    在一个已存在构造器的对象中是不能直接添加新属性的,会返回 undefined ,需要使用 prototype 属性给对象的构造函数添加新的属性:构造函数名.prototype.新属性/者新方法; 可以使用 .property["property"] 来访问对象属性。
    this 通常指向的是我们正在执行的函数本身,或者是指向该函数所属的对象(运行时)。

在这里插入图片描述


5. HTML DOM

DOM (Document Object Model ) 文档对象模型,是 W3C 组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口。简单的说 就是把文档当作一个对象来看待。DOM 的顶级对象是 document ,通过 DOM 使 JavaScript 获得了足够的能力来创建动态的 HTML:
1.JavaScript 能够改变页面中的所有 HTML 元素(element)
2.JavaScript 能够改变页面中的所有 HTML 属性(attribute)
3.JavaScript 能够改变页面中的所有 CSS 样式(style)
4.JavaScript 能够对页面中的所有事件做出反应(event)

5.1 查找 HTML 元素

  • 通过 JavaScript 操作 HTML 元素必须首先找到该元素,有三种方法来做这件事:
    · 通过 id 找到 HTML 元素
    · 通过 标签名 找到 HTML 元素
    · 通过 类名 找到 HTML 元素

getElementsByTagName 和 getElementsByClassName 这两个方法查找多个 dom 元素,返回的是 htmlcollection 类型,是伪数组而不是真数组,故不能使用数组的方法。我们可以使用数组原型配合 slice 方法,利用 call,apply,bind 方法或者利用 ES6 提供的 Array 的 from 方法将伪数组转为真数组。

<script>
    function myFunction() {
        console.log("ById:", document.getElementById("demo"));
        let byTagName = document.getElementsByTagName("h1");
        console.log("ByTagName:", byTagName);
        console.log("ByClassName:", document.getElementsByClassName("demo"));
        
        console.log("prototypeSliceCall:", Array.prototype.slice.call(byTagName));
        console.log("ArrayFrom:", Array.from(byTagName));
    }
</script>
<div>
  <h1 id="demo" class="demo">这是一个有趣的世界</h1>
  <h1 id="demo2">Hello World!</h1>
  <button type="button" onclick="myFunction()">尝试一下</button>
</div>

在这里插入图片描述

5.2 操作 HTML 元素

要创建新的 HTML 元素(节点)需要先创建一个元素,然后在已存在的元素中添加它。
insertBefore() 方法,添加新元素到指定元素前面;appendChild() 方法,添加新元素到尾部。

在这里插入图片描述

node.remove() 方法,删除元素,前提是必须知道其父元素(node)。
node.replaceChild() 方法,替换 HTML DOM 中的元素,前提是必须知道其父元素(node)。

![在这里插入图片描述](https://img-blog.csdnimg.cn/7a8ce5aaf9854d3090179cdc91de72d9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA44GK44GG44Gb44GN56Kp,size_20,color_FFFFFF,t_70,g_se,x_16

5.2 监听 HTML 事件

该章节内容过多,单开了一个博客。

点此跳转 → 友情链接


6. Browser BOM

BOM ( Browser Object Model ) 浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,简单的说就是 把浏览器当做一个对象来看待。BOM 的顶层对象是 Window,其他对象都是该对象的子对象。BOM 比 DOM更大,它包含 DOM ,通过 BOM 使 JavaScript 有能力与浏览器"对话"。
由于 BOM 尚无正式标准,每个浏览器都有其自己对 BOM 的实现方式。BOM 有窗口对象、导航对象等一些实际上已经默认的标准,但对于这些对象和其它一些对象,每个浏览器都定义了自己的属性和方式。

在这里插入图片描述

6.1 Window 对象

Window 对象表示浏览器中打开的窗口。

  • window 对象属性
    属性很多,只列出部分。
属性描述
closed返回窗口是否已被关闭
innerHeight返回窗口的文档显示区的高度
innerWidth返回窗口的文档显示区的宽度
outerHeight返回窗口的外部高度,包含工具条与滚动条
outerWidth返回窗口的外部宽度,包含工具条与滚动条
pageXOffset设置或返回当前页面相对于窗口显示区左上角的 X 位置
pageYOffset设置或返回当前页面相对于窗口显示区左上角的 Y 位置
screenLeft返回相对于屏幕窗口的x坐标
screenTop返回相对于屏幕窗口的y坐标

在这里插入图片描述

  • window 对象方法
    方法很多,只列出部分。
方法描述
open()打开一个新的浏览器窗口或查找一个已命名的窗口
stop()停止页面载入
closed()关闭浏览器窗口
focus()把键盘焦点给予一个窗口
blur()把键盘焦点从顶层窗口移开
alert()显示带有一段消息和一个确认按钮的警告框
confirm()显示带有一段消息以及确认按钮和取消按钮的对话框
prompt()显示可提示用户输入的对话框
setInterval()按照指定的周期(以毫秒计)来调用函数或计算表达式
setTimeout()在指定的毫秒数后调用函数或计算表达式
clearInterval()取消由 setInterval() 设置的 timeout
clearTimeout()取消由 setTimeout() 方法设置的 timeout
postMessage()安全地实现跨源通信

在这里插入图片描述

6.2 Navigator 对象

Navigator 对象包含有关浏览器的信息。
来自 navigator 对象的信息具有误导性,不应该被用于检测浏览器版本。

属性 / 方法描述
appCodeName返回浏览器的代码名
appName返回浏览器的名称
appVersion返回浏览器的平台和版本信息
cookieEnabled返回指明浏览器中是否启用 cookie 的布尔值
platform返回运行浏览器的操作系统平台
userAgent返回由客户机发送服务器的user-agent 头部的值
javaEnabled()指定是否在浏览器中启用 Java
taintEnabled()规定浏览器是否启用数据污点 (data tainting)
<script>
    function myFunction() {
        let txt = "";
        txt += "appCodeName: " + navigator.appCodeName + "<br />";
        txt += "appName: " + navigator.appName + "<br />";
        txt += "appVersion: " + navigator.appVersion + "<br />";
        txt += "cookieEnabled: " + navigator.cookieEnabled + "<br />";
        txt += "platform: " + navigator.platform + "<br />";
        txt += "userAgent: " + navigator.userAgent + "<br />";
        txt += "javaEnabled(): " + navigator.javaEnabled() + "<br />";
        document.getElementById("demo").innerHTML = txt;
    }
</script>

在这里插入图片描述

6.3 Screen 对象

Screen 对象包含有关客户端显示屏幕的信息。

属性描述
height返回屏幕的总高度
width返回屏幕的总宽度
availHeight返回屏幕的高度(不包括Windows任务栏)
availWidth返回屏幕的宽度(不包括Windows任务栏)
colorDepth返回目标设备或缓冲器上的调色板的比特深度
pixelDepth返回屏幕的颜色分辨率(每象素的位数)
<script>
    function myFunction() {
        let txt = "";
        txt += "height: " + screen.height + "<br />";
        txt += "width: " + screen.width + "<br />";
        txt += "availHeight: " + screen.availHeight + "<br />";
        txt += "availWidth: " + screen.availWidth + "<br />";
        txt += "colorDepth: " + screen.colorDepth + "<br />";
        txt += "pixelDepth: " + screen.pixelDepth + "<br />";
        document.getElementById("demo").innerHTML = txt;
    }
</script>

在这里插入图片描述

6.4 History 对象

History 对象包含用户(在浏览器窗口中)访问过的 URL。

属性 / 方法描述
length返回历史列表中的网址数
back()加载 history 列表中的前一个 URL
forward()加载 history 列表中的下一个 URL
go()加载 history 列表中的某个具体页面

在这里插入图片描述

6.5 Location 对象

Location 对象包含有关当前 URL 的信息。
window.location.assign(url) : 加载 URL 指定的新的 HTML 文档。相当于一个链接跳转到指定的 url,当前页面会转为新页面内容,可以点击后退返回上一个页面;
window.location.replace(url) : 通过加载 URL 指定的文档来替换当前文档,这个方法是替换当前窗口页面,前后两个页面共用一个窗口,所以是没有后退返回上一页的。

属性 / 方法描述
hash返回一个URL的锚部分
host返回一个URL的主机名和端口
hostname返回URL的主机名
href返回完整的URL
pathname返回的URL路径名
port返回一个URL服务器使用的端口号
protocol返回一个URL协议
search返回一个URL的查询部分
assign()载入一个新的文档
reload()重新载入当前文档
replace()用新的文档替换当前文档

在这里插入图片描述


7. 异步编程

异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念。在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。
简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行(异步就是从主线程发射一个子线程来完成任务),异步的执行效率更高。

在这里插入图片描述

  • 什么时候用异步编程
    现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

7.1 回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。

  • demo
    setTimeout 会在子线程中等待 3 秒,在 setTimeout 函数执行之后主线程并没有停止。

在这里插入图片描述

7.2 异步 AJAX

该章节内容过多,单开了一个博客。

点此跳转 → 友情链接

7.3 Promise

Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务(将嵌套格式的代码变成了顺序格式的代码)。本质上 Promise 是一个函数返回的对象,也就是可以被链式调用。我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。
一个 Promise 必然处于以下几种状态之一:
· 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
· 已兑现(fulfilled): 意味着操作成功完成。
· 已拒绝(rejected): 意味着操作失败。

  • Promise 静态方法
方法说明
Promise()创建一个新的 Promise 对象。该构造函数主要用于包装还没有添加 promise 支持的函数
Promise.all(iterable)在 iterable 参数对象里所有的 promise 对象都成功的时候才会触发成功,常被用于处理多个 promise 对象的状态集合
Promise.allSettled(iterable)等到所有 promises 都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))
Promise.any(iterable)接收一个 Promise 对象的集合,当其中的一个 promise 成功,就返回那个成功的 promise 的值
Promise.race(iterable)接收一个 Promise 对象的集合,当其中任意一个子 promise 被成功或失败后,就返回那个 Promise 对象
Promise.reject(reason)返回一个状态为失败的 Promise 对象,并将给定的失败信息传递给对应的处理方法
Promise.resolve(value)返回一个状态由给定value决定的Promise对象

7.3.1 构造 Promise 对象

这个回调传递了两个参数:一个 resolve 回调,用于用一个值或另一个 promise 的结果来解析 promise ;一个 reject 回调,用于提供的原因或错误拒绝 promise。

const myFirstPromise = new Promise((resolve, reject) => {
  // 做一些异步操作,最终会调用下面两者之一:
  //
  //   resolve(someValue); // fulfilled
  // 或
  //   reject("failure reason"); // rejected
});

想要某个函数拥有 promise 功能,只需让其返回一个 promise 即可。当异步代码执行成功时,才会调用 resolve(…) , 当异步代码失败时就会调用 reject(…)

function myFunction() {
  const demo = document.getElementById("demo");
  return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", "http://localhost:8080/ITGodRoad/testPromise.do");
      xhr.onload = () => resolve(demo.innerHTML = xhr.responseText);
      xhr.onerror = () => reject(demo.innerHTML = xhr.statusText);
      xhr.send();
  });
}

在这里插入图片描述

7.3.2 使用 Promise 传递

resolve() 中可以放置一个参数用于向下一个 then 传递一个值,then 中的函数也可以返回一个值传递给 then。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作;
reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常。

resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。

<script>
    var promiseCount = 0;

    function myFunction() {
        const demo = document.getElementById("demo");
        let thisPromiseCount = ++promiseCount;
        // 新构建一个 Promise 实例:使用 Promise 实现每过一段时间给计数器加一的过程,每段时间间隔为1~3秒不等
        let p1 = new Promise((resolve, reject) => {
            demo.insertAdjacentHTML('beforeend', "<p>Promise 开始,第" + thisPromiseCount + "次点击异步代码开始</p>")
            // 创建一个异步调用
            setTimeout(
                function () {
                    // 填充 Promise
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        })
        p1.then(
            // 记录填充值
            function (val) {
            	/*
            	'beforebegin':元素自身的前面。
				'afterbegin':插入元素内部的第一个子节点之前。
				'beforeend':插入元素内部的最后一个子节点之后。
				'afterend':元素自身的后面。
				*/
                demo.insertAdjacentHTML('beforeend', "<p>Promise 已填充完毕,第" + val + "次点击异步代码结束</p>");
            })
            .catch(
                // 记录失败原因
                (reason) => {
                    demo.innerText = "处理失败的原因:" + reason;
                });

    }
</script>

<div>
  <h1 id="demo" class="demo">这是一个有趣的世界</h1>
  <h1 id="demo2">Hello World!</h1>
  <button type="button" onclick="myFunction()">尝试一下</button>
</div>

连续点击按钮,触发异步函数,可以从结果中看出,谁先结束谁就返回了,不会收到其他任务影响。

在这里插入图片描述


【每日一面】

undefined 和 null 的区别

undefined: 是一个没有设置值的变量 。是所有没有赋值变量的默认值,自动赋值。
null: 是一个只有一个值的特殊类型,表示一个空对象引用。可以主动设置为 null 来释放一个变量引用的对象,表示一个变量不再指向任何对象地址。
null 和 undefined 的值相等,但类型不等。

typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true
 
  1. 在 JavaScript 中,数字不分为整数类型和浮点型类型,所有的数字都是浮点型类型,且均为 64 位。其中 0 到 51 存储数字(片段),52 到 62 存储指数,63 位存储符号。
    极大或极小的数字可通过科学(指数)计数法来写:
    var y=123e5;  // 12300000
    var z=123e-5; // 0.00123
    ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值