【coderwhy前端笔记 - 阶段二 JavaScript基础】

本文深入浅出地讲解了JavaScript的基础知识与核心技术,包括变量、数据类型、运算符、流程控制、函数、对象及DOM操作等内容,并通过实例演示帮助读者理解和掌握。

js章节没有像前面四章(html+css)事无巨细的记录(暂未美化)

这里写目录标题

1 编写事项

1.1 编写方式

<script src="xx.js"></script>,不需要写type="text/javascript",因为默认就是这个类型

<script src="xx.js">alert("哈哈")</script> 引入js文件时,中间写的代码不生效

注意编写顺序,从上至下执行,一般将js文件放在</body>上面

严格区分大小写

1.2 交互方式

在这里插入图片描述

// 1.交互方式一: alert函数
alert("Hello World");

// 2.交互方式二: console.log函数, 将内容输出到控制台中(console)
// 使用最多的交互方式
console.log("Hello Coderwhy");

// 3.交互方式三: document.write()
document.write("Hello Kobe");

// 4.交互方式四: prompt函数, 作用获取用户输入的内容
var result = prompt("请输入你的名字: ");
alert("您刚才输入的内容是:" + result);

快速console.log方法

方式一:输入log,回车
在这里插入图片描述

方式二:安装插件react,输入clg ,回车
在这里插入图片描述

1.3 注释

    // 1.单行注释
    
    // 2.多行注释
    /* 
     我是一行注释
     我是另外一行注释
    */

    // 3.文档注释
    /**
     * 和某人打招呼
     * @param {string} name 姓名
     * @param {number} age 年龄
     */
    function sayHello(name, age) {}
    sayHello()

1.4 代码色块对齐

代码编辑器 vscode 中打开 settings.json 加上👇

"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs":"active"

2 变量

2.1 命名规则

首字母:字母 _ $
其他字母:字母 _ $ 数字
不能使用 关键字和保留字

2.2 两个变量数字交换

方法一:借助第三个变量

var num1 = 10, num2 = 20, temp
temp = num1  // temp = 10
num1 = num2  // num1 = 20
num2 = temp  // num2 = 10

方法二:不借助第三方

var num1 = 10, num2 = 20,
num1 = num1 + num2  // num1 = 30
num2 = num1 - num2  // num2 = 30 - 20 = 10
num1 = num1 - num2  // num1 = 30 - 10 = 20

2.3 声明

1、未声明(var pyy) >> 直接使用 console.log(pyy)  >> 报错

console.log(name) // 未声明name时,默认为隐藏属性window.name,值为空
				  // 若定义了var name = "pyy" ,则name为变量的值

2、已声明(var pyy) >> 未赋值 >> undefined

3、建议声明(var pyy) >> 无特定值 >> 赋值为null

2.4 数组

var names = ["abc", "cba", "nba", "mba", "bba", "aaa", "bbb"]

3 数据

3.1 类型

8种数据类型(7种原始类型和1种复杂类型)

NumberStringBooleanUndefinedNullObjectBigInt(后续了解)、Symbol(后续了解)

typeof返回的字符串有:
undefined表示值未定义(未赋值)、boolean表示值为布尔值、string表示值为字符串、number表示值为数值、object表示值为对象(而不是函数)或null、function表示值为函数、symbol表示值为符号

内置类:Number String Boolean Symbol BigInt Math Array Date

(1)Number 数字

表示整数和浮点数:18 和 1.88,可做加减乘除运算。

特殊数值:
infinity 正无穷、(包括 1/0);
NaN 计算错误值,字符串 与 数字运算

十进制  var num1 = 111;
十六进制 var num2 = 0x111;
八进制  var num3 = 0o111;
二进制  var num4 = 0b111;

最小正数值:Number.MIN_VALUE,这个值为:5e-324,小于这个的数字会被转化为0
最大正数值:Number.MAX_VALUE,这个值为:1.7976931348623157e+308

isNaN:判断是不是一个数字,是true,否false

(2)String 字符串

字符串的三种包含方式""''``

""'' 无区别

`` ES6新增语法,可在里面增加变量表达式(推荐)

var message3 = `Hello World, ${name}, ${2 + 3}`

特殊功能的字符可以通过转义字符的形式放入字符串\'\"\\反斜杠、\t制表符、\n换行符

拼接:var str3 = str1 + str2

获取长度:console.log(str1.length)

(3)Boolean 布尔

true1false0

(4)Undefined (已声明未赋值)(未定义)

已声明(var pyy),未赋值,默认为undefined

注意:定义变量时就初始化(var pyy = null),不要将一个变量赋值为undefined

(5)Object 与 null

object 为对象,用于合并多个变量

var info = {
  name: "a",
  age: 1,
  height: 1
}
打印某一个
console.log(info.name)

初始化值

  • 已经知道设置为什么类型时
    • 数字类型 👉 0,如: var age = 0
    • 字符串类型 👉 "",(空字符串)
    • 布尔类型 👉 false

(设置 0""false,作为判断条件都会默认为 false)


  • 没想好设置为什么类型
    • {},如:var pyy = {},if(pyy) >> true,不建议初始化为{}
    • null,如:var pyy = null ,if(pyy) >>  false推荐!

null 表示对象为空,用于未知的值,不确定对象时,可以赋值null
注意:null 的 typeof 为 object

var address = null
console.log(typeof address) // Object

3.2 转换

console.log(typeof a) 打印 a 的类型

(1)转为string

隐式(⭐):
string + 任何类型 = string
如:var num1 = 11; var numStr = num1 + "";,numStr 自动转为string

显示:
调用string()函数,如string(num1)
调用toString()方法

(2)转换Number

算数运算会将其他类型转换为数字,(少用)
比如 "6" / "2",但 number + string = string

调用Number()函数,(⭐)
在这里插入图片描述

string案例:

console.log(Number("abc123")) // NaN
console.log(Number("         123       ")) // 123
console.log(Number("")) // 0

(3)转为Boolean

显示转换:调用Boolean(value)

隐式转换:

  • 直观上为“空”的值都变为false,(0""nullundefinedNaN
  • 其他变为true
  • string 或 其他类型转为 boolean >> !! ,案例: 👇
    在这里插入图片描述

(4)直接赋值

var a = "aaa"  // 此时为字符串类型
a = 1 // 此时为数字类型

3.3 运算

(1)赋值运算

在这里插入图片描述

幂运算

console.log(Math.pow(2, 4))   等于    console.log(2 ** 4)

链式赋值:从右到左进行计算

var a, b, c;
a = b = c= 2 + 2;
console.log(a, b, c) // 4 4 4

求奇偶
关键代码num % 2 == 0, yes >> 偶数
            no >> 奇数

    var num = 120
    if (num % 2 !== 0) { // 奇数
      console.log(`${num} 是一个奇数`)
    }else{
      console.log(`${num} 是一个偶数`)
    }

(2)原地修改

在这里插入图片描述

(3)++ - -

方式一:a += 1 >> a = a + 1

方式二:i++ 加 1,i-- 减 1,只能用于变量( i++ ✔) ( 5++❌ )

后置形式:counter++,(先计算,计算结束,再自增
前置形式:++counter,(先自增,再计算,计算结束

独立使用 counter++++counter 无区别

var num1 = 5  				!假设每行运算前都给 num 赋值 5
var result1 = 100 + num1++  // 先用原值参与计算,再自增
							// result: 105   num1: 6
var result2 = 100 + ++num1  // 先用原值自增,再计算
							// result: 106   num1: 6
var result3 = num1++ + 100  // 先用原值计算,再自增
							// result:105    num1: 6
var result3 = ++num1 + 100  // 先用原值自增,再计算
							// result:106    num1: 6

运算,参考优先级表格
在这里插入图片描述
var num = 5; var result = 2 + 3 * ++num
先自增,++num = 6
再乘法,3 * 6 = 18
后加法,2 + 18 = 20

(4)> < == ===

大于 >,小于<==相等性检查(两边值会先被转化为数字,此为隐式转换),=== 比较类型和内容(不做任何类型转换)

3 判断(分支)语句

3.1 if else

if() {} 的()为计算的表达式,结果为 Boolean 值

假值(falsy):0、空字符串 ""nullundefinedNaN都会被转换成false
真值(truthy):其他值被转成true

在这里插入图片描述

if(){} 只有一行时,可以省略{},如 if (num1 > 5) num2 -= 8

3.2 Switch

switch (表达式/变量) {
 case 常量1:
     console.log("常量1")
     break
 default:
     console.log("没有找到")
     break
}

不加 break 会默认穿透,直至switch结束。

合并case写法:

switch (表达式/变量) {
 case 常量1: case 常量2: case 常量3:
     console.log("heihei")
     break
 default:
     console.log("没有找到")
     break
}

3.3 one ? two : three 三元运算

因为有三个操作数

var result = condition ? value1 : value2
				条件	 为真时	  为假时

如:a b 比大小

var a = 10, b = 20
var result = a > b ? yes : no
console.log(a,b,result)

如:让用户输入一个年龄, 判断是否成年人

var age = prompt("请输入您的年龄:")
age = Number(age)
var message = age >= 18 ? "成年人": "未成年人"
alert(message)

4  逻辑运算符 && || !

在这里插入图片描述
&& >> 短路与
|| >> 短路或

4.1 或 ||

【❤】
运算元1 || 运算元2 || 运算元3
运算元1:var name = "pyy" // true,到此截至
运算元2。。。。。 不看
运算元3。。。。。 不看

【❤】
var message = info,当使用 console.log(message) ,但我们不清楚 info 是否有内容时
可以将 var message = info 改成 var message = info || "我是默认值"

【❤】
将运算元暂时转为boolean值进行判断,最后返回的仍是原始值

var info = "abc"
var obj = {name: "pyy"}
var message = info || obj || "我是默认值"
             对(true)
得:var message = info,此时 message = info = "abc"

4.2 且 &&

【❤】
运算元1 || 运算元2 || 运算元3
运算元1:var name = "" // false,到此截至
运算元2。。。。。 不看
运算元3。。。。。 不看

【❤】找找有没有obj,
在这里插入图片描述

4.3 非 !

! 反转
!! 反转再反转,就是变为原有值的布尔类型,案例看我

5 循环语句

也称为遍历或迭代

5.1 while 检查 >> 迭代

成立 >> 执行代码块
不成立 >> 跳出代码块

while(循环条件){ 循环代码块 }

如果条件一直成立 >> 死循环 (需要避免)

5.2 do…while 迭代 >> 检查

不管条件成不成立,都会先执行一次do的循环代码块

do { 循环代码块 } while(条件)

更倾向于使用while

5.3 for

for(begin;condition;step){ 循环代码块 }
for(let i = 0; i < 3; i++){ alear("hh") }
初始化
let i = 0
判断
i < 3
执行
alert('haha')
自增
i++
结束一次
结束

5.4 循环控制

break 跳出循环,结束

var names = ["abc", "cba", "nba", "mba", "bba", "aaa", "bbb"]
for (var i = 0; i < names.length; i++) {
  if (names[i] === "nba") {
    break  // 直接结束到for外面
  }
  console.log(names[i])
} // abc cba

continue 跳过本次循环,执行下一个循环体

for (var i = 0; i < names.length; i++) {
  if (names[i] === "nba" || names[i] === "cba") { // 遇到nba 或者 cba 跳过本次循环
    continue
  }
  console.log(names[i])
}
循环初始化
var i = 0
循环判断
i < names.length
if判断
是否nba 或 cba
continue跳过
循环自增
i++
打印names的i
结束一次
结束

6 JavaScript函数

6.1 foo bar baz

本身没有特别得用途和意义,常被称之为“伪变量”,一般用于不知道起什么名字时使用

foo >> var foo = "aaa"    >> 做变量名
bar >> function bar() { }  >> 做函数名
baz >> var baz = { }     >> 做数组名

6.2 函数使用步骤

  1. 声明函数 —— 封装 独立的功能
    function 函数名() { 函数封装的代码 }

  2. 调用函数 —— 享受 封装的成果
    函数名()

6.3 形参 实参

形参:接收参数用的,作为变量使用
实参:把数据传递到函数内部

 // 声明函数
 function myInfo(name,age) {  // 形参,理解为变量
 	console.log(`名字:${name},年龄:${age}`)
 }
 // 调用函数
 myInfo("pyy",45)  // 实参,理解为具体内容

6.4 返回值 return

(1)无返回值 ()

情况一:未在函数内写return

 function sayHello(name) {
   console.log(`Hi ${name}`) // 此处打印:Hi Kobe
 }

 var foo = sayHello("Kobe")
 console.log("foo:", foo)  //  此处打印:foo:undefined

情况二:虽然写return,但无返回值

 function baz() {
   console.log("Hello Baz")
   return
   console.log("Hello World")
   console.log("Hello Why")
 }

baz()

(2)执行完 return 退出函数

执行到 return 时,函数立即停止执行,退出函数

 function baz() {
   console.log("Hello Baz") // 此处打印:Hello Baz
   return
   console.log("Hello World")
   console.log("Hello Why")
 }

 baz()

(3)成功返回值

⭐成功返回值的条件:

  1. 声明函数中的 return具体的
  2. 调用该函数

有参数,返回参数值

 function sum(text) {
   return text
 }
 var summ = sum("hhh")
 console.log("return值", summ) // 此处打印:return值 hh

无参数,返回字符串

 function sum() {
   return "hh"
 }
 var summ = sum()
 console.log("return值", summ) // 此处打印:return值 hh

(4)案例

传入一个数字n, 计算1~n的数字和

 function sumN(n) {
   // 1.加对n的判断
   if (n <= 0) {
     console.log(`您传入的${n}是有问题的`)
      return
   }

   // 2.真正对1~n的数字进行计算
   // 1~n的数字和
   // 1~5 1 2 3 4 5
   var total = 0
   for (var i = 1; i <= n; i++) {
     total += i
   }
   return total
 }

 var result1 = sumN(5)
 var result2 = sumN(10)
 console.log(`result1: ${result1}, result2: ${result2}`)

 var result3 = sumN(-10)
 console.log("result3:", result3)

6.5 arguments 存放所有传入的参数

arguments 函数存放所有调用者(步骤二)传入的参数。

 步骤一:声明函数
 function foo(name,age) {     仅调用了前面两个,并命名为name和age
       // console.log(arguments[0]) //  此处打印:pyy
       // console.log(arguments[1]) //  此处打印:45
       // console.log(arguments[2]) //  此处打印:hhh
       console.log(argument) // 参数用的不一样,看个效果图
 }
 步骤二:调用函数
 foo("pyy",45,"hhh")           arguments存放了`"pyy",45,"hhh"`

在这里插入图片描述

有返回值的方法

 function sum() {
   var total = 0
   for (var i = 0; i < arguments.length; i++) {
     var num = arguments[i]
     total += num
   }
   return total
 }
 console.log(sum(10, 20))
 console.log(sum(10, 20, 30))
 console.log(sum(10, 20, 30, 40))

6.6 函数中调用函数

在这里插入图片描述

(1)递归

函数调用自己 >> 递归
在这里插入图片描述

必须要有结果,否则产生无限调用,造成报错

缺点: 性能是比较低(占用过多的栈内存)

优点: 写出来的代码非常简洁

(❤)递归的方式计算幂

递归的方式计算 23

 function pow(x, n) {			
   if(n === 1) return x			
   return x * pow(x, n-1)		
 }
 console.log(pow(2, 3))

实现思路:
  xn = x * xn-1 >> pow(2,3) = 2 * pow(2,2)
           理解为23 = 2 * 22,运算规则在pow()

运行步骤:
详细 👇
在这里插入图片描述
简约 👇
在这里插入图片描述

(❤)斐波那契

数列: 1 1 2 3 5 8 13 21 34 55 … x
位置: 1 2 3 4 5 6 7 8 9 10 … n

f(n) = f(n-1) + f(n-2)
等于前面两个数字的合

 function fibonacci(n) {
   if (n === 1 || n === 2) return 1
   return fibonacci(n-1) + fibonacci(n-2)
 }

6.6 局部变量 外部变量

ES5前没有块级作用域,但 function 函数可以定义自己的作用域(有效范围)
函数a 内部有 函数b,a内定义的变量,b可以访问到
在这里插入图片描述

概念:
函数内部 >> 局部变量 >> 在函数内部定义的变量
函数外部 >> 外部变量 >> 函数 内部访问 函数的变量,访问的变量称之为外部变量

全局变量:
函数外声明的变量,在任何函数中都可见的,通过var声明的全局变量会在window对象上添加一个属性

访问顺序:优先访问自己函数中的变量,没有找到时,在外部中访问

6.7 函数声明 与 函数表达式 区别

函数声明:在主代码流中声明为单独的语句的函数。

在函数声明被定义之前,它就可以被调用(js准备运行脚本时,首先会寻找全局函数声明,并创建这些函数),👇

在该声明中,fuction foo() 为单独的语句,调用语句foo(),放在前或后都可以

 foo()  // 放这里可以
 function foo() {
   console.log("foo函数被执行了~")
 }
 foo()  // 放这里也可以

函数表达式:在一个表达式中或另一个语法结构中创建的函数。

在代码执行到创建,并且仅从那一刻起可用,👇

将调用函数bar() 放在上面会报错,bar is not a function

 bar()    // 报错
 var bar = function() {
   console.log("bar函数被执行了~")
 }
 bar()   // 可以

6.8 头等公民

函数作为一等(头等)公民

作用:

  1. 函数可以被赋值给变量(函数表达式)👆
  2. 让函数在变量之间来回传递
 var foo1 = function() {
   console.log("foo1函数被执行~")
 }
 var foo2 = foo1 // = 👆
 foo2() // 译为调用foo2()函数 -> 调用foo1()
  1. 函数可以作为另一个函数的参数
 var foo1 = function() {
   console.log("foo1函数被执行~")		// 1、打印一次  6、再次打印
 }
 function bar(fn) {				// 3、bar()带入变量foo1代码
   console.log("fn:", fn)		// 4、此时未执行fn()->foo1()函数,打印该函数代码
   fn()							// 5、执行fn()->foo1()函数
 }
 bar(foo1)						// 2、执行 bar()

在这里插入图片描述

  1. 函数作为另一个函数的返回值
 function sayHello() {
   function hi() {
     console.log("hi kobe")	// 4、执行打印
   }
   return hi				// 2、结束!返回 hi()函数,此时  var fn = hi()
 }

 var fn = sayHello()		// 1、运行sayHello函数
 fn()					// 3、执行fn(),相当于执行hi()
  1. 将函数存储在另外一个数据结构中
 var obj = {
   name: "why",
   eating: function() {
     console.log("eating")
   }
 }
 console.log(obj);		// 1、{name: 'why', eating: ƒ}
 obj.eating()			// 2、eating
 function bar1() {
   console.log("bar1函数被执行~")
 }
 function bar2() {
   console.log("bar2函数被执行~")		// 3、bar3函数被执行~
 }
 function bar3() {
   console.log("bar3函数被执行~")
 }
 // 事件总线的封装
 var fns = [bar1, bar2, bar3]
 console.log(fns);			// 1、(3) [ƒ, ƒ, ƒ]
 fns[2]()					// 2、调用bar2()

6.9 回调函数

概念:通过 fn 去调用 bar 函数的过程, 称之为函数的回调

 function foo(fn) {
   fn()				// 2、fn = bar。   fn() -> 执行参数bar()
 }
 function bar() {
   console.log("bar函数被执行了~")	// 3、打印
 }
 foo(bar)			// 1、bar作为参数传入foo()

案例:

 function request(url, callback) {
   console.log("根据URL向服务器发送网络请求")				// 2、打印
   console.log("需要花费比较长的时间拿到对应的结果")		// 3、打印
   var list = ["javascript", "javascript学习", "JavaScript高级编程"]		// 4、新增变量 list 
   callback(list)		// 5、此时callback 值为 handleResult 的代码,
 }						//    callback(list) -> handleResult(list)

 function handleResult(res) {		// 1.5、此时函数 handleResult 作为参数传入函数request(),注意:此时未执行
   console.log("在handleResult中拿到结果:", res)		// 6、handleResult(list)被执行,效果如图
 }
 request("url", handleResult)		// 1、执行request(),传入参数:字符串"url"和 handleResult

在这里插入图片描述

省略 handleResult() 的写法

  // 3.函数回调的案例重构
 function request(url, callback) {
   console.log("根据URL向服务器发送网络请求")
   console.log("需要花费比较长的时间拿到对应的结果")
   var list = ["javascript", "javascript学习", "JavaScript高级编程"]
   callback(list)
 }

 // 传入的函数是没有名字, 匿名函数
 request("url", function(res) {
   console.log("在handleResult中拿到结果:", res)
 })

6.10 立即执行函数

现在少用,了解一下

写法:(匿名函数)(),立即执行匿名函数

 (function() {})()			// 执行的 () 放在外面,常用
 (function(fn) {}())			// 执行的 () 放在里面
 +function foo(){}()			// 非主流写法,一般不会有人写

 (function() { 
   console.log("立即执行函数被调用~")
 })()

错误写法👇,函数声明不能立即调用,函数表达式才可以

function foo(){}()

立即执行函数的参数和返回值

 var result = (function(name) { 		// 1、(匿名函数)(name),直接执行该匿名函数,参数name的值为"pyy"
   console.log("函数立刻被执行~", name)	// 2、打印:函数立刻被执行~ pyy
   return "Hello World"					// 3、函数停止,返回字符串"Hello World"。var result = "Hello World"
 })("pyy")
 console.log(result)					//4、打印result:"Hello World"

应用:

  1. 防止全局变量的命名冲突

立即执行函数中定义的变量有自己的作用域

 (function() {
   var message = "Hello World"
   console.log(message)		// 可打印
 })()
 console.log(message)		// 找不到,message is not defined

多人编写js,都恰好使用到 var message时,会造成混乱

当立即执行函数想要把某个变量返回出去时,👇,别看 不用这个了

var xmModule = (function() {
  var xmModule = {}

  var message = "Hello XiaoMing"
  console.log(message)
  console.log(message.length)

  xmModule.message = message
  return xmModule
})()

  1. 案例:监听按钮

条件:
在这里插入图片描述
知识点:
在这里插入图片描述

仅拿到按钮1:👇

 var btnEl = document.querySelector(".btn")  // 仅拿到按钮1
 console.log(btnEl)		// 打印 “<button class="btn">按钮1</button>”
 
 btnEl.onclick = function() {
   console.log("点击了按钮1")	// 点击后打印
 }

获取所有的按钮监听点击:👇

(未使用立即执行函数 👇)

 var btnEls = document.querySelectorAll(".btn")
 console.log(btnEls);                        // 获取到四个按钮

 for (let i = 0; i < btnEls.length; i++) {   // i<4,此处只能用let,使块级作用域生效,用 var 会导致执行btn.onclick时i一直为4
   
   var btn = btnEls[i];
   console.log(btn);                         // i = 0 时,打印“<button class="btn">按钮1</button>”

   btn.onclick = function() {                // i = 0 时,btn = btnEls[0],btn.onclick = btnEls[0].onclick
     
     console.log(`按钮${i+1}发生了点击`)      // i = 0 时,打印:按钮1发生了点击
     console.log(btn);                       // i = 0 时,打印“<button class="btn">按钮1</button>”
   }
 }

(使用立即执行函数 👇)

 var btnEls = document.querySelectorAll(".btn")        // 获取到四个按钮

 for (var i = 0; i < btnEls.length; i++) {
   var btn = btnEls[i];									// i = 0 时,btn = <button class="btn">按钮1</button>
   (function(m) {										// (匿名函数)(m),直接执行该匿名函数,参数m的值为"i"
     btn.onclick = function() {
       console.log(`按钮${m+1}发生了点击`)				// 传入参数 i 后,这里相当于按钮${i+1}发生了点击
     }
   })(i)
 }

 console.log(i)		// for已经执行完毕,i = 4

7 面向对象

7.1 对象的基本使用

 var person = {
   // key: value
   name: "ppy"
   age: 88
   run: function() {
     console.log("hh")
   }
 }

函数 vs 方法

 函数
 function foo() {}
 方法  // (将一个函数放在对象里,作为对象的一个属性)
 var person = {
   name: function() {}
 }

key: value 的 key 大多数情况下可以省略引号。"name": "pyy" >> name: pyy

当 key 存在空格,如 my friend 就必须加上引号 >> "my friend"

7.2 创建对象

  1. 对象字面量,var obj1 = { }
  2. Object 构造函数
 var obj2 = new Object()
 obj2.name = "kobe"
  1. new 其他类()
 function Person() {}
 var obj3 = new Person()

7.3 操作对象

(1)定义对象

var info = {
   name: "why",
   age: 18,
   friend: {
     name: "kobe",
     age: 30
   },
   running: function() {
     console.log("running~")
   }
 }

(该代码作为《访问对象》《修改对象》《添加对象》《删除对象》的前提)

(2)访问对象

在这里插入图片描述

(3)修改对象

 info.age = 25                    // 1
 info.running = function() {      // 2
   console.log("I am running~")   // 6.打印:I am running~
 }
 console.log(info.age)   // 4.打印:25
 info.running()          // 5.执行 

(4)添加对象

 info.height = 1.88
 info.studying = function() {
   console.log("I am studying~")
 }
 console.log(info)

(5)删除对象

delete

未删除时:
在这里插入图片描述
删除代码:

 delete info.age

删除后:
在这里插入图片描述

7.4 方括号 []

info.good friend = "hh" >> js无法理解
info["good friend"] = "hh" >> 可以理解

使用案例

 var obj = {
   name: "why",
   "my friend": "kobe",
   "eating something": function() {
     console.log("eating~")
   }
 }

 console.log(obj["my friend"])
 console.log(obj.name)
 console.log(obj["name"])		// 跟上面一样

 // obj["eating something"]()
 var eatKey = "eating something"
 obj[eatKey]()

结果:
在这里插入图片描述

.[] 区别
点方法 . :后面接的是一个属性名称
中括号 [] :中括号里可以是字符串、数字、变量、属性名

7.5 遍历对象

Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组;

 var info = {
   name: "why",
   age: 18,
   height: 1.88
 }

 console.log(Object.keys(info))    // 打印的是key名称,['name', 'age', 'height']

 // 对对象进行遍历
 // 1.普通for循环
 var infoKeys = Object.keys(info)
 for (var i = 0; i < infoKeys.length; i++) {
   var key = infoKeys[i]
   var value = info[key]
   console.log(`key: ${key}, value: ${value}`)   // key: name, value: why
 }                                               // key: age, value: 18
                                                 // key: height, value: 1.88
 

 // 2.for..in..: 遍历对象
 for (var key in info) {
   console.log(key);       // key是打印对象的key名称,info[key]是打印值
   var value = info[key]   // 打印值
   console.log(`key: ${key}, value: ${value}`)
 }

 // for..of..: 默认是不能遍历对象

7.6 栈内存 与 堆内存

案例一:
在这里插入图片描述

案例二:

 function foo(a) {		// 3、a = 100
   a = 200				// 4、a = 200,等于一个新值,对原来的num没有影响
 }
 var num = 100			// 1、num = 100
 foo(num)				// 2、foo(num),传入100
 console.log(num)		// 5、打印:100

(晚安~ 明天记得画原理图)

同理:

案例三 👇

 function foo(a) {
   a = {
     name: "why"       // 未传出值
   }
 }

 var obj = {
   name: "obj" 
 }
 
 console.log(foo(obj)) // 打印:underfunded
 console.log(obj)      // 打印:{ name: "obj" }

原理图
在这里插入图片描述

案例四

var m = {}
var n = {}
console.log(m === n)	// false 

m、n 虽然同为空对象,但指向不同的堆内存地址,所以不相等

7.7 值类型和引用类型

值类型

  • 原始类型的保存方式:在变量中保存的是值本身
  • 所以原始类型也被称为值类型

引用类型

  • 对象类型的保存方式:在变量中保存的是对象的 “引用”
  • 所以对象类型也被称为引用类型

7.8 this

this代表的是当前调用对象

全局环境 >> this 指向 window
对象调用 >> this 指向 调用对象

情况一:如果普通的函数被默认调用, 那么this指向的就是window
在这里插入图片描述

情况二: 如果函数它是某一个对象引用并调用它, 那么this会指向这个对象
在这里插入图片描述

情况三:变量
在这里插入图片描述

情况四:对象与声明函数
在这里插入图片描述

7.9 类和对象

(1)痛点 >> 重复代码

解决痛点:重复代码
创建一个班45个学生(对象)
https://www.iqiyi.com/v_1k74um4yugc.html?vfm=2008_aldbd&fv=p_02_01

(2)工厂函数

解决方案 ——> 工厂函数( 工厂生产student对象) ——> 一种设计模式
在这里插入图片描述
打印时,对象的类型都是Object

(3)构造函数 ⭐

构造函数也称之为构造器(constructor)通常是我们在创建对象时会调用的函数;

JavaScript已经默认提供给了我们可以更加符合JavaScript思维方式(面向对象的思维方式)的一种创建对象的规则。new

 // JavaScript已经默认提供给了我们可以更加符合JavaScript思维方式(面向对象的思维方式)的一种创建对象的规则
 // 在函数中的this一般指向某一个对象
 /*
   如果一个函数被new操作符调用
     1.创建出来一个新的空对象
     2.让this指向这个空对象
     3.执行函数体的代码块
     4.如果没有明确的返回一个非空对象, 那么this指向的对象会自动返回
 */
 function coder(name, age, height) {         // 3.执行函数体的代码块
   this.name = name                          
   this.age = age
   this.height = height
   this.running = function() {
     console.log("running~")
   }
   // return this       省略return           // 如果没有明确的返回一个非空对象, 那么this指向的对象会自动返回
 }

 // 在函数调用的前面加 new 关键字(操作符)
 var stu1 = new coder("why", 18, 1.88)      // 1.创建出来一个新的空对象    2.让this指向这个空对象
 var stu2 = new coder("kobe", 30, 1.98)
 console.log(stu1, stu2)

类的表现形式就是构造函数

  • 构造函数也时普通函数
  • 普通函数被使用new操作符来调用,那这个函数就称之为一个构造函数

一个函数被使用 new 操作符调用了,会执行以下操作:

  1. 在内存中创建一个新对象(空对象)
  2. 这个对象内部的[[prototype]]属性会被赋值为该构造 函数的prototype属性
  3. 构造函数内部的this,会指向创建出来的新对象
  4. 执行函数的内部代码(函数体代码)
  5. 如果构造函数没有明确的返回一个非空对象, 那么this指向的对象会自动返回
(❤)使用习惯

在这里插入图片描述

(4)类方法

构造函数上(类上面)添加的函数, 称之为类方法

Dog.running = function() {}
Dog.running()

7.10 全局对象 window

省略,代码 07_JavaScript对象的使用\15_额外补充-全局对象window.html

8 常见内置类

8.1 包装类型

(1)原始类型的包装类

① var name = “pyy”
② console.log(name.length)

本来原始类型就是简单的值(①),不能调用属性和方法(② ×),但是JavaScript为使其可以获取属性和调用方法,对其封装了对应的包装类型(② ✔)

常见的包装类型有:String、Number、Boolean、Symbol、BigInt类型

8.2 数字类型 Number

本身存在一个number的构造函数
Number构造函数 -> Window.Number

 // 类属性
 // Number中本身是有自己的属性
 console.log(Number.MAX_VALUE)         // 最大值
 console.log(Number.MIN_VALUE)         // 最小值
 // integer: 整数
 console.log(Number.MAX_SAFE_INTEGER)   // 最大整数
 console.log(Number.MIN_SAFE_INTEGER)   // 最小整数

方法补充

(1)toString(base) 转字符串

 var num = 1000
 console.log(num.toString(), typeof num.toString())    // 转字符串类型
 console.log(num.toString(2))            // 转二进制
 console.log(num.toString(8))            // 转八进制
 console.log(num.toString(16))           // 转十六进制

(2)toFixed(digits) 格式化数字

保留digits位小数(0~20)

 var pi = 3.1415926
 console.log(pi.toFixed(3))

(3)Number.parseInt(变量名) 解析成整数

 var num1 = "123.521"
 console.log(Number.parseInt(num1))

(4)Number. parseFloat(string) 解析成浮点数

浮点数(有小数)

 var num1 = "123.521"
 console.log(Number.parseFloat(num1))

8.3 数学对象 Math

在这里插入图片描述

(1)取整

取整数,去掉小数点

(1)Math.round() 按“周围”理解,四舍五入

(2)Math.floor() 按“地板”理解,向下取舍

(2)随机数 Math.random()  [0, 1)

生成一个0~99的随机数

var randomNum = Math.floor(Math.random() * 100)

Math.random()  >> 生成 [0, 1) >> 如:0.5471947852060866

Math.random() * 100        >> 如:54.71947852060866

Math.floor(Math.random() * 100)   >> 如:55.

8.4 字符串类型 String

(1)使用

获取长度 .length

访问某个位置的字符
变量名[4] >> 访问第五个字符(从0开始) >> 超出时为undefined
变量名.charAt(4) >> 一个方法:访问第五个字符 >> 超出时为空

遍历
for普通遍历: for (var i = 0; i < message.length; i++) { }
for…of 的遍历:for (var char of message) { }

(只有迭代器支持 for…of 遍历,目前可迭代对象:字符串、数组)

(2)修改

字符串在定义后是不可以修改的

 var message = "Hello World"
 
 message[2] = "x"   // 无任何反应,不支持修改字符串
 
 message = "aaa"	// 不能算严格意义上的修改字符串
 					// 此处为将一个新的字符串赋值给message 

变大写和变小写

 // String两个方法:(重要)
 toUpperCase: 将所有的字符变成大写
 toLowerCase: 将所有的字符变成小写
 
 var message1 = message.toUpperCase()	// 生成新字符串(message的大写)赋值给新的变量
 message = message.toUpperCase()		// 生成新字符串(message的大写)赋值给message 

(3)查找

方法一:
判断一个字符串中是否存在另外一个字符串:

  • 变量名.indexOf("pyy")
  • 存在,返回所在的索引位置(第一个字符)
  • 不存在,返回 -1
 var message = "my name is why."
 var name = "why"

 var index = message.indexOf(name)   // 11
 
 if (message.indexOf(name) !== -1) {
   console.log("message中包含name")
 } else {
   console.log("message不包含name")
 }

方法二:
判断包含关系message.includes(name) >> message内是否包含name(var name = “pyy”)

  • 包含,true
  • 不包含,false

(4)开头 结尾

是否以xxx开头message.startsWith("my") >> message是否以 “my” 开头

是否以xxx结尾message.endsWith("my") >> message是否以 “my” 结尾

(5)替换

替换字符串message.replace("why", "kobe") >> 找到 why,替换成kobe

 var message = "my name is why."
 var name = "why"
 var newName = "kobe"
 var newMessage = message.replace("why", function() {
   return newName.toUpperCase() 	// 返回newName大写
 })									// newMessage  = my name is KOBE.

(6)获取子字符串

在这里插入图片描述
常用slice,一般不用substr

 var message = "Hello World"

 // 获取子字符串
 console.log(message.slice(3, 7))    // 获取第 3 4 5 6 个字符
 console.log(message.slice(3, -1))   // 获取第 3 个 至 倒数减 1 个
 console.log(message.slice(3))       // 获取第 3 个 至 最后

 // substr
 console.log(message.substr(3, 7))	 // 获取第 3 个开始,打印 7 个字符

(7)concat 拼接 trim 删空格 split 切割 join 串联

在这里插入图片描述

8.5 数组 Array

(1)创建

创建数组
在这里插入图片描述
索引访问数组中某元素,0开始编号

 console.log(names[0]) // 第一个元素
 console.log(names[names.length-1]) // 最后一个元素

(2)基本操作(增删改查)

在这里插入图片描述

(3)增加和删除 ⭐splice

操作头部:

names.unshift("a")				在头部添加元素

names.shift()					在头部删除一个元素

操作尾部:

names.push("a", "b")			在尾部添加元素

names.pop() 					从尾部删除一个元素

任意位置添加、删除、替换:

splice:从 index 1 开始删除 2 个

names.splice(1, 2)

⭐ splice!可以添加、删除、替换

names.splice(3,1,"pyy","pyyyy") 	// 在位置3,删除1个,插入2个
  • array.splice(start, deleteCount, [item1, ....])

  • start:从start位置开始,(操作位置start),(0,1,2,3…)

  • deleteCount:删除几个(0或负表示不删除)

  • [item1, …]:从start位置后面,添加的元素

(4)length属性

在这里插入图片描述

(5)遍历

在这里插入图片描述

(6)slice 截取 cancat 拼接 join 串联

slice 截取数组,译为显示哪个

显示第2 第3个 (从0开始,到end-1个,不包含end)

names.slice(2,4)

区别:

slice方法: 不会修改原数组

splice方法: splice修改原有的数组


concat 拼接

var newNames2 = names1.concat(names2, names3)

join 将一个数组连接起来形成字符串

console.log(names.join("-"))

(7)查找 indexOf find

  • .indexOf 方法:查找某个元素的索引 >> 图1
  • .findfindIndex 直接查找元素或者元素的索引 >> 图2
  • .includes 方法:判断数组是否包含某个元素

在这里插入图片描述
解释find原理

 var stu = students.find(function(item) {		// find 会查找 students 的对象,有4个对象,则 find 4次
 												// 如第一次:item = students[0],即 { id: 100, name: "why", age: 18 }
   if (item.id === 101) return true				// 结束!找到了
 })
 console.log(stu)

⭐快捷的箭头函数写法

var stu = students.find(item => item.id === 101)
console.log(stu)

高阶函数:函数的参数是函数
在这里插入图片描述

(8)排序 sort  reverse

在这里插入图片描述

8.6 Date

(1)获取时间

打印结果:2022/11/22 6:17:54

 var year = date.getFullYear()
 var month = date.getMonth() + 1
 var day = date.getDate()
 var hour = date.getHours()
 var minute = date.getMinutes()
 var second = date.getSeconds()
 console.log(year, month, day, hour, minute, second)
 console.log(`${year}/${month}/${day} ${hour}:${minute}:${second}`)

(2)获取时间戳

方式一:new Date().getTime() 将date对象转化为时间戳 ⭐

方式二:new Date().valueOf() 将date对象转化为时间戳 ⭐

方式三:+new Date()    不用看

方式四:Date.now()     获取当前时间戳

测试代码性能
在这里插入图片描述

(3)Date.parse

将字符串时间转成时间戳

 var timeString = "03/23/2033"

 // 1.方式一:
 var date = new Date(timeString)
 var timestamp = date.getTime()

 // 2.方式二:
 var timestamp = Date.parse(timeString)
 console.log(timestamp)

(4)日期格式化

后面的写更好
在这里插入图片描述

9 DOM

ppt:10_JavaScript的DOM操作(一)

9.1 理解

DOM

  • 文档对象模型,将页面所有的内容表示为可以修改的对象 >> Document
  • DOM是浏览器文档和JavaScript语法之间的桥梁
  • 通过js来操作文档的某个元素

在这里插入图片描述

BOM:浏览器对象模型,有浏览器提供的用于处理文档之外的所有内容的其他对象,如 navigator、location、history

9.2 DOM元素之间的关系

(1)类

省略重复代码

父类 Person,Student 和 Teacher 是 Person 的子类
在这里插入图片描述

(2)继承

在这里插入图片描述

9.4 获取DOM元素

(1)对象

在这里插入图片描述

(2)节点 与 元素

在这里插入图片描述

(❤)节点

如果我们获取到一个节点(Node)后,可以根据这个节点去获取其他的节点,我们称之为节点之间的导航。
节点包括:注释 文本 等

在这里插入图片描述   在这里插入图片描述

(❤)元素

常用

如果我们获取到一个元素(Element)后,可以根据这个元素去获取其他的元素,我们称之为元素之间的导航。

元素包括:div、ul、li
在这里插入图片描述 在这里插入图片描述

(4)表格

在这里插入图片描述

案例

 // 获取body中第一个元素  已知为table
    var tableEl = document.body.firstElementChild

 // 通过table元素获取内部的后代元素
 console.log("body 的第一个元素",tableEl);
 console.log("表格的tHead", tableEl.tHead)
 console.log("表格的tBodies", tableEl.tBodies);
 console.log("表格的tFoot", tableEl.tFoot);
 console.log("表格的rows", tableEl.rows)

 // 拿到一行元素
 var rowEl = tableEl.rows[2]         // 第三行
 console.log(rowEl.cells[0])         // 第一个
 console.log(rowEl.sectionRowIndex)
 console.log(rowEl.rowIndex)

 // 1.获取1-1
 var row1El = tableEl.rows[0]
 var cell1El = row1El.cells[0]
 console.log(cell1El)

 // 2.获取2-2
 var row2El = tableEl.rows[1]
 var cell2El = row1El.cells[1]
 
 // for循环
 for (var i = 0; i < tableEl.rows.length; i++) {
   var rowEl = tableEl.rows[i]
   var cellEl = rowEl.cells[i]

   // 设置样式
   cellEl.style.backgroundColor = "red"
   cellEl.style.color = "white"
 }

在这里插入图片描述

(5)元素( ID CSS 等 )

在这里插入图片描述
querySelector ⭐ 常用
querySelectorAll
getElementByld
getElementsByName
getElementsByTagName
getElementsByClassName


9.5 DOM节点的type、tag、content

节点的属性

nodeType 节点的类型:1 - 元素,2 - 属性,3 - 文本,8 - 注释

nodeName:获取node节点的名字

tagName:获取元素的标签名词

innerHTML: 对应的html元素也会获取

textContent: 只会获取文本内容

nodeValue / data:用于获取非元素节点的文本内容

boxEl.hidden = true,隐藏


9.6 DOM节点的attributes、properies 属性

元素 中的属性称之为 attribute

对象 中的属性称之为 property

在这里插入图片描述

标准的attribute在对应的对象模型中都有对应的property

在这里插入图片描述

(1)元素的 attribute 属性

在这里插入图片描述

(2)attribute 属性 的分类

标准的attribute: 某些attribute属性是标准的,比如id、class、href、type、value等;非标准的attribute: 某些attribute属性是自定义的,比如abc、age、height等;
在这里插入图片描述

(3)attribute 属性 的操作

elem.hasAttribute(name)  >>  检查特性是否存在

elem.getAttribute(name)  >>  获取这个特性值

elem.setAttribute(name, value) >>  设置这个特性值

elem.removeAttribute(name) >> 移除这个特性

attributes >> attr对象的集合,具有name、value属性

特征:

  • 名字是大小写不敏感的、
  • 值总是字符串类型的

(4)元素的 properies 属性

对于标准的attribute,会在DOM对象上创建与其对应的property属性
在这里插入图片描述

(5)data- 自定义属性 (HTML5)

<div class="pyy" data-name="box" data-age="45"></div>



9.7 JavaScript 动态修改样式

(1)已有样式,添加class

选择一: 在CSS中编写好对应的样式,动态的添加class

className方法
boxEl.className = "abc" >> 添加一个类

注意:boxEl.className = "abc" >> 赋值会替换整个class,添加类建议用👇add()

classList 方法
boxEl.classList.add (class) >> 添加一个类
boxEl.classList.remove(class) >> 移除类
boxEl.classList.toggle(class) >> 如果类不存在就添加类,存在就移除它。
boxEl.classList.contains(class) >> 检查给定类,返回 true/false。

classList是可迭代对象,可以通过for of进行遍历。

(只有迭代器支持 for…of 遍历,目前可迭代对象:字符串、数组)

(2)动态的修改style属性

选择二:动态的修改style属性
在这里插入图片描述

可通过getComputedStyle 全局函数来读取样式
在这里插入图片描述

(3)dataset 使用

 var boxEl = document.querySelector(".box")
 // 小程序开发中使用
 console.log(boxEl.dataset.age)
 console.log(boxEl.dataset.height)

9.8 元素的常见操作

(1)创建:createElement 插入

创建一个DOM对象,并插入

 // 2.真实创建一个DOM对象
 var h2El = document.createElement("h2")	// 创建一个<h2></h2>
 h2El.className = "title"					// 添加class="title"
 h2El.classList.add("active")				// 添加class="active"
 h2El.textContent = "我是标题"				// 添加文字

 // 将元素插入boxEl
 boxEl.append(h2El)							// 在boxEl 的末尾插入
 boxEl.prepend(h2El)						// 在boxEl 的开头
 boxEl.after(h2El)							// 在boxEl 的后面插入
 boxEl.before(h2El)							// 在boxEl 的前面
 boxEl.replaceWith(h2El, "abc")				// 替换boxEl 为 h2El 和 abc

在这里插入图片描述

(2)移除:remove 复制:cloneNode

 // 1.获取元素
 var boxEl = document.querySelector(".box")					// 一个div
 var removeBtnEl = document.querySelector(".remove-btn")	// 移除按钮
 var cloneBtnEl = document.querySelector(".clone-btn")		// 复制按钮

 // 2.监听removeBtn的点击
 removeBtnEl.onclick = function() {
   boxEl.remove()											// 移除div
 }

 // 3.复制box
 var counter = 0
 cloneBtnEl.onclick = function() {
   var newNode = boxEl.cloneNode(true)						// 复制boxEl的内容。true -> 深度复制
   newNode.children[0].textContent = "我是标题" + counter	// "克隆人box"的第1个子元素文字替换为:
   // boxEl.after(newNode)
   document.body.append(newNode)							// 在body的末尾处插入

   counter++
 }

(3)案例

(❤)prompt 动态列表
  <h1>动态创建列表</h1>
  <ul class="list"></ul>

  <script>
    var ulEl = document.querySelector(".list")

    var isFlag = true
    while (isFlag) {
      var message = prompt("请输入信息:")
      if (!message) { // 没有输入内容
        isFlag = false
      } else {
        var liEl = document.createElement("li")
        liEl.textContent = message
        ulEl.append(liEl)
      }
    }
  </script>

(❤)动态显示时间

在这里插入图片描述

 // 封装了工具函数:除了年,保持两位数
 function padLeft(content, count, padStr) {
   count = count || 2             // 没有count值,则为 2
   padStr = padStr || "0"         // 没有padStr值,则为 0

   content = String(content)      // 字符串
   return content.padStart(count, padStr)    // 不够 count 位数,用 padStr 补齐
 }

 // 1.获取时间的元素
 var timeEl = document.querySelector(".time")

 setInterval(function() {         // setInterval(fn,1000) 每过一秒钟执行一次
   // 2.获取具体的时间并且进行格式化
   var date = new Date()
   var year = date.getFullYear()
   var month = padLeft(date.getMonth() + 1)
   var day = padLeft(date.getDate())
   var hour = padLeft(date.getHours())
   var minute = padLeft(date.getMinutes())
   var second = padLeft(date.getSeconds())

   // 3.将时间放到timeEl中
   timeEl.textContent = `${year}-${month}-${day} ${hour}:${minute}:${second}`
 }, 1000);

9.9 的大小、滚动、坐标

(1)DOM元素

api含义
clientWidthcontentWith+padding (不包含滚动条)
clientHeightcontentHeight+ padding
clientTopborder-top的宽度
clientLeftborder-left的宽度
offsetWidth元素完整的宽度
offsetHeight元素完整的高度
offsetLeft距离父元素的x
offsetHeight距离父元素的y
scrollHeight整个可滚动的区域高度
scrollTop滚动部分的高度

在这里插入图片描述

(2)window

window 的 width 和 height

  • innerWidth、innerHeight >> 获取window窗口的宽度和高度 (包含滚动条)
  • outerWidth、outerHeight >> 获取window窗口的整个宽度和高度 (包括调试工具、工具栏)
  • documentElement.clientHeight、 documentElement.clientWidth >> 获取html的宽度和高度 (不包含滚动条)

window的滚动位置

  • scrollX >> X轴滚动的位置 (别名pageXOffset)
  • scrollY >> Y轴滚动的位置 (别名pageYOffset)

10 事件监听 略

ppt:12_JavaScript的事件监听.pdf
在这里插入图片描述

11 DOM 实战 略

ppt:13

12 BOM 操作 略

ppt:14


PPT 08 省略


90 document 语句

A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y、Z

  • document.querySelector(“.box”) 元素选择器
    在这里插入图片描述

  • document.write(“hhh”) 在视口打印


92 随手记函数

1、prompt 输入值

var inputInfo = prompt("请输入一个值")
console.log()

2、语法糖

语法糖的概念: 一种简写或者特殊的写法, 这种写法相对于原有的写法更加的方便或者阅读性更强

相比于原来的写法, 有一点点的甜头, 称之为语法糖

简写一亿(100000000) >> 1_0000_0000

封装工具函数: 对数字进行格式化

function formatCount(count) {
  var result = 0
  if (count >= 1_0000_0000) { // 超过1_0000_0000值进行转换
    result = Math.floor(count / 1_0000_0000) + "亿"
  } else if (count >= 10_0000) {
    result = Math.floor(count / 1_0000) + "万"
  } else {
    result = count
  }

  return result
}

3 debug

终极技巧:debug,代码出问题时,产生bug,debug找出bug

打断点:
方法一,代码里写 debugger
方法二,👇,34行代码不会执行
在这里插入图片描述

100 代码规范

  1. 函数规范
function foo(x, y) { 	// foo前空格   多参数","后空一格  参数")"后空一格  "{"与前面在同一行
  let result			// 代码前面空两格
}
  1. 代码块之间空一行
    在这里插入图片描述
  2. 反引号``之间,可以换行,可以加其他变量
var message = `
呼呼呼${bar}
`
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值