JavaScript的基本内容学习

这篇具有很好参考价值的文章主要介绍了JavaScript的基本内容学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概要
  • 前端的组成
层次 作用
HTML(结构层) 利用语义化标签搭建网页
CSS(样式层) 利用样式进行美化网页、进行网页布局
JavaScript(行为层) 可以给网页添加动态效果
  • JavaScript 是一种高级、解释型的编程语言,由网景公司(Netscape)在1995年开发,现由ECMA国际通过ECMAScript标准规范进行标准化。它是互联网上最广泛使用的客户端脚本语言,主要用于增强网页和用户交互、构建动态功能及创建网络应用。JavaScript 最初设计用于嵌入到HTML文档中,并能在用户的浏览器端直接执行,无需编译成可执行文件。随着技术发展,JavaScript 也扩展到了服务器端(Node.js)、移动端应用开发(如React Native)以及跨平台桌面应用开发(Electron)等领域。JavaScript 在Web开发中的核心作用包括表单验证、动画效果、用户界面互动、数据处理以及构建复杂的单页应用程序(SPA)等。此外,它还支持大量的开源库和框架,如jQuery、React、Vue.js等,极大地丰富了其功能和使用场景。

  • JavaScript的组成

    1. ECMAScript(核心):这是JavaScript语言的核心标准,定义了语言的基本语法、数据类型、控制结构、内置对象和函数等。例如变量声明、函数定义、字符串操作、数组方法、流程控制语句等都是ECMAScript规范的一部分。
    2. DOM(文档对象模型):DOM(Document Object Model)是文档对象模型的缩写,它是一种接口标准,用于表示和操作HTML、XML等文档的标准格式。DOM是浏览器提供的一套API,用于访问和操作HTML或XML文档的接口。通过DOM,JavaScript可以动态地改变网页的内容、结构和样式,比如获取页面元素、修改内容、添加或删除节点等。
    3. BOM(浏览器对象模型):BOM则是与浏览器交互的对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象,比如window对象、navigator对象、location对象、history对象等,这些对象提供了有关浏览器环境本身的信息,并允许脚本与浏览器进行交互,如弹出对话框、控制浏览器历史记录、处理定时器等。
  • 另外,在现代Web开发中,还有其他一些重要组成部分,如:

    1. Web API:浏览器提供的各种接口,包括但不限于AJAX、Fetch、WebSocket、Geolocation、IndexedDB等,使得JavaScript能更好地实现异步通信、地理位置定位、离线存储等功能。
    2. 库和框架:如jQuery、React、Vue、Angular等,它们为开发者提供了更高层次的抽象和工具,简化开发过程,提高开发效率。但请注意,这些并不是JavaScript语言本身的组成部分,而是基于JavaScript构建的额外工具。
  • JavaScript 的主要特点包括:

    1. 轻量级:易于学习和编写,语法简洁。
    2. 解释性:代码不需要预编译,可在支持JavaScript的环境中即时执行。
    3. 基于对象:采用面向对象编程机制,同时具有原型继承的特点。
    4. 事件驱动:支持事件处理模型,可以对用户的操作或特定事件做出响应。
    5. 弱类型:变量的数据类型可以在运行时自动确定或改变。
    6. 跨平台:能够在多种操作系统环境下运行,在所有现代浏览器中均得到支持。
    7. DOM操作:与HTML和CSS紧密结合,能够动态修改和访问网页内容、样式和结构。
    8. AJAX支持:允许无刷新页面更新,实现异步数据交换。
基本内容
  • JavaScript输出数据的方式:

    1. 使用 window.alert()弹出警告框。
    2. 使用 document.write() 方法将内容写到 HTML 文档中。
    3. 使用 innerHTML写入到 HTML 元素。
    4. 使用console.log()写入到浏览器的控制台。
    5. prompt() 是一个内置的浏览器窗口对象方法,用于与用户进行交互。它会弹出一个对话框,显示一段提示信息,并允许用户输入文本数据。
  • 数据类型:

    • 基本数据类型:包括number(数字)、string(字符串)、boolean(布尔值)、nullundefined以及ES6新增的symbol
    • 引用数据类型:包括object(对象)和function(函数),其中数组(array)和正则表达式(RegExp)也是对象类型的子类。
  • 变量声明:

    • var:在ES5及更早版本中使用,具有变量提升特性,在同一个作用域内可以重新声明。
    • letconst(ES6引入):提供了块级作用域,并且const用于声明常量,一旦赋值后不可更改其引用。
  • 操作符:

    • 算术运算符:如+-*/%等。
    • 关系与相等运算符:比较两个值的关系,如><>=<===!====(严格相等)、!==(严格不等)。
    • 逻辑运算符:&&(逻辑与)、||(逻辑或)、!(逻辑非)。
    • 赋值运算符:=, +=, -=等。
    • 位运算符:对二进制数进行操作,如&|^~<<>>>>>
    • 条件运算符(三元运算符):condition ? exprIfTrue : exprIfFalse
  • 控制结构:

    • 条件语句:if...elseswitch
    • 循环:forwhiledo...whilefor...in(遍历对象属性)、for...of(遍历可迭代对象,如数组)。
    • 跳转语句:breakcontinue
  • 函数:

    • 函数定义:通过function关键字创建函数。
    • 匿名函数:没有名称的函数,可以直接赋值给变量或者作为参数传递。
    • 箭头函数(ES6):简洁的函数定义语法,如(param1, param2) => expression{ statements }
    • 返回值:使用return语句从函数内部返回结果。
  • 对象:

    • 对象字面量:通过键值对形式创建对象,如{ key: value }
    • 属性访问:通过.[ ]来访问和修改对象属性。
    • 构造函数:使用new关键字实例化对象。
    • 原型链和继承:JavaScript基于原型实现继承机制。
  • 数组:

    • 数组定义:通过方括号[]初始化数组。
    • 内置方法:如.push().pop().shift().unshift().slice().map().filter()等。
  • 字符串:

    • 字符串是不可变的,可以通过字符串方法进行操作,如.length获取长度、.charAt()访问单个字符、.split()分割字符串、.concat()拼接字符串等。
  • 内置对象包括MathDateArrayObjectFunctionRegExp等。

    1. Object:所有JavaScript对象的基类,提供了一些通用的方法:

      • Object.create(prototype[, propertiesObject]):创建一个新对象,其[[Prototype]]链接到指定的对象。
      • Object.defineProperty(obj, prop, descriptor):直接在一个对象上定义或修改一个属性及其特性。
      • Object.keys(obj)Object.values(obj)Object.entries(obj):分别返回一个对象的所有自身可枚举属性名数组、值数组和键值对数组。
    2. Array:数组对象的构造函数,包含大量处理数组的方法:

      • push(): 向数组末尾添加元素。
      • pop(): 删除并返回数组最后一个元素。
      • shift(): 删除并返回数组的第一个元素。
      • unshift(): 在数组开头添加元素。
      • slice(): 返回一个子数组,原数组不变。
      • map(): 创建一个新数组,其结果是调用提供的函数处理原数组每个元素的结果。
      • filter(): 创建一个新数组,其中包含通过测试函数的所有元素。
    3. Function`

      • 函数对象的构造函数,但通常使用函数声明或箭头函数语法创建函数。
      • 每个函数都是Function的实例,拥有自己的方法如call()apply()bind()用于改变函数上下文(this)并执行函数。
    4. String:字符串对象的相关方法:

      • length: 属性返回字符串的长度。
      • charAt(index): 返回指定位置的字符。
      • substring(start, end?): 提取字符串的一部分。
      • split(separator[, limit]): 根据分隔符将字符串分割成数组。
      • concat(string2, ...[, stringN]): 连接两个或更多的字符串,并返回一个新的字符串。
    5. Number:提供与数字相关的属性和方法,例如:

      • isNaN(value): 判断给定参数是否为NaN。
      • isFinite(number): 判断给定数是否为有限数值。
      • toFixed(digits): 把数字转换为指定位数的小数。
    6. Math:包含数学常数和函数,如:

      • Math.PI: 圆周率。
      • Math.random(): 返回0到1之间的随机浮点数。
      • Math.floor(x): 对数进行下舍入。
      • Math.ceil(x): 对数进行上舍入。
      • Math.pow(base, exponent): 计算基数的指数次幂。
    7. Date:表示日期和时间的JavaScript对象,可以获取当前日期、设置日期以及进行日期操作。

      • 创建Date对象:

        • 构造函数:

          var date = new Date();
          

          不传入参数时,创建的是当前时间的一个新实例。

          或者可以通过以下方式指定特定时间:

          // 直接输入年、月、日等参数(月份从0开始计数,因此1代表2月)
          var date1 = new Date(2024, 0, 18); // 创建一个2024年1月18日的新实例
          
          // 使用特定格式的字符串创建
          var date2 = new Date("January 18, 2024 00:00:00"); 
          var date3 = new Date("2024-01-18T00:00:00"); // ISO 8601格式
          
          // 指定自1970年1月1日以来的毫秒数
          var date4 = new Date(1685055600000); // 2023年8月2日12:00:00 UTC
          
      • 获取和设置日期/时间值:

        • 实例方法

          • getDate(), getDay(), getFullYear(), getHours(), getMilliseconds(), getMinutes(), getMonth(), getSeconds(), getTime(), getTimezoneOffset() 等用于获取相应的时间部分。
          • 对应地,有 setDate(), setFullYear(), setHours(), setMilliseconds(), setMinutes(), setMonth(), setSeconds() 等方法来设置具体的时间值。

          示例:

          var today = new Date();
          console.log(today.getDate()); // 获取当前日期(1-31)
          today.setFullYear(2025); // 设置年份为2025
          
        • 其他常用方法:

          • toLocaleDateString()toLocaleTimeString() 方法将日期和时间转换为本地化格式的字符串。
          • toDateString() 返回日期部分的字符串形式。
          • toTimeString() 返回时间部分的字符串形式。
          • toISOString() 返回ISO 8601格式的字符串,如:“2024-01-18T00:00:00.000Z”。
        • 静态方法:

          • Date.now() 返回当前时间距离1970年1月1日0点0分0秒(UTC)的毫秒数。
          • Date.parse(dateString) 解析给定的日期字符串,并返回该时间点与1970年1月1日之间的毫秒数。此方法对于不同格式的日期字符串解析规则可能因浏览器而异,建议使用new Date(dateString)并检查返回值是否有效来确保兼容性。
        • 示例操作:

        var d = new Date();
        console.log(d.toLocaleString()); // 显示当前日期和时间的本地格式
        
        d.setDate(d.getDate() + 7); // 将日期增加7天
        console.log(d.toDateString()); // 显示修改后日期
        
        console.log(Date.now()); // 输出当前时间戳(毫秒)
        
    8. RegExp:正则表达式(Regular Expression,简称 RegExp),是 JavaScript 中用于处理文本字符串的强大工具。它定义了一种模式,可以用来搜索、匹配、替换文本中的特定子串。

    • 在JavaScript中创建正则表达式有两种方式:

      1. 字面量语法:

        var regex = /pattern/flags;
        

        其中 pattern 是一个代表所需匹配模式的字符串,而 flags 可选,包含标志字符(如 g、i、m),分别表示全局搜索(global)、不区分大小写(ignore case)和多行模式(multiline)。

      2. 构造函数语法:

        var regex = new RegExp('pattern', 'flags');
        
    • 正则表达式的常用方法:

      • .test(string): 测试给定字符串是否满足正则表达式所定义的模式。
      • .exec(string): 在字符串中执行查找,并返回第一个匹配项的信息,如果没有找到匹配项,则返回null。当使用全局标志g时,连续调用.exec()会逐个查找所有匹配项。
    • 与字符串对象结合的方法:

      • string.match(regexp): 在字符串中查找正则表达式的匹配项,返回匹配结果数组或null
      • string.replace(regexp|substr, newSubstr|function):根据正则表达式或子串进行查找并替换,如果第一个参数是正则表达式还可以利用分组(())捕获的内容进行动态替换。
      • string.search(regexp):返回字符串中第一次出现正则表达式匹配项的索引位置,如果没有找到返回-1
    • 全局函数如isNaN()检查是否为NaN、parseInt()parseFloat()转换字符串为数字、prompt()alert()confirm()与用户交互。

      • isNaN(value): 这不是一个正则表达式相关函数,而是用来检查传递的值是否为NaN(非数字)。返回值是一个布尔值,如果是NaN则返回true,否则返回false
      • parseInt(string, radix): 该函数解析一个字符串,并返回一个整数。第二个可选参数指定进制,默认是10进制。如果字符串不能被解析成有效的整数,或者基数无效,则返回NaN
      • parseFloat(string): 类似于parseInt,但此函数尝试将字符串解析为浮点数。
      • prompt(message[, defaultText]): 此全局浏览器函数弹出一个对话框,提示用户输入信息。返回用户输入的字符串或在用户取消时返回null
      • alert(message): 显示一个警告对话框,包含指定的消息内容,并在用户点击确定后关闭。
      • confirm(question): 显示一个确认对话框,包含指定的问题文本以及“确定”和“取消”按钮。用户点击确定时返回true,点击取消时返回false
  • 全局函数部分在JavaScript中指的是可以直接调用而无需特定对象的函数,这些函数在浏览器环境中提供了一些基本的用户交互和数据处理能力。以下是几个常用的全局函数详细介绍:

    1. isNaN(value)

      • 该函数接收一个参数并检查其是否为NaN(非数字)。
      var num = "Hello";
      console.log(isNaN(num)); // 输出:true,因为"Hello"不是数字
      

      注意:isNaN会首先尝试将传入值转换为数字,因此某些非数字字符串也可能返回false,例如空字符串""会被转换为0,所以isNaN("")会返回false。

    2. parseInt(string, radix)

      • 此函数用于解析一个字符串,并返回其中包含的整数值。第二个可选参数指定进制,默认是10进制。
      var str = "123";
      console.log(parseInt(str)); // 输出:123
      console.log(parseInt("1101", 2)); // 输出:13,二进制数1101转换为十进制数
      
    3. parseFloat(string)

      • 类似于parseInt,但此函数尝试将字符串解析为浮点数。
      var floatStr = "3.14";
      console.log(parseFloat(floatStr)); // 输出:3.14
      
    4. prompt(message[, defaultText])

      • 这是一个浏览器环境下的全局函数,它弹出一个对话框提示用户输入信息,用户可以在这个对话框内输入文本,然后点击确认或取消按钮。函数返回用户输入的字符串,如果用户点击取消,则返回null
      var userInput = prompt("请输入您的姓名:", "John Doe");
      if (userInput !== null) {
        console.log(userInput);
      }
      
    5. alert(message)

      • 显示一个警告对话框,包含给定的消息内容。这个对话框通常只包含一个“确定”按钮,当用户点击确定后对话框消失。
      alert("这是一条消息提醒!");
      
    6. confirm(question)

      • 显示一个确认对话框,包含一个问句以及“确定”和“取消”两个按钮。用户点击“确定”时,函数返回true;点击“取消”时,函数返回false
      var isAgreed = confirm("你是否同意条款和条件?");
      if (isAgreed) {
        console.log("用户已同意条款和条件");
      } else {
        console.log("用户不同意条款和条件");
      }
      

    这些全局函数主要用于简单的用户交互和数据类型转换,在现代Web应用开发中,为了更好的用户体验,推荐使用更复杂的UI组件和API进行交互操作。对于验证数据格式等任务,正则表达式也经常与这些函数结合使用。

  • 异步编程在JavaScript中,由于其单线程执行模型,处理网络请求、文件读写等耗时操作时需要采用异步编程方式,以避免阻塞主线程。以下是关于异步编程的三种主要技术手段的详细解释:

    1. 回调函数 回调函数是最早的异步编程模式之一,在JavaScript中广泛应用。当一个异步任务完成后,通过调用预先定义好的函数(即回调函数)来处理结果或错误。

      function getData(callback) {
        // 假设这是一个异步操作
        setTimeout(() => {
          const data = 'Async Data';
          callback(data); // 异步操作完成后调用回调函数
        }, 2000);
      }
      
      function processData(data) {
        console.log('Processed data:', data);
      }
      
      // 使用回调函数处理异步结果
      getData(processData);
      

      缺点:随着异步逻辑复杂度增加,多个回调嵌套导致代码难以阅读和维护,这通常被称为“回调地狱”。

    2. Promise Promise 是ES6引入的一种标准机制,用于处理异步操作并解决回调地狱问题。它代表了一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:pending(进行中)、fulfilled(已成功)或rejected(已失败)。一旦状态改变,就不可再变。

      function getData() {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            const data = 'Async Data';
            if (data) { // 模拟异步操作的成功情况
              resolve(data);
            } else {
              reject(new Error('Failed to fetch data'));
            }
          }, 2000);
        });
      }
      
      getData().then(data => {
        console.log('Processed data:', data);
      }).catch(error => {
        console.error('Error:', error.message);
      });
      
    3. async/await async/await 是基于Promise的更简洁的异步编程语法糖。async 关键字用来声明一个异步函数,该函数会隐式地返回一个Promise对象;await 关键字则用于等待Promise的结果,并可以放在async函数内部。

      async function getData() {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('Async Data');
          }, 2000);
        });
      }
      
      async function main() {
        try {
          const data = await getData();
          console.log('Processed data:', data);
        } catch (error) {
          console.error('Error:', error.message);
        }
      }
      
      main(); // 启动异步操作
      

    使用async/await可以使异步代码看起来更加同步化,更易于理解和调试。然而,本质上它们仍然是基于Promise的异步编程机制,只是提供了一种更接近传统顺序流程控制的语法形式。

  • 模块化是编程中的一种设计思想,它将程序分割成多个独立、可复用的部分(即模块),每个模块有自己明确的职责和接口。在JavaScript中,ES6引入了原生的模块系统,通过importexport关键字支持模块导入导出功能,使得代码结构更加清晰,同时方便代码复用和管理。

    • export 关键字:export用于对外暴露模块的功能(变量、函数、类等)。一个模块可以有多个export语句,也可以通过default export来指定一个默认输出项。

    • 命名导出:为模块内的每个需要导出的成员分别指定名称

      // math.js
      function add(x, y) {
        return x + y;
      }
      
      function subtract(x, y) {
        return x - y;
      }
      
      export { add, subtract };
      
    • 默认导出:模块内只能有一个default export,代表这个模块的默认出口。

      // person.js
      class Person {
        constructor(name, age) {
          this.name = name;
          this.age = age;
        }
      }
      
      export default Person;
      
    • import 关键字:import用于从其他模块导入已经导出的功能。

      • 导入默认导出:

        // 导入person.js中的默认导出(Person类)
        import Person from './person';
        
        const alice = new Person('Alice', 30);
        
      • 导入命名导出:

        // 导入math.js中的命名导出
        import { add, subtract } from './math';
        
        console.log(add(5, 3)); // 输出8
        console.log(subtract(5, 3)); // 输出2
        
      • 重命名导入:导入时可以给导入的变量或函数重新命名以避免命名冲突

        import { add as sum, subtract as difference } from './math';
        
      • 整体导入:使用*一次性导入模块的所有导出项目,并将其作为一个对象来访问

        // 导入math.js的所有导出内容
        import * as math from './math';
        
        console.log(math.add(5, 3)); // 输出8
        console.log(math.subtract(5, 3)); // 输出2
        

    通过这种方式,JavaScript开发者可以在不同的文件中编写模块化的代码,然后通过importexport相互连接,形成一个复杂的、分层次的应用程序结构。文章来源地址https://www.toymoban.com/news/detail-805479.html

到了这里,关于JavaScript的基本内容学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端开发——Javascript知识(介绍)

    目录 有关JavaScript的知识  JavaScript的优点   JavaScript的领域 JavaScript的组成 JavaScript的特点 第一个JavaScript程序 在 HTML 文档中嵌入 JavaScript 代码 在脚本文件中编写 JavaScript 代码 JavaScript内容  Html内容  JavaScript 代码执行顺序 JavaScript中的几个重要概念 标识符 保留字 区分

    2024年02月01日
    浏览(46)
  • 前端开发——JavaScript的条件语句

      世界不仅有黑,又或者白 世界而是一道精致的灰  ——Lungcen     目录 条件判断语句 if 语句 if else 语句 if else if else 语句  switch语句 break case 子句 default语句 while循环语句 do while循环语句 for循环语句 for 循环中的三个表达式 for 循环嵌套 for 循环变体——for in for 循环

    2023年04月21日
    浏览(42)
  • 快速认识,前端必学编程语言:JavaScript

    JavaScript是构建Web应用必学的一门编程语言,也是最受开发者欢迎的热门语言之一。所以,如果您还不知道JavaScript的用处、特点的话,赶紧补充一下这块基础知识。 JavaScript 是一种高级、单线程、垃圾收集、解释或即时编译、基于原型、多范式、动态语言,具有非阻塞事件循

    2024年02月05日
    浏览(49)
  • JavaScript学习 -- HMAC算法基本原理

    HMAC(Hash-based Message Authentication Code)算法是一种基于哈希算法的消息认证码算法。它可以用于验证和保护数据在传输过程中的完整性和真实性。在JavaScript中,我们可以使用HMAC算法来保证数据的安全性。本篇文章将介绍HMAC算法的基本原理和相关技术,并提供一些实例来演示如

    2024年02月15日
    浏览(33)
  • 【前端学习笔记2】javaScript基础

    是一种运行在客户端(服务器的编程语言) javacript分为行内JavaScript,内部JavaScript,外部JavaScript 内部JavaScript 直接写在html中body里面 alert(“hello,world”) 我们将script放在html文件的地步附近的原因是浏览器会按照代码在文件中的顺序加载html 如果先加载的JavaScript期望修改其

    2024年01月22日
    浏览(36)
  • 【前端灵魂脚本语言JavaScript⑤】——JS中数组的使用

    🐚 作者: 阿伟 💂 个人主页: Flyme awei 🐋 希望大家多多支持😘一起进步呀! 💬 文章对你有帮助👉关注✨点赞👍收藏📂 第一种: var 数组名 = new Array(); 创建一个空数组 第二种: var arr2 = new Array(10); 创建一个定长为10的数组 第三种 var arr3 = new Array(a,b,c); 创建时直接指定元素值

    2023年04月08日
    浏览(59)
  • 30个前端开发中常用的JavaScript函数

    🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 在前端开发中通常会用到校验函数,检验是否为空、手机号格式、身份证格式等等。现按照用途分类整理出了30个常用的方法,在V

    2024年02月14日
    浏览(44)
  • 2023年web前端开发之JavaScript进阶(一)

    接上篇博客进行学习,通俗易懂,详细 博客地址: 2023年web前端开发之JavaScript基础(五)基础完结_努力的小周同学的博客-CSDN博客 学习 作用域 、变量提升、 闭包 等语言特征,加深对 JavaScript 的理解,掌握变量赋值、函数声明的简洁语法, 降低代码的冗余度 。 理解作用域对程序

    2024年02月03日
    浏览(54)
  • [前端开发] 常见的 HTML CSS JavaScript 事件

    代码示例指路 常见的 HTML、CSS、JavaScript 事件代码示例 在 Web 开发中,事件是用户与网页交互的重要方式之一。通过事件,用户可以与页面元素进行交互,触发相应的功能或效果。本文将介绍常见的 HTML、CSS、JavaScript 事件,以及事件对象和事件代理的概念。 鼠标事件 鼠标事

    2024年02月19日
    浏览(54)
  • 开发语言漫谈-JavaScript

           JavaScript、Java名字很相近,但它们没有任何亲缘关系,是由不同公司开发的编程语言。Java由Sun公司(后被Oracle收购)开发,JavaScript最初是由Netscape公司开发的(当年浏览器的霸主)。JavaScript最初的名字是 LiveScript,Netscape将其命名为 JavaScript,无非是蹭 Java流量。当

    2024年04月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包