JavaScript基础知识
2021/12/26 1:08:00
本文主要是介绍JavaScript基础知识,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 基础语法
1.1 变量
- 变量需要声明和赋值,声明和赋值可以同时进行(未赋值的变量类型都是undefined)
- 有五种基本数据类型:
String
、Number
、Boolean
、Undefined
、Null
- 复杂数据类型都是Object类型
typeof 变量或常量
:查看变量或常量的数据类型- 基本类型的比较
都是值比较
===
:对于基本数据类型来说,等价于==
;对于对象类型来说,当类型相同取值也相同的时候才会返回为true(不会自动类型转换)- 全局变量在函数外/类外声明,如果在函数中直接对一个变量赋值,则这个变量也是全局变量。
对象和函数都是引用数据类型
1.2 类型转换
var ret = Number(arg)
- 作用:将非数值变量转换为数值变量
- arg:可以是数字字符串,布尔,null和undefined
var ret = parseInt(str)
- 作用:将字符串转换为整数
- str:字符串
var ret = parseFloat(str);
- 作用:将字符串转换为浮点数
- str:字符串
var ret = Boolean(arg);
- 作用:将其他数据类型转换为Boolean类型
- arg:可以是数字类型、字符串、null、undefined、Object
1.3 控制语句与运算符
- 控制语句几乎跟java没啥区别,不写了
===
类型要相同,取值也要相同(不会自动类型转换)!==
不全等运算- 基本类型的比较是值比较
2. 对象(es6之前)
2.1 对象的两种创建方式
var person = new Object(); // 给对象增加属性 person.name = "孙悟空"; person.age = 18;
// 创建对象时给其添加属性 var person = { name: "孙悟空", age: 18 };
2.2 访问、删除、遍历对象属性
obj.name
:访问属性方式一obj["name"]
:访问属性方式二delete obj.name
:删除属性方式for (var 变量 in 对象) {}
:对象元素的遍历
3. 函数
3.1 函数的创建
function fun1(参数列表) { 语句... } // 匿名函数 var fun1 = function(参数列表) { 语句.... }
3.2 构造函数
// 使用构造函数来创建对象 function Person(name, age) { // 设置对象的属性 this.name = name; this.age = age; // 设置对象的方法 this.sayName = function () { console.log(this.name); }; }
- 构造函数和普通函数的定义没有啥区别
- 构造函数首字母一般
大写
,调用构造函数需要用new
关键字来生成对象。 - 构造函数里面可以通过
this
来表示新建对象 - 通过构造函数名添加的属性为
静态属性
,只能通过构造函数名来访问
Person.nation="中国"; console.log(Person.nation);
3.3 this在不同函数里代表什么
- 当以
函数
的形式代用时,this代表window - 当以
方法
的形式调用时,哪个对象调用的就代表谁 - 当以
构造函数
的形式调用时,this代表新创建的那个对象
4. 原型
- 每个构造函数都会有一个prototype属性,它是一个对象类型
- prototype属性为原型对象,这个对象里面需要有一个属性叫
constructor
,并且要指向当前构造函数
- prototype属性为原型对象,这个对象里面需要有一个属性叫
- 每个对象都会有原型(
__proto__
),原型也是一个对象,指向的是构造函数中的prototype - 因此原型会形成一个原型链
- Object对象是所有对象的祖先,Object的原型对象指向为null
- 如果一个构造器没有指定prototype属性,则原型默认就是Object的实例对象
- 一个对象的原型链上的属性和方法对这个对象来说都是可见的
综上,es6之前通过构造函数与原型实现了类与继承等概念
// 使用构造函数来创建对象 function Person(name, age) { // 设置对象的属性 this.name = name; this.age = age; } // 在Person类的原型对象中添加方法 Person.prototype.sayName = function() { console.log(this.name); }; var person1 = new Person("孙悟空", 18); var person2 = new Person("猪八戒", 19); var person3 = new Person("沙和尚", 20); person1.sayName(); person2.sayName(); person3.sayName();
4.1 对象的内置的方法
toString()
:继承自Object对象hasOwnProperty(name)
:查看当前对象是否拥有某个属性或方法(而非原型链上)
5. 对象继承(es6之前)
5.1 原型链继承
// 定义父类型构造函数 function SupperType() { this.supProp = 'Supper property'; } // 给父类型的原型添加方法 SupperType.prototype.showSupperProp = function () { console.log(this.supProp); }; // 定义子类型的构造函数 function SubType() { this.subProp = 'Sub property'; } // 创建父类型的对象赋值给子类型的原型 SubType.prototype = new SupperType(); // 将子类型原型对象的构造属性设置为子类构造函数 SubType.prototype.constructor = SubType; // 给子类型原型对象添加方法 SubType.prototype.showSubProp = function () { console.log(this.subProp) }; // 创建子类型的对象: 可以调用父类型的方法 var subType = new SubType(); subType.showSupperProp(); subType.showSubProp();
- 实现原理是:
子类的原型对象是父类型的一个实例对象
- 特点:
- 子类多个实例对象的原型指向同一个原型对象,一个子类对象修改了原型属性,其他所有子类对象的原型属性也会被修改
- 不能传递参数
- 基础单一
5.2 构造函数继承
// 定义父类型构造函数 function SuperType(name) { this.name = name; this.showSupperName = function () { console.log(this.name); }; } // 定义子类型的构造函数 function SubType(name, age) { // 在子类型中调用call方法继承自SuperType SuperType.call(this, name); this.age = age; } // 给子类型的原型添加方法 SubType.prototype.showSubName = function () { console.log(this.name); }; // 创建子类型的对象然后调用 var subType = new SubType("孙悟空", 20); subType.showSupperName(); subType.showSubName(); console.log(subType.name); console.log(subType.age);
- 原理:使用call将父类构造函数引入子类构造函数中
5.3 组合继承
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.setName = function (name) { this.name = name; }; function Student(name, age, price) { Person.call(this, name, age); // 为了得到父类型的实例属性和方法 this.price = price; // 添加子类型私有的属性 } Student.prototype = new Person(); // 为了得到父类型的原型属性和方法 Student.prototype.constructor = Student; // 修正constructor属性指向 Student.prototype.setPrice = function (price) { // 添加子类型私有的方法 this.price = price; }; var s = new Student("孙悟空", 24, 15000); console.log(s.name, s.age, s.price); s.setName("猪八戒"); s.setPrice(16000); console.log(s.name, s.age, s.price);
- 原理:原型链+借用构造函数的组合继承
6. 常用对象
6.1 数组对象
var arr=new Array();
arr.push(a1,a2)
:尾部追加多个元素arr.pop()
:弹出最后一个元素arr.unshift(a1,a2)
:头部追加多个元素arr.shift()
:弹出头部一个元素arr.slice(1,4)
:切片(起始位置,结束位置)不更改原数组arr.reverse()
:翻转数组arr.sort()
:排序数组arr.join(" ")
:按空格将数组拼接成字符串arr.concat(arr1,arr2);
:将多个数组拼接成一个数组返回arr.length
:数组长度[...arr1,...arr2]
:也可以实现两个数组拼接
数组遍历
var arr=[1,2,3]; // 第三个参数可以不要 arr.forEach(function(value,index,array){ console.log(value); }) // 遍历方式2 const xiyou=['唐僧','孙悟空','猪八戒','沙僧']; for(let v in xiyou){ console.log("v 是index"); } for(let v of xiyou){ console.log("v 是value"); }
filter()
var arr=[1,2,3,4,5,6,7]; // 第三个参数可以不要 var arr1=arr.filter(function(value,index,array){ return value>=3; })
some()
:查找是否存在满足条件的元素
var arr=[10,30,4]; var isExist=arr.some(function(value){ return value>=20; })
map()
var arr=[10,30,4]; var arr1=arr.map(function(value){ return value*20; })
6.2 函数对象
函数本身也是一个对象,函数的构造函数时Function
函数的调用方式
// 普通函数: this指向window fn(); // 作为对象的方法:this指向obj obj.fn(); // 构造函数:this指向新创建的对象 new Fn(); // 绑定事件函数:this指向btn btn.onclick=function(){}; // 定时器函数:this指向window setInterval(function(){},1000); // 立即执行函数:this指向window (function(){})();
call()
:改变了this指向
function fun(a, b) { console.log("a = " + a); console.log("b = " + b); console.log("fun = " + this); } var obj = { name: "obj", sayName: function () { console.log(this.name); } }; fun(2, 3); console.log("==============="); fun.call(obj, 2, 3);
apply()
:会将参数封装在一个数组中,改变了this指向
function fun(a, b) { console.log("a = " + a); console.log("b = " + b); console.log("fun = " + this); } var obj = { name: "obj", sayName: function () { console.log(this.name); } }; fun(2, 3); console.log("==============="); fun.apply(obj, [2, 3]);
bind()
: 返回一个新的函数,可以改变绑定的this
var obj={ name:"andy" }; function fun(){ console.log(this); } var fun1=fun.bind(obj); fun1();
6.3 Date对象
var date=new Date();
date.getFullYear();
date.getMonth();
date.getDate()
date.getHours()
date.getMinutes()
date.getSeconds()
date.getMilliseconds()
6.4 Math工具类
Math.abs(1)
Math.ceil(1.1)
Math.floor(1.1)
Math.round(1.1)
Math.round(Math.random()*10)
Math.pow(12,3)
Math.sqrt(16)
6.5 String对象
str.charAt(1)
str.charCodeAt(1)
str.concat("你好","世界")
:拼接多个字符串str.indexof("o")
str.lastIndexof("o")
str.slice(0,5)
str.substring(0,5)
str.substr(0,5)
str.split(" ")
str.toUpperCase()
str.toLowerCase()
6.7 浅拷贝与深拷贝
var obj={ id=1, name:"andy", msg:{ age:18; } } var o={}; // 浅拷贝 Object.assign(o,obj);
- 深拷贝自己加实现逻辑
7. Exception
7.1 Error对象属性
name
:设置或返回错误名message
:错误消息
try { // 可能发生异常的代码 } catch (error) { // 发生错误执行的代码 } finally { // 无论是否出错都会执行的代码 }
7.2 抛出异常
/*该函数接收一个数字,返回它的平方。*/ function foo(num) { if (typeof num == "number") { return num * num; } else { throw new TypeError("您输入的是一个非法数字!") } } console.log(foo(4)); console.log(foo("abc"));
7.3 自定义异常
/*自定义错误*/ function MyError(message) { this.message = "注意:这是自定义的错误" this.name = "自定义错误"; } MyError.prototype = new Error(); try { throw new MyError("注意:这是自定义错误类型") } catch (error) { console.log(error.message) }
8. 闭包
- 当一个嵌套的内部函数引用了嵌套的外部函数的变量,就产生了闭包
- 闭包的作用
- 可以读取函数内部的变量
- 让这些变量的值始终保存在内存中
8.1 闭包的演示
function fun1() { var a = 2; function subFun() { a++; console.log(a); } // 返回值是子函数 return subFun; } var f1 = fun1(); f1(); f1();
- 通过当前函数调用返回
子函数
,保证当前函数中的变量保存在内存中不会被清除
8.2 闭包的生命周期
- 产生:在嵌套内部函数定义执行完就产生了(不是在调用)
- 死亡:当嵌套的内部函数成为垃圾对象时就死亡了
function fn1() { //此时闭包就已经产生了(函数提升, 内部函数对象已经创建了) var a = 2; function fn2() { a++; console.log(a); } return fn2; } var f = fn1(); f(); // 3 f(); // 4 f = null; //闭包死亡(包含闭包的函数对象成为垃圾对象)
8.3 闭包的应用
- 具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 只向外暴露一个包含n个方法的对象或函数
- 而模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
方式一
function myModule() { //私有数据 var msg = 'Hello, World'; //操作数据的函数 function doSomething() { console.log('doSomething() ' + msg.toUpperCase()); } function doOtherthing() { console.log('doOtherthing() ' + msg.toLowerCase()); } //向外暴露对象(给外部使用的方法) return { doSomething: doSomething, doOtherthing: doOtherthing } } // 其他文件 var module = myModule(); module.doSomething(); module.doOtherthing();
方式二
(function (window) { //私有数据 var msg = 'Hello, World'; //操作数据的函数 function doSomething() { console.log('doSomething() ' + msg.toUpperCase()); } function doOtherthing() { console.log('doOtherthing() ' + msg.toLowerCase()); } //向外暴露对象(给外部使用的方法) window.myModule = { doSomething: doSomething, doOtherthing: doOtherthing } })(window); //在页面中 myModule.doSomething(); myModule.doOtherthing();
9. es6新特性
9.1 let关键字
- 用于声明一个变量
let a=1
- 不允许重复声明
- 支持块级作用域
- 不存在变量提升
- 不影响作用域链
9.2 const 关键字
- 用于声明一个常量
const MAX=100
- 不允许重复声明
- 支持块级作用域
- 声明时必须赋值
- 值不可修改
- 标识符一般大写
9.3 数组和对象支持析构解构
数组
const arr = ["张学友", "刘德华", "黎明", "郭富城"]; let [zhang, liu, li, guo] = arr;
对象
//对象的解构赋值 const lin = { name: "林志颖", tags: ["车手", "歌手", "小旋风", "演员"] }; let {name, tags} = lin;
let wangfei = { name: "王菲", age: 18, songs: ["红豆", "流年", "暧昧"], history: [ {name: "窦唯"}, {name: "李亚鹏"}, {name: "谢霆锋"} ] }; let {name, age, songs: [one, two, three], history: [first, second, third]} = wangfei;
9.4 模板字符串
let name = '小可爱'; let result = `欢迎${name}访问我的文章`;
- 可以使用
${变量名}
形式输出变量 - 字符串中支持换行符
9.5 对象支持简写
let name = "张三"; let age = 18; let speak = function () { console.log(this.name); }; //属性和方法简写 let person = { name, age, speak };
9.6 箭头函数
- 通过箭头定义函数
let fn = (arg1, arg2, arg3) => { return arg1 + arg2 + arg3; } let fn = num => { return num * 10; }; let fn = score => score * 20;
- 箭头中的this 指向
声明时
所在作用域中 this 的值
9.7 不定参数
// 作用与 arguments 类似 function add(...args) { console.log(args); } add(1, 2, 3, 4, 5);
- rest 参数必须是最后一个形参
9.8 展开运算符(伪数组)
对数组的展开
// 展开数组 let tfboys1 = ["德玛西亚之力", "德玛西亚之翼", "德玛西亚皇子"]; let tfboys2 = ["德玛西亚之力", "德玛西亚之翼", "德玛西亚皇子"]; let tfboys=[...tfboys1,...tfboys2];
对对象的展开
// 展开对象 let skillOne = { q: "致命打击" }; let skillTwo = { w: "勇气" }; let skillThree = { e: "审判" }; let skillFour = { r: "德玛西亚正义" }; let gailun = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};
9.9 class
- 类本质其实还是函数,它就是一个语法糖
- class:声明类
- constructor:定义构造函数初始化
- extends:继承父类
- supper:调用父类构造函数
- static:定义静态属性和方法
//父类 class Phone { //构造方法 constructor(brand, color, price) { this.brand = brand; this.color = color; this.price = price; } //对象方法 call() { console.log("我可以打电话!!!") } } //子类 class SmartPhone extends Phone { constructor(brand, color, price, screen, pixel) { super(brand, color, price); this.screen = screen; this.pixel = pixel; } //子类方法 photo() { console.log("我可以拍照!!"); } playGame() { console.log("我可以玩游戏!!"); } //方法重写 call() { console.log("我可以进行视频通话!!"); } //静态方法 static run() { console.log("我可以运行程序") } static connect() { console.log("我可以建立连接") } } //实例化对象 const Nokia = new Phone("诺基亚", "灰色", 230); const iPhone6s = new SmartPhone("苹果", "白色", 6088, "4.7inch", "500w"); //调用子类方法 iPhone6s.playGame(); //调用重写方法 iPhone6s.call(); //调用静态方法 SmartPhone.run();
get和set
class Phone{ get price(){ console.log("价格属性被读取了"); return 10; } set price(newVal){ console.log("价格被修改了"); } }
9.10 Symbol数据类型
- Symbol的值是唯一的(动态值,但唯一),用来解决命令冲突的问题
- Symbol值不能与其他数据进行运算
- Symbol的作用
是给对象添加属性和方法
Symbol的创建
let s=Symbol(); let s1=Symbol("张三"); let s2=Symbol("张三"); console.log(s1===s2); // false let s3=Symbol.for("张三"); let s4=Symbol.for("张三"); console.log(s3===s4); // true
给对象添加属性或方法
//在方法中使用 Symbol let game = { name: "狼人杀", [Symbol('say')]: function () { console.log("我可以发言") }, [Symbol('zibao')]: function () { console.log('我可以自爆'); } }; // 方式二 let game={ 省略 } let methods={ up:Symbol(), down:Symbol() }; game[methods.up]=function(){ console.log("我可以向上") } game[methods.down]=function(){ console.log("我可以向下") }
9.11 迭代器
- 内置迭代器的对象类型有
Array
、Arguments
、Set
、String
、TypedArray
、NodeList
- es6提供了一种新的遍历
for ... of
循环,迭代器主要提供for…of消费
如何获取对象的迭代器
//声明一个数组 const xiyou = ["唐僧", "孙悟空", "猪八戒", "沙僧"]; //使用 for...of 遍历数组 for (let v of xiyou) { console.log(v); } console.log("==============="); //获取迭代器对象 let iterator = xiyou[Symbol.iterator](); //调用对象的next方法 console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());
工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
- 每次调用next方法会返回一个包含value和done属性的对象
如何自定义一个迭代器
//声明一个对象 const banji = { name: "五班", stus: [ "张三", "李四", "王五", "小六" ], [Symbol.iterator]() { //索引变量 let index = 0; let _this = this; return { next: function () { if (index < _this.stus.length) { const result = {value: _this.stus[index], done: false}; //下标自增 index++; //返回结果 return result; } else { return {value: undefined, done: true}; } } }; } } //遍历这个对象 for (let v of banji) { console.log(v); }
- 通过闭包实现
9.12 生成器函数
定义生成器函数与访问生成器
function * gen() { /*代码1开始执行*/ console.log("代码1执行了"); yield "一只没有耳朵"; /*代码2开始执行*/ console.log("代码2执行了"); yield "一只没有尾巴"; /*代码3开始执行*/ console.log("代码3执行了"); return "真奇怪"; } let iterator = gen(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log("==============="); //遍历 for (let v of gen()) { console.log(v); }
生成器参数
function * gen(arg) { console.log(arg); let one = yield 111; console.log(one); let two = yield 222; console.log(two); let three = yield 333; console.log(three); } //执行获取迭代器对象 let iterator = gen('AAA'); console.log(iterator.next()); //next方法可以传入实参 console.log(iterator.next('BBB')); console.log(iterator.next('CCC')); console.log(iterator.next('DDD'));
模拟获取用户数据,订单数据,商品数据
function getUsers() { setTimeout(() => { let data = "用户数据"; iterator.next(data); }, 1000); } function getOrders() { setTimeout(() => { let data = "订单数据"; iterator.next(data); }, 1000); } function getGoods() { setTimeout(() => { let data = "商品数据"; iterator.next(data); }, 1000); } function * gen() { let users = yield getUsers(); console.log(users); let orders = yield getOrders(); console.log(orders); let goods = yield getGoods(); console.log(goods); } //调用生成器函数 let iterator = gen(); iterator.next();
9.13 Promise
- Promise是一个构造函数
基本使用
//实例化 Promise 对象 const p = new Promise(function (resolve, reject) { setTimeout(function () { if(远程调用成功){ resolve(data); }else{ reject(err) } }, 1000); }); //调用 promise 对象的 then 方法 p.then(function (value) { console.log(value); }, function (reason) { console.error(reason); });
使用案例
// 接口地址: https://api.apiopen.top/getJoke const p = new Promise((resolve, reject) => { //1. 创建对象 const xhr = new XMLHttpRequest(); //2. 初始化 xhr.open("GET", "https://api.apiopen.top/getJoke"); //3. 发送 xhr.send(); //4. 绑定事件, 处理响应结果 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { //判断响应状态码 200-299 if (xhr.status >= 200 && xhr.status < 300) { //表示成功 resolve(xhr.response); } else { //如果失败 reject(xhr.status); } } } }); //指定回调 p.then(function (value) { console.log(value); }, function (reason) { console.error(reason); });
支持链式调用
//创建 promise 对象 const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("用户数据"); }, 1000) }); //链式调用+箭头函数 p.then(value => { console.log(value); return value; }).then(value => { console.log(value); });
支持catch异常
const p = new Promise((resolve, reject) => { setTimeout(() => { //设置 p 对象的状态为失败, 并设置失败的值 reject("出错啦!"); }, 1000); }); p.catch(function (reason) { console.error(reason); });
9.14 Set集合
size
add()
delete()
has()
clear()
//创建一个空集合 let s = new Set(); //创建一个非空集合 let s1 = new Set([1, 2, 3, 1, 2, 3]); //集合属性与方法 //返回集合的元素个数 console.log(s1.size); //添加新元素 console.log(s1.add(4)); //删除元素 console.log(s1.delete(1)); //检测是否存在某个值 console.log(s1.has(2)); //清空集合 console.log(s1.clear());
9.15 Map集合
size
set(key,value)
get(key)
has(key)
clear()
//创建一个空 map let m = new Map(); //创建一个非空 map let m2 = new Map([ ["name", "张三"], ["gender", "女"] ]); //属性和方法 //获取映射元素的个数 console.log(m2.size); //添加映射值 console.log(m2.set("age", 6)); //获取映射值 console.log(m2.get("age")); //检测是否有该映射 console.log(m2.has("age")); //清除 console.log(m2.clear());
9.16 对象扩展
Object.is(obj1,obj2)
:很像===
console.log(Object.is(120, 120));// true console.log(Object.is(NaN, NaN));// true console.log(NaN === NaN);// false
Object.assign(obj1,obj2)
:用obj2去覆盖obj1,有重名属性则覆盖,没有的属性则添加
const config1 = { host: "localhost", port: 3306, name: "zhangsan", pass: "root", test1: "test1" }; const config2 = { host: "127.0.0.1", port: 3309, name: "lisi", pass: "root", test2: "test2" } console.log(Object.assign(config1, config2));
Object.setPrototypeOf(obj)
与Object.getPrototypeOf(obj,原型obj)
const school = { name: "MySchool" }; const cities = { xiaoqu: ["北京", "上海", "深圳"] }; Object.setPrototypeOf(school, cities); console.log(Object.getPrototypeOf(school)); console.log(school);
9.17 模块化
模块化的暴露
- m1.js
//方式一:分别暴露 export let school = "华北理工大学"; export function study() { console.log("我们要学习!"); }
- m2.js
//方式二:统一暴露 let school = "华北理工大学"; function findJob() { console.log("我们要找工作!"); } export {school, findJob};
- m3.js
//方式三:默认暴露 export default { school: "华北理工大学", change: function () { console.log("我们要改变自己!"); } }
模块化的导入
// 引入 m1.js 模块内容 import * as m1 from "./m1.js"; // 引入 m2.js 模块内容 import * as m2 from "./m2.js"; // 引入 m3.js 模块内容 import * as m3 from "./m3.js"; m1.study(); m2.findJob(); m3.default.change();
- 解构赋值形式
// 引入 m1.js 模块内容 import {school, study} from "./m1.js"; // 引入 m2.js 模块内容 import {school as s, findJob} from "./m2.js"; // 引入 m3.js 模块内容 import {default as m3} from "./m3.js"; console.log(school); study(); console.log(s); findJob(); console.log(m3); m3.change();
这篇关于JavaScript基础知识的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求