JavaScript学习

一、对象

  • 对象的创建

    • 形式 字面量(var,let,cont) 变量名 = {键值对}
    • 方法    new Object()
var obj = {
    name: 'baozi',
	age: 18
}
console.log(obj);
var nobj = new Object();
console.log(nobj);
  • 操作对象的属性

    • 添加属性

      • 点语法   对象.属性名 = 属性值;
      • [] 语法   对象["属性名"] = 属性值;

注意事项:

  • 添加属性值的时候,如果是字符串形式,一定要加上引号
  • 在使用[]方法的时候,中括号里的属性名也要加上引号
obj.sex = "男";
console.log(obj)
nobj["name"] = "rbz";
console.log(nobj);
  • 更改属性值

    • 可以使用添加属性值的方法进行更改
obj.sex = "nan";
console.log(obj)
nobj["name"] = "肉包子";
console.log(nobj);
  • 删除属性

    • 方法   delete 对象名.属性名
delete obj.age;
console.log(obj);
  • 查找属性值

    • 方法  对象名["属性名"]         
console.log(obj["name"]);

二、运算符 

  • 算数运算符

    • +(加)  -(减)  *(乘)    、(除)  %(取余)
  • 比较运算符

    • >(大于号),<(小于号) ,>= (大于等于),<=(小于等于) ,== (等于号) ,!=(不等于) , ===(全等号 要求值和数据类型都一致),!==(不全等)

注意:

  • 比较运算符返回的结果是布尔值,true或者是false
  • 一个等于号是复制,将右边的数据赋值给左边的变量
  • 两个等号是判断是否相等,只会比较数值大小,不会进行数据类型的比较,只需要数据大小相同即可    console.log(18 == '18')   // true
  • 三个等号就是既要要求数据大小,也要要求数据类型相同   console.log(18 == '18')   // false
  • 不等于和不全等这两个返回值是双等和三等号的相反值,如果不等为false,那么与之对应的双等就是true,反之则是false。
var a = 10,
    b = "10",
    c = '20';
console.log(a !== b)        //true
console.log(a == b)         //true
console.log(a != b)         //false
console.log(a != c)         //true
console.log(a === c)        //false
console.log(a !== c)        //true 
  • 自增 ++ 和自减--

    • 自增++

      • 使用口诀:先自加,后返回值       ++num => num = num+1

var num = 10;
alert (++num + 10); // 21
console.log(num)        //11
  • 自减--
    • 使用口诀:先返回原值,后进行自加

var num = 10;
alert(10 + num--); // 20
console.log(num)        //9

 注意

  • 前置递增和后置递增运算符可以简化代码的编写,让变量的值 + 1 比以前写法更简单

  • 单独使用时,运行结果相同,与其他代码联用时,执行结果会不同

  • 开发时,大多使用后置递增/减,并且代码独占一行

  • 逻辑运算符

    •  逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值
      • &&(逻辑与) ||(逻辑或) !(逻辑非)
true && false     // false
true ||  false    // true
!true            // false
  • 赋值运算符      

    •  =(直接赋值) +=(加上一个数字再等于) -=(减去一个数字再等于) *= /= %= 乘,除,取模后再赋值
var age = 10;
age += 5;  // 相当于 age = age + 5;
age -= 5;  // 相当于 age = age - 5;
age *= 10; // 相当于 age = age * 10;
  •  运算符的优先级(优先级从上到下)

    • 小括号 ()
    • 一元运算符 +,-,++,--,!
    • 算数运算符 先 * / 后 + -
    • 关系运算符 >,>=,
    • 相等运算符 ==,===,!== ,!=
    • 逻辑运算符 先与运算,后或运算
    • 赋值运算符 =
    • 逗号运算符

注意:

  • 一元运算符里面的逻辑非优先级很高

  • 逻辑与要比逻辑或的优先级高

三、流程控制语句 

        流程控制主要有三种结构,分别是顺序结构分支结构循环结构,这三种结构代表三种代码执行的顺序

  • 分支结构

  • if语句

    • if
if(条件表达式){
    //条件成立的时候,执行里面的代码语句
}
  • if else
if(条件表达式){
    //条件成立的时候,执行里面的代码语句
}else{
    //否则,条件不成立的时候,执行里面的代码语句
}
  • if else if else
if(条件表达式1) {  
    语句1; 
} else if(条件表达式2) {
   语句2; 
} else if(条件表达式3) {
  语句3; 
} else { 
  *//上述条件都不成立执行此处代码* 
}
  • 三元表达式

语法结构:表达式1?表达式2:表达式3

如果表达式1为true,则返回表达式2的值,如果表达式1为false,则返回表达式3的值

var figuer = prompt('请输入0~59之间的一个数字');
var result = figuer < 10 ? '0' + figuer : figue
alert(result);         
  •  switch语句

switch :开关 转换 , case :小例子 选项

关键字 switch 后面括号内可以是表达式或值, 通常是一个变量

关键字 case , 后跟一个选项的表达式或值,后面跟一个冒号

  • 执行流程

switch 表达式的值会与结构中的 case 的值做比较

如果存在匹配全等(===) ,则与该 case 关联的代码块会被执行,并在遇到 break 时停止,整个 switch 语句代码执行结束

如果所有的 case 的值都和表达式的值不匹配,则执行 default 里的代码

执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句

switch(表达式){
  case value1:
     //表达式等于 value1 时要执行的代码
     break;
  case value2:
     //表达式等于value2 时要执行的代码
     break;
  default:
     //表达式不等于任何一个value时要执行的代码        
}
  • 示例
var fruit = prompt('请您输入查询的苹果');
switch (fruit) {
    case '苹果':
        alert('苹果的价格为3.5元/千克');
        break;
    case '香蕉':
        alert('香蕉的价格为3元/千克');
        break;
    default:
        alert('没有这种水果');
}
  • 循环语句

  • for循环

        在程序中,一组被重复执行的语句被称之为循环体,能否继续重复执行,取决于循环的终止条件。由循环体及循环的终止条件组成的语句,被称之为循环语句。

for(初始化变量;条件表达式;操作表达式) {

   //循环体 

}
  • 示例
  • 输出10句 你好!
for(var i = 1; i<=10; i++  ){
     console.log('你好');
}
  • 输出一行比一行多一个星星,一共十行
var star = ""
for(var a =0 ;a<10 ;a++){
    star += "*";
    console.log(star)
}
  •  双重for循环

         循环嵌套是指在一个循环语句中再定义一个循环语句的语法结构,例如在for循环语句中,可以再嵌套一个for 循环,这样的 for 循环语句我们称之为双重for循环。

for(外循环的初始;外循环的条件;外形循环的操作表达式){
    for(内循环的初始;内循环的条件;内循环的操作表达式){
        需执行的代码;
    }
}
  • 注意:
    • 内层循环可以看做外层循环的语句
    • 内层循环执行的顺序也要遵循 for 循环的执行顺序
    • 外层循环执行一次,内层循环要执行全部次数
  • 示例:
  • 打印五行五列五角星 
var star = '';
for(var j = 1;j<=5;j++)
{
   for (var i = 1; i <= 5; i++)
   {
     star += '☆'
   }
    //每次满5个星星就加一次换行
    star +='\n'  
}
console.log(star);
  • 打印倒三角
var star = '';
var row = prompt('请输入行数');    
var col = prompt('请输入列数');
for (var i = 1; i <= row; i++) {
    for (var j = i; j <= col; j++) {
        star += '☆';
    }
    star += '\n';
}
console.log(star);
  •  while循环

  • 执行逻辑
    • 先执行条件表达式,如果结果为 true,则执行循环体代码;如果为 false,则退出循环,执行后面代码

    • 执行循环体代码

    • 循环体代码执行完毕后,程序会继续判断执行条件表达式,如条件仍为true,则会继续执行循环体,直到循环条件为 false 时,整个循环过程才会结束

  • 注意
    • 使用 while 循环时一定要注意,它必须要有退出条件,否则会称为死循环

    • while 循环和 for 循环的不同之处在于 while 循环可以做较为复杂的条件判断,比如判断用户名和密码

  • 示例:
  • 打印从1到99

var age = 0;
while (age <= 100) {
    age++;
    console.log('您今年' + age + '岁了');
}
  •  计算1~100的和
var figure = 1;
var sum = 0;
while (figure <= 100) {
    sum += figure;
    figure++;
}
console.log('1-100的整数和为' + sum);
  • do while循环

  • 执行逻辑
    • 先执行一次循环体代码
    • 再执行表达式,如果结果为true,则继续执行循环体代码,如果为false,则退出循环,继续执行后面的代码
    • 先执行再判断循环体,所以dowhile循环语句至少会执行一次循环体代码
do {
  //循环体代码-条件表达式为true的时候重复执行循环一代码
}while(条件表达式);
  •  示例
  • 弹出一个提示框, 你爱我吗? 如果输入我爱你,就提示结束,否则,一直询问 

do {
    var love = prompt('你爱我吗?');
} while (love != '我爱你');
alert('登录成功');
  • continue 关键字

 用于立即跳出本次循环,继续下一次循环(本次循环体中 continue 之后的代码就会少执行一次)。

//例如,吃5个包子,第3个有虫子,就扔掉第3个,继续吃第4个第5个包子
for (var i = 1; i <= 5; i++) {
 if (i == 3) {
     console.log('这个包子有虫子,扔掉');
     continue; // 跳出本次循环,跳出的是第3次循环 
  }
  console.log('我正在吃第' + i + '个包子呢');
}
  •  break 关键字

break 关键字用于立即跳出整个循环 

//吃5个包子,吃到第3个发现里面有半个虫子,其余的也不吃了
for (var i = 1; i <= 5; i++) {
   if (i == 3) {
       break; // 直接退出整个for 循环,跳到整个for下面的语句
   }
   console.log('我正在吃第' + i + '个包子呢');
 }
  • 四、this与自定义属性

  • this关键字

        this默认指向的是当前元素,全局函数中的this指向window对象

        代码中声明了一个全局函数,是属于浏览器窗口对象的,所以this表示的就是浏览器窗口对象window

function fn() {
    consolo.log(this);
}
fn()
//标签事件属性中的this指向window对象

        如果将一个全局函数在一个标签属性中调用,如下

<button onclick="fn()">点我试试</button>
function fn() {
    console.log(this)
}
//事件属性函数中的this指向当前操作的标签

        如果在标签对象的属性上声明了一个函数,此时这个函数属于标签属性,所以函数内部的this指向当前标签对象

<button id="btn">点我试试</button>
var btn = document.getElementById('btn');
btn.onclick = function() {
    console.log(this);
}
  • 自定义属性

// 自定义属性:自己定义
// 固有属性:系统提供的
var oDiv = document.getElementsByTagName("div");

console.log(oDiv[0].tag); //unfined  暂时获取不到直接写在标签上的自定义属性

//1.在js中添加自定义属性 标签.属性名
oDiv[0].tag = true;
console.log(oDiv[0].tag);
  • 五、初级函数

    • 函数声明

// 函数表达式
var f = function() {
      console.log(1);  
}
 
// 函数声明
function f (){
     console.log(2);
}
// 调用
f()
  • 形参和实参

    • 形参:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。

    • 实参:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。

// 函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部
// 带参数的函数声明
function 函数名(形参1, 形参2, 形参3...) {
  // 函数体
}
 
// 带参数的函数调用
函数名(实参1, 实参2, 实参3); 
形参1 = 实参1
形参2 = 实参2
形参3 = 实参3
...

注意事项:

函数最终的运算结果由实参所解决定;
不论形参还是实参,都不需要关键字“var”的显示声明,函数的参数只能在函数内部访问。
形参与实参是通过位置而不是参数名来匹配对应的
形参与实参的个数可以不一致
如果一个形参没有接收到实参传递来的值,那么他为undefined

在实参数量未知的时候可以使用arguments。arguments代表了一个函数的所有参数,他是一个类似数组的东西,可通过下标取值。在我们不知道具体的参数个数时,尤为有用。

  • 返回值

        当函数执行完的时候,并不是所有时候都要把结果打印。我们期望函数给我一些反馈(比如计算的结果返回进行后续的运算),这个时候可以让函数返回一些东西。也就是返回值。函数通过return返回一个返回值。

        每一个函数都会有一个返回值,这个返回值可以通过关键字“return”进行设置。

//声明一个带返回值的函数

function 函数名(形参1, 形参2, 形参3...) {

//函数体

return 返回值;

}

 
//可以通过变量来接收这个返回值

var 变量 = 函数名(实参1, 实参2, 实参3...)

注意事项:
若未显式地设置函数的返回值,那函数会默认返回一个undefined值
但若手动地设置了函数的返回值(return)后,函数将返回开发者手动设置的那个值
在函数中,一旦执行完成“return”语句,那么整个函数就结束了,后续语句将不再执行;
就是“return”之后的值只能有一个。如果尝试返回多个值,那得到的结果始终是最后一个值
  • 预解析与作用域

  • 作用域

在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

就是代码名字(变量)在某个范围内起作用和效果 目的是为了提高程序的可靠性更重要的是减少命名冲突

作用域的划分全局作用域:整个script标签 或者是一个单独的js文件,script标签以内,函数体以外称之为全局作用域

<script> 
  var num = 10;
  var num = 30;
  console.log(num);
</script>

        局部作用域:函数执行形成局部作用域(私有作用域)在函数内部就是局部作用域 这个代码的名字只在函数内部起效果和作用。

function fn() {
    // 局部作用域
    var num = 20;
    console.log(num);
}
fn();

全局变量和局部变量全局变量(全局函数):全局作用域下定义的变量就属于全局变量,可以在任意地方使用或修改

// 注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量
var num = 10; // num就是一个全局变量
console.log(num);    
function fn() {
   console.log(num);
}
fn();

局部变量(局部函数):局部作用域下定义的变量就属于局部变量,只能在当前作用域下使用或修改

  // 注意: 函数的形参也可以看做是局部变量
function fun(aru) {
    var num1 = 10; // num1就是局部变量 只能在函数内部使用
    num2 = 20;
}
fun();
     从执行效率来看全局变量和局部变量
     (1) 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
     (2) 局部变量 当我们程序执行完毕就会销毁, 比较节约内存资源
     js中没有块级作用域  js的作用域: 全局作用域  局部作用域  现阶段我们js 没有 块级作用域
        我们js 也是在 es6 的时候新增的块级作用域
        块级作用域 {}   if {}  for {}
  • 预解析

-我们js引擎运行js 分为两步: 预解析 代码执行
  • 预解析 js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面
  • 代码执行 按照代码书写的顺序从上往下执行
    • 预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
      • 变量提升 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
      • 函数提升 就是把所有的函数声明提升到当前作用域的最前面 不调用函数
    • 预解析可以分为:
      • 全局作用域下的预解析
      • 局部作用域下的预解析
    • 预解析发生在js代码真正执行之前,先进性预解析的操作,把所有带有var和functiuon关键的进行预解析,var进行预解析是只声明不定义,funtion在预解析的时候是声明+定义
  • 函数封装 

函数 是由事件驱动的或者当它被调用时执行的可重复使用的代码块。 用函数把重复的代码块包裹起来就是函数封装。

封装的作用: 其实就是为了减少代码的冗余,增加代码的可读性与易维护性, 将实现同一功能的代码封装起来,在需要实现这一功能时调用即可。

  • 六、匿名函数和密保 

    • 匿名函数

      • 匿名函数就是没有函数名的函数,但是这样写的话,会报错,所以为了解决这个问题我们可以从多个角度进行解决

// 1.把匿名函数赋值给一个变量

var box=function(){
  return 'Hex';
}

alert(box());


// 2.通过自我执行来调用函数

(function(){
    alert('Hex');
})();


// 3. 把匿名函数自我执行的返回值赋值给变量

var box=(function(){
    return 'Hex';
})();
alert(box);//注意:此处不带括弧


// 4.省去变量

alert((function() {
    return 'Hex';
})());


// 5.在使用的时候如何传参

(function(age) {
    alert('Hex--' + age);
})(30);
  •  闭包

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

var n=999;

function f1(){
alert(n);
}

f1();  // 999
另一方面,在函数外部无法读取函数内的局部变量。

function f1(){
    var n=999;
}

alert(n);  // error

这里有一个地方需要注意, **函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!** 

function f1(){
n=999;

}

f1();

alert(n);  // 999
  • 作用 

    • 通过一系方法,将函数内部的变量(局部变量)转化为全局变量

    • 子级可以调用父级的变量,而父级无法调用子级的变量

function f1(){

    var n=999;  
    
    function f2(){
        alert(n);   // 999
    }

}
  • 七、定时器

 js的定时器有两种定时器,一个是延迟执行,一个是间断执行

//setTimeout():指定时间后执行一段代码(延迟执行)。
//setInterval():每隔一段时间执行一段代码(间隔执行)。

//延迟执行
 setTimeout(function(){
    console.log(111);
},1000)  //一秒钟打印出111

 
//间隔执行
setInterval(function(){
    console.log(111);
},1000)  //每隔一秒钟打印出111
  • 清除定时器

 每次使用定时器时,必须清除定时器

clearTimeout(timer) ====> 用于清除setTimeout
clearInterval(timer) ====> 用于清除setInterval

示例: 

//在开启定时器的同时定义一个变量接受定时器返回的id,用于清除定时器
var timer=setTimeout(function(){
    console.log(111);
},1000)

// 使用清除延迟定时器
clearTimeout(timer);

var timer2=setInterval(function(){
    console.log(111);

},1000)
  // 使用清除间歇定时器
clearInterval(timer2);
  • 八、内置对象

  • 什么是内置对象

    • 根据JS API(开发文档说明)(Application Program Interface)讲解的内置对象就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或者最基础而且最必要的功能(常用的属性、函数等)

  • math对象

  • 常用方法

// 向下取整,不会四舍五
console.log(Math.floor(3.99))   //3
// 向上取整,会四舍五
console.log(Math.ceil(3.56))        //4     
// 四舍五入法
console.log(Math.round(3.6))        //4
// Math.max():获取数组序列中最大的值
console.log(Math.max(5,20))         //20
// Math.min():获取数组序列中最小的值
console.log(Math.min(5,20))         //5
// 计算某个数组的次方数  计算5的20次方
console.log(Math.pow(5,20))         //95367431640625
// 开平方根
console.log(Math.sqrt(100))         //10
// 获取随机数   范围是(0,1)
console.log(Math.random())        
  • 应用
// 1.随机一个整数
Math.round(Math.random()*10)
//或者是从0-10之间的整数
parseInt(Math.round()*10)


// 2.指定一个任意整数的范围
// 指定一个范围整数取随机整数,并且要求包含这两个整数
function randomNum(min,max){
    return Math.floor(Math.random()*(max-min+1)+min);
}


// 3.随机点名系统
<p id="name"></p>
<button type="button">确定</button>
<button type="button">开始</button>
<script>
    var namelist = [
        "老李",
        "老王",
        "老张",
        "老赵",
        "老钱",
        "老孙",
        "老周",
        "老吴",
        "老郑",
        "老程",
    ];
    var p = document.getElementById("name")
    var btnEnd = document.getElementsByTagName("button")[0];
    var btnStar = document.getElementsByTagName("button")[1];

    function qiehuan() {
        var index = parseInt(Math.random() * namelist.length);
        p.innerText = namelist[index]
    }

    var timer = setInterval(qiehuan, 1);
    btnEnd.onclick = function () {
        clearInterval(timer)
    }
    
    btnStar.onclick = function(){
        timer = setInterval(qiehuan, 1);
    }
</script>


// 4.生成随机验证码
var str = "safsdfa564x1b54x5g1e51654b64h64e6aGDG6sg6g46sd4f8eG";
var p = document.getElementsByTagName("p")[0]

// 第一种方法
function randomNum(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}
var item = randomNum(0, str.length - 6);
var a = str.substring(item, item + 5);
p.innerHTML ="第一种方法生成的验证码&nbsp;"+ a;


// 第二种方法
var str1 = "abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQISTUVWXYZ0123456789";
var p2 = document.getElementsByTagName("p")[1]
var res = ""
for (let a = 0; a < 5; a++) {
    let index = parseInt(Math.random() * str1.length)
    res += str1.charAt(index)
}
console.log(res)
p2.innerHTML ="第二种方法生成的验证码&nbsp;"+ res;
  • Date对象

date主要是用来处理日期和时间

获取当前时间,使用date对象必须要实例化

var time = new Date();

 获取指定时间的日期对象

var time=new Date("2021,10,1");   

//语法解释
利用new来声明一个新的的对象实体,使用new操作符的语法如下:
var 实例对象名称 = new 对象名称(参数列表)

date对象常用的方法

//Date    操作日期和时间的对象
Date.getFullYear()            //返回Date对象的年份字段
Date.getMonth()            //返回月份数(0-11),想要几月的话,需要加一
Date.getDay()            //返回一周的第几天(0-6) 0 代表周日
Date.getDate()            //返回日期的“日”部分,值为1~31
Date.getHours()            //返回日期的“小时”部分,值为0~23
Date.getMinutes()            //返回日期的“分钟”部分,值为0~59
Date.getSeconds()            //返回日期的“秒”部分,值为0~59
Date.getTime()                //返回从1970年1月1日00:00到现在的毫秒数(格林尼治时间),也就是时间戳
Date.setFullYear()            //设定日期的“年”部分
Date.setMonth()                //设定日期的“月”部分,值为0~11。其中0表示1月,…,11表示12月
Date.setDate()                //设定日期的“日”部分,值为0~31
Date.setHours()                //设定日期的“小时”部分,值为0~23
Date.setMinutes()                //设定日期的“分钟”部分,值为0~59
Date.setSeconds()                //设定日期的“秒”部分,值为0~59

示例

var date = new Date();
console.log(date);
year = date.getFullYear();
console.log("当前年份是", year);
month = date.getMonth() + 1;
console.log("当前月份是", month); //0为一月,比实际少1个月  所以要想获取当前的实际日期,需要+1
date1 = date.getDate();
console.log("当前日期", date1)
day = date.getDay();
console.log("当前星期", day) //0为星期天
time = date.getTime();
console.log("当前时间", time); //返回从1970年1月1日00:00到现在的毫秒数(格林尼治时间),也就是时间戳
hour = date.getHours();     
console.log("当前时间的小时", hour) //24小时制
minutes = date.getMinutes();
console.log("当前时间的分钟", minutes);
seconds = date.getSeconds();
console.log("当前时间的秒数", seconds) //毫秒为单位
  • String对象

常用方法

String            //操作字符串的对象
length属性        //获取字符串的长度
charAt(下标)        //获取对应位置的字符
indexOf(str[,index])    //返回某个指定的字符串值在字符串中首次出现的位置
lastIndexOf(str[,index])        //返回某个指定的字符串值在字符串中最后一次出现的位置
substring([start,[stop]])        //截取字符串,从start到stop,包括开始不包括结束 。
slice([start,[stop]])    //截取字符串
toUpperCase        //转换为大写
toLowerCase            //转换为小写
split            //(分割标准,[数组的长度]) : 将字符串按特定标志分割成数组
replace        //(被替换的字符串,替换的字符): 替换特定的字符

实例演示

var str = "asdfsdgcxhedfgshsRSFssdg";
console.log(str)
console.log("长度为", str.length); //24
console.log("下标为5(第六个字母是)", str.charAt(5)); //d
console.log("h第一次出现的下标是", str.indexOf("h")); //9
console.log("s最后一次出现的下标是", str.lastIndexOf("s")); //21
console.log("查看是否存在l,如果存在则返回对应的下标,如果不存在则返回-1", str.indexOf("l")); //-1
// substring

//从下标为0的地方开始截取,一直截取到下标为4的位置(不包括自己缩写的结束下标)
var a = str.substring(0, 5);
console.log(a) //asdfs
// 如果只有开始位置,那么代表的意思就是从这个下标开始一直到结束
a = str.substring(1);
console.log(a);     //sdfsdgcxhedfgshsRSFssdg
//如果参数为负数,那么代表的意思是0
a = str.substring(-1,3);
console.log(a)      //asd
// 如果开始参数的位置在结束参数位置的右侧,截取结果为结束位置到开始位置之间所有的字符,但不包括开始位置的字符(也就是将两个参数位置对调,开始参数变为结束参数,结束参数变为开始参数)
a = str.substring(4,1);
console.log(a)  //sdf
// 如果开始和结束位置一样,结果为空
a = str.substring(1,1);
console.log(a)

// slice
//从下标为0的地方开始截取,一直截取到下标为4的位置(不包括自己缩写的结束下标)
var a = str.slice(0, 5);
console.log(a) //asdfs
// 如果只有开始位置,那么代表的意思就是从这个下标开始一直到结束
a = str.slice(1);
console.log(a);     //sdfsdgcxhedfgshsRSFssdg
//如果参数为负数,那么代表的意思是从右往左数(倒序-1,-2,-3……),
a = str.slice(-1);
console.log(a)      //g
a = str.slice(-5,-1);       
console.log(a)                  //Fssd
a = str.slice(-5,22);
console.log(a)              //Fss
// 如果开始参数的位置在结束参数位置的右侧,截取结果为空
a = str.slice(3,0);
console.log(a)      //空
// 如果开始和结束位置一样,结果为空
a = str.slice(1,1);
console.log(a)      //空

// 大小写切换   不会对原字符串产生任何的影响
var b = str.toUpperCase();      //将该字符串全部转换成大写
console.log(b)      //ASDFSDGCXHEDFGSHSRSFSSDG
b = str.toLowerCase();      //将该字符串全部转换成小写
console.log(b)      //asdfsdgcxhedfgshsrsfssdg


// 切割字符串       split  不会对原字符串产生影响
var arr = "2022-12-23";
var arr1 = arr.split("-"); //按照特定的字符“-”,将字符串进行切割
console.log(arr1)   //(3) ['2022', '12', '23']
console.log(arr)    //2022-12-23
//替换特定的字符   replace      不会对原字符串产生影响,且只执行一次
var arr2 = arr.replace("-",'*')
console.log(arr2)//2022*12-23
console.log(arr)    //2022-12-23

// 将数组转换为字符串
// 第一种方法       通过使用toString()方法将其强制转换为字符串,然后通过替换进行替换(此处用到了正则,g代表的是执行全局匹配[查找所有匹配而非在找到第一个匹配后停止)
var arr3 = arr1.toString().replace(/,/g,'-');
console.log(arr3)   //2022-12-23
console.log(arr1)   //(3) ['2022', '12', '23']
// 第二种方法
var arr4 = arr1.join('*');
console.log(arr4);      //2022*12*23
console.log(arr1)       //(3) ['2022', '12', '23']

// 检索字符串中指定的子字符串   search()  
/*  
    搜索单个字符
        如果字符串里面有,则返回它所对应首次出现的下标
        如果字符串里没有,则返回-1
    搜索多个字符组合
        如果字符串里面有,则返回它们整体首次出现中的第一个字符的下标
        如果字符串里没有,则返回-1
 */
var arr5 = "asdfa"
console.log(arr5.search("a"))   //0
console.log(arr5.search("sd"))  //1
console.log(arr5.search("e"))   //-1
console.log(arr5.search("ae"))  //-1

// 可在字符串内检索指定的值     match()   一般与正则表达式进行联合使用
var arr6 = "asd asd asd ASD aSd lasd wdsa";
console.log(arr6.match(/asd/g))

注意:

slice与substring的区别在于当接收的参数是负数时,slice会将它字符串的长度与对应的负数相加,结果作为参数。substring则干脆将负参数都直接转换为0

示例演示2:

// 文字展开收缩
<div>
    <p>为贯彻落实党中央、国务院决策部署,12月21日,教育部会同中央网信办、公安部、国家疾控局召开2023年研考工作调度会。教育部党组书记、部长怀进鹏出席会议并讲话,教育部党组成员、副部长翁铁慧主持会议。会议要求,各地各部门要提高政治站位,强化政治执行力,落实安全稳定责任,全力以赴抓好研考组织工作。各地要调集动员专门力量,优先保障考生核酸检测,及时向考生和考点反馈核酸检测结果。加强考场防疫管理,配足配齐防疫物资。要加强组考管理,确保考试安全。要严格执行安全保密规定,确保试卷流转绝对安全,严格落实入场和考场监督检查要求,严厉打击考试作弊,严肃处理各类违规违纪行为。会议要求,各地各有关部门要加强服务保障,关心关爱广大考生和考务工作人员。要坚持以生为本,优化考生服务,加强政策宣传解读,及时告知考生组考防疫安排,及时回应和妥善解决考生急难愁盼的问题,积极为特殊困难考生参加考试提供合理便利。要关心考务工作人员,创造有利条件,为广大考务工作人员,尤其是监考老师,提供安全暖心的工作环境。中央网信办、公安部、国家疾控局有关负责同志出席会议,并就做好研考考试环境综合治理和组考防疫工作作了讲话。河南省、广东省有关负责同志发言。会议在北京设主会场,各省、自治区、直辖市设分会场。各省(区、市)高校招生委员会主任、有关部门负责同志及各省教育行政部门、招生考试机构主要负责同志参加会议。
    </p><span>收缩</span>
</div>
<script>
    var p = document.getElementsByTagName("p")[0];
    var str = p.innerText;
    var span = document.getElementsByTagName("span")[0];
    var a = 0;
    span.onclick = function () {
        a++;
        if (a % 2) {
            span.innerHTML = "展开";
            p.innerHTML = str.slice(0, 50) + "……";
        } else {
            span.innerHTML = "收缩";
            p.innerHTML = str;
        }
    }
</script>
  • 数组

  • 数组(Array)是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素可以放数组,字符串,数字,集合对象等,所有的都可以放

//普通变量一次只能存储一个值
var num = 10;
//数组一次可以存储多个值
var arr =[1,2,3,4,5];
  • 创建数组

//第一种方法:利用 new 创建数组
var 数组名 = new Array();
var arr = new Array(); //创建一个新的空数组


//第二种方法:利用数组字面量创建数组
// 1.利用数组字面量方式创建空的数组 
var 数组名 =[];
// 2.使用数组字面量方式创建带初始值的数组
var 数组名 =['小白','小黑','小黄','瑞奇'];
// 3.数组中可以存放任意类型的数据,例如字符串,数字,布尔值等
var arrStus =['小白',12,true,28.9];

注意:

  • 数组的字面量是方括号 []
  • 声明数组并赋值称为数组的初始化
  • 这种字面量方式也是我们以后最多使用的方式
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0, "a", null, false, undefined, [5, 7]];
// 1.push()  向数组的末尾添加一个或多个元素,并返回新的长度
// 返回的是一个新数组的长度,要想获取新数组,直接打印原数组即可,如果想要添加多个,,直接使用逗号隔开即可
var a = arr.push("{aa:1}", "aa")
console.log(arr)
console.log(a)
// 2.pop()  删除并返回数组的最后一个元素
// 返回的是原数组最后一项的数据,如果打印原数组,那么获取到的是删除完之后的数据,想要获取被删除的数据,需要拿一个新的变量进行存取
var b = arr.pop()
console.log(arr)
console.log(b)
// 3.shift() 删除并返回数组的第一个元素
//返回的是原数组第一项的数据,如果打印原数组,那么获取到的是删除完之后的数据,想要获取被删除的数据,需要拿一个新的变量进行存取
var c = arr.shift()
console.log(arr)
console.log(c)
// 4.unshift():向数组的开头添加一个或更多元素,并返回新的长度。
//返回的是一个新数组的长度,要想获取新数组,直接打印原数组即可,如果想要添加多个,直接使用逗号隔开即可
var d = arr.unshift(1, "aa")
console.log(arr)
console.log(d)
// 5.splice()
//5.1 删除数组元素  数组.splice(index,howmany)  ,从下标为index开始,一直删除howmany个元素
//所返回的数据是被删除的内容,需拿一个变量进行存储,直接打印原数组是直接打印被删除之后的数组
var e = arr.splice(1, 5) //删除数组,从下标为一的位置开始删除,然后一直删除5个元素
console.log(arr)
console.log(e)
// 5.2  替换数组元素  数组.splice(index,howmany,item1,)
//所返回的数据是被删除的内容,需拿一个变量进行存储,直接打印原数组是直接打印被替换之后的数组
// 然后将替换的元素全部加入到被删除元素的原位置上,
// 添加元素的个数是自己后面item位置上所包含的数量,有几个添加几个
var f = arr.splice(1, 2, "a", "b", "c")
console.log(arr)
console.log(f)
// 5.3插入数组元素:splice(1,0,'a') 从下标为1开始,删除0个,字符a插入在下标为1的位置,其他的数组元素往后移动
//其返回值是一个空数组
// 添加元素的个数是自己后面item位置上所包含的数量,有几个添加几个
var g = arr.splice(1, 0, "aa", "bb");
console.log(g)
console.log(arr)

// 6.数组排序
// console.time()
arr = [1, 2, 1, 2, 4, 2, 5, 5, 5, 8, 4, 849, 76, 46, 6, 46];
// arr.sort(function(a,b){
//     return a-b;
// })
// console.log(arr)
// index = 0

var arr= [1,5,7,9]
// sort会改变原数组的顺序
arr.sort(function(a,b){
    return a-b      //返回负数,数组正序(从小到大)
    // return b-a    //返回正数,数组逆序(从大到小进行排序)
})
console.log(arr) 

注意:

  • 删除数组元素:splice(1,3) 从下标为1开始,删除3个数组元素
  • 替换数组元素:splice(1,2,'a','b') 从下标为1开始,删除2个数组元素,使用字符a,b代替删除的元素。
  • 插入数组元:splice(1,0,'a') 从下标为1开始,删除0个,字符a插入在下标为1 的位置,其他的数组元素往后移动
// 1、使用原生js进行数组内部排序
// 选择法
// console.time()
var arr = [8, 5, 3, 1, 7, 2, 9, 6] //定义一个数组    
for (var j = 0; j <= arr.length - 1; j++) { //定义一个for循环,循环次数为它的长度-1取索引值
    var minIndex = j; //定义一个变量表示索引用来遍历数组
    for (var i = j + 1; i <= arr.length - 1; i++) { //定义一个for循环,循环次数为它的长度-1,j+1变量赋值给i,此处循环的是arr[j]后面的所有元素
        if (arr[minIndex] > arr[i]) { //判断如果左边索引值的元素比右边索引值的元素大,则换位
            minIndex = i;
        }
    }
    var tmp = arr[minIndex] //定义一个变量用于交换索引值,先把上面得到的最小值赋给tmp
    arr[minIndex] = arr[j] //再把当时最小值跟第一位的值交换一下
    arr[j] = tmp
    //console.log(tmp) //输出tmp被赋予的最小值
    // console.log(arr[j]) //此时数组的第一位就是最小值,因为它的索引已经被跟之前的第一位值索引调换位置
}
console.log(arr) //打印输出,结果为:Array(8) [ 1, 2, 3, 5, 6, 7, 8, 9 ]
// console.timeEnd()


// 冒泡法
var arr = [8, 5, 3, 1, 7, 2, 9, 6,1] //定义一个无序数组
for (var j = 0; j <= arr.length - 1; j++) {
    // 定义一个变量j表示循环数组的长度 - 1 次
    for (var i = 0; i <= arr.length - 1; i++) { //定义一个变量i表示循环数组的长度-1次
        if (arr[i] > arr[i + 1]) { //判断索引为i的值比索引为i+1的值大,则进行换位
            var tmp = arr[i]; //定义一个变量tmp,给它赋值索引为i的元素
            arr[i] = arr[i + 1] //把索引为i的元素覆盖为索引为i+1的元素
            arr[i + 1] = tmp //再把tmp的值赋给索引为i+1的值
        }
    }
}
console.log(arr) //最后打印数组,结果:Array(8) [ 1, 2, 3, 5, 6, 7, 8, 9 ]

var arr = [0,1,2,4,3];
// 1.join():  将数组按特定标志组合成字符串
    // 不会对原数组产生任何的改变
var arr1 = arr.join("*")
console.log(arr1)
console.log(arr)
// 2.reverse() :  将数组倒序表示,并返回
    // 会对原数组产生影响
arr1 = arr.reverse()
console.log(arr1)
console.log(arr)
// 3.concat(): 将多个数组组合成一个新数组返回
// 不会对原数组产生任何的改变
var arr2 = arr1.concat(arr);
console.log(arr2)
console.log(arr1)
console.log(arr)
// 4.indexOf():在数组中查找指定的元素,找到返回对应的位置,找不到返回-1
// 不会对原数组产生任何的改变
a = arr.indexOf(1);
console.log(arr)
console.log(a)

// 2、数组递归
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
var a = arr.slice(1, 5);
console.log(arr)
// [
//     1, 2, 3, 4, 5,
//     6, 7, 8, 9
// ]
console.log(a) // [ 2, 3, 4, 5 ]
// every    针对数组元素做些判断,如果结果都为true  则返回的结果为true
arr = [true, false, true]
var b = arr.every(function (value, index) {
    console.log(value)
    console.log(index)
    return value === true
})
console.log(b)
// some :  针对数组元素做些判断,如果结果有一个为true  则返回的结果为       true
var c = arr.some(function (value, index) {
    console.log(value)
    console.log(index)
    return value === true
})
console.log(c)
// filter : 针对数组元素做些判断,满足条件的元素,会组成一个新的数组,并且返回
// 但不会改变原数组
arr = [1, 2, 3, 4, 5, 6]
var d = arr.filter(function (item, index) {
    return item > 3
})
console.log(arr)
console.log(d);
// map :    返回一个新的数组
// 不会改变原数组
// 当条件是判断的时候,返回的新数组是由true和false组成的,满足条件的返回true,不满足条件的返回false
var e = arr.map(function (item, index) {
    return item > 3
})
console.log(arr)
console.log(e);
// forEach :  没有返回值,就是一个简单的循环    参数分别为:遍历的数组内容;第对应的数组索引,数组本身。
arr.forEach(function (item, index) {
    console.log(item)
})

例题示例:

// 1、使用forEach,将数组里面的name属性重组到一个新数组里面
var newArr = [];
var arr = [
    {
        id:1,
        name:"周一",
    },
    {
        id:2,
        name:"周二",
    },
    {
        id:3,
        name:"周三",
    },
    {
        id:4,
        name:"周四",
    },
    {
        id:5,
        name:"周五",
    },
    {
        id:6,
        name:"周六",
    },{
        id:7,
        name:"周天",
    }
];
arr.forEach(function(item,value){
    // console.log(item.name)
    newArr.push(item.name)
})
console.log(newArr)
  •  九、DOM(文档对象模型)

    • 获取元素

// 通过getElementById获取的
//getElementById是通过标签的 id 名称来获取标签的
<body>
  <div id="box"></div>
  <script>
      var box = document.getElementById('box');
      console.log(box); // <div></div>
  </script>
</body>


// 通过getElementsByClassName获取
//getElementsByClassName是通过标签的 class 名称来获取标签的  
//所获取的是一个类数组,可以通过下标进行选择
<body>
  <div calss="box"></div>
  <script>
      var box = document.getElementsByClassName('box');
      console.log(box); // [<div></div>]
    console.log(box[0]); // <div></div>
  </script>
</body>

//获取到的是一组元素,是一个长的和数组一样的数据结构,但不是数组,是伪数组
// 这一组数据也是按照索引排列的,所以我们想要准确的拿到这个 div ,需要用索引来获取
//无论是几个,哪怕是一个,所获取到的也是一个类数组的形式


//通过getElementsByTagName获取
//getElementsByTagName是用标签的 标签名 来获取标签的            
//所获取的是一个类数组,可以通过下标进行选择
<body>
  <div></div>
  <script>
      var box = document.getElementsByTagName('div');
      console.log(box); // [<div></div>]
    console.log(box[0]); // <div></div>
  </script>
</body>
// 和 getElementsByClassName 一样,获取到的是一个长得像数组的元素
// 必须要用索引才能得到准确的 DOM 元素
//无论是几个,哪怕是一个,所获取到的也是一个类数组的形式


// 通过querySelector获取
//querySelector是按照选择器来获取元素的
//这个方法只能获取到一个元素,并且是页面中的第一个满足条件的元素
console.log(document.querySelector('div')) ;    // 获取页面中的第一个 div 元素 
console.log(document.querySelector('.box'));     // 获取页面中第一个有 box 类名的元素
console.log(document.querySelector('#box'));     // 获取页面中第一个 id 名为 box 的元素


// 通过querySelectorAll获取
//querySelectorAll是按照选择器的方式来获取元素
//这个方法能获取到所有满足条件的元素,组装成一个伪数组的形式返回
console.log(document.querySelectorAll('div')); // 获取页面中的所有的 div 元素 
console.log(docuemnt.querySelectorAll('.box')); // 获取页面中所有有 box 类名的元素
// 获取到的是一组数据,也是需要用索引来获取到准确的每一个DOM元素
  • 操作属性

    • 获取元素内部的HTML结构设置元素内容(innerHTML)

1.获取元素内部的HTML结构

<body>
  <div>
    <p>
      <span>hello</span>
    </p>
  </div>

  <script>
    var div = document.querySelector('div');
    console.log(div.innerHTML);
        /*
            
      <p>
        <span>hello</span>
      </p>
        
        */
  </script>
</body>


2.设置元素内容

<body>
  <div></div>

  <script>
    var div = document.querySelector('div');
       div.innerHTML = '<p>hello</p>';
       //设置完后,页面中的div元素里面就会嵌套一个 p 元素
  </script>
</body>
  •  只能获取和设置元素内部的文本内容,无法获取和设置HTML标签(innerText)

1.获取元素内部的文本内容

<body>
  <div>
    <p>
      <span>hello</span>
    </p>
  </div>

  <script>
    var div = document.querySelector('div');
    console.log(div.innerText);    //hello
  </script>
</body>



2.设置文本内容

<body>
  <div></div>

  <script>
    var div = document.querySelector('div');
    div.innerText = '<p>hello</p>';
  </script>
</body>

// 设置完毕以后,会把`<p>hello</p>`当做一个文本出现在div元素里面,而不会把 p 解析成标签
  •  获取或修改自定义属性

1.获取属性(包括自定义属性)   getAttribute

<body>
  <div a="100" class="box"></div>

  <script>
    var div = document.querySelector('div');
    console.log(div.getAttribute('a'));    //100
    console.log(div.getAttribute('class'));    //box
  </script>
</body>



2.设置属性(包括自定义属性) setAttribute

<body>
  <div></div>

  <script>
    var div = document.querySelector('div');
    div.setAttribute('a',100);
    div.setAttribute('class','box');
    console.log(div);    // <div a="100" class="box"></div>
  </script>
</body>



3.删除指定元素的指定属性    removeAttribute

<body>
  <div a="100" class="box"></div>

  <script>
    var div = document.querySelector('div');
    div.removeAttribute('class');
    console.log(div); // <div a="100"></div>
  </script>
</body>
  • 获取节点

  • 1.节点的分类

    • DOM的节点我们一般分为常用的三大类元素节点、文本节点、属性节点

    • 元素节点
      • 我们通过getElementBy...获取到的都是元素节点

    • 属性节点
      • 我们通过getAttribute获取到的就是元素的属性节点

    • 文本节点
      • 我们通过innerText获取到的就是元素的文本节点

  • 获取节点

    获取子节点
    -childNodes:获取某一个节点下 所有的子一级节点
    
    <body>
      <div>
        <p>hello</p>
      </div>
      
      <script>
        // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
          var oDiv = document.querySelsctor('div');
        
        console.log(oDiv.childNodes);
        /*
            NodeList(3) [text, p, text]
          0: text
          1: p
          2: text
          length: 3
          __proto__: NodeList
        */
      </script>
    </body>
    
    - 我们会发现,拿到以后是一个伪数组,里面有三个节点
    - 一个text:从<div>一直到<p>,中间有一个换行和一队空格,这个是第一个节点,是一个文本节点
    - 一个 p :这个 p 标签就是第二个节点,这个是一个元素节点
    - 一个 text:从 </p> 一直到 </div> 中间有一个换行和一堆空格,这个是第三个节点,是一个文本节点
    
    
    -获取父元素
    -parentNode:获取某一个节点的父节点
    
    <body>
      <ul>
        <li id="a">hello</li>
        <li id="b">world</li>
        <li id="c">!!!</li>
      </ul>
      
      <script>
        // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
          var oLi = document.querySelector('#b');
        
        console.log(oLi.parentNode); // <ul>...</ul>
      </script>
    </body>
    
    - 只获取一个节点,不再是伪数组
    - 获取的是当前这个 li 的父元素节点
    - 因为这个 li 的父亲就是 ul ,所以获取到的就是 ul ,是一个元素节点
    
    
    -获取其他节点
    
    // 获取第一个子元素或者是子节点     firstChild/firstElementChild
    // 获取第一个子元素   获取的是回车
    console.log(podiv.firstChild)
    // 获取第一个子节点     获取到的是标签
    console.log(podiv.firstElementChild)
    // 所以firstChild标准浏览器会获取到空行,firstElementChild是专门解决这个问题的,但是两者不能共用
    // 之所以不能同时使用,是因为浏览器不同的原因,所以说为了解决这个问题,只需要使用或者 ||  就可以
    // 例如  父元素.firstElementChild || 父元素.firstChild;
    var ul = document.getElementsByTagName("ul")[0]
    var ac = ul.children[2];
    // 获取第一个子节点或者是子元素,并将其背景颜色设置为粉色
    var one = ul.firstElementChild || ul.firstChild;
    one.style.background = "pink";
    // 获取最后一个子节点或者是子元素,并将其背景颜色设置为绿色
    var one = ul.lastElementChild || ul.lastChild;
    one.style.background = "green";
    // 依据第三个li获取第二个li,并将其背景颜色设置为红色
    var two = ac.previousElementSibling || ac.previousSibling;
    two.style.background = "red";
    // 依据第三个li获取第四个li,并将其背景颜色设置为蓝色
    var four = ac.nextElementSibling || ac.nextSibling;
    four.style.background = "blue";
    
    
    
    
    
    • 操作DOM节点

1.建立节点

var oul = document.getElementsByTagName("ul")[0]
// 创建标签节点     li   
var li = document.createElement("li")
// 创建一个文本节点
var text = document.createTextNode("这是文本节点");
var a = 1;
// 为标签节点添加内容 
li.innerHTML = "你好" + a
// 将新建的文本标签放到ul里面
oul.appendChild(text)
// 将新建的li标签放到ul里面
oul.appendChild(li)
console.log(oul.childNodes)



2.插入、克隆、添加、删除等 操作DOM节点

<body>
    <ul>
        <li class="fz">1</li>
        <li id="red">
            我是用来克隆的
            <span>我是span</span>
        </li>
    </ul>
    <script>
        // 先获取父元素  ul
        var oul = document.getElementsByTagName("ul")[0];
        // 创建一个新的li标签
        var li1 = document.createElement("li");
        // 并为此添加文本 为2
        li1.innerHTML = "2"
        // 将其插入到ul里面,成为第二个子标签
        oul.appendChild(li1)
        // 创建一个p标签
        var p1 = document.createElement("p")
        // 为p标签添加文本
        p1.innerHTML = "我来插队了"
        // 通过  父元素.insertBefore(newChild,refChild)方法  在refchild标签之前加入newChild节点
        // 注意:参数必须是节点,添加一个已经存在的节点,会发生物理位移
        // 例如 在li1标签前面添加一个p标签
        oul.insertBefore(p1, li1)
        // 删除当前节点
        li1.remove();
        // 删除父元素里面的某个子节点
        oul.removeChild(p1);
        // 替换节点,父元素.replaceChild(newChild,refChild)
        //  将后面的节点(refChild)替换成前面的节点(newChild)
        // 获取原有的第一个li节点
        var li = oul.getElementsByTagName("li")[0];
        var h1 = document.createElement("h1")
        h1.innerHTML = "我是用来替换的"
        oul.replaceChild(h1, li)
        // 克隆节点
        // 方法 节点.cloneNode(boolean)
        // 在括号里面可以填写true和false
        // 当填写true的时候代表的意思是      既有标签又有内容
        // 当填写false的时候代表的意思是    复制标签,没有内容
        /* 
            注意:
                1.使用克隆复制某个标签的时候,同时也会把改标签的classname和id名也复制过来
                2.也就意味着,使用该classname和id设置的css属性也同样会复制过来
                3.内部的标签也会克隆过来
        */
        var red = document.getElementById("red")
        var hTrue = red.cloneNode(true);
        var hFalse = red.cloneNode(false);
        console.log(hTrue) //<h1>我是用来替换的</h1>
        oul.appendChild(hTrue)
        console.log(hFalse) //<h1></h1>
        oul.appendChild(hFalse)
    </script>
</body>
  •  十、BOM

 浏览器对象模型 核心是 window  bom包含dom。

// 如何获取元素的可视宽,以及占位宽高

// 可视宽高 clientWidth clientHeight 元素宽度+padding
// 占位宽高 offsetWidth offsetHeight 元素宽高+padding+border

// client和offset的区别
// client的计算不包含border,offset包含border
window.onload = function () {
  var div = document.getElementsByTagName("div")[0]
  // client系列
  // 元素.clientWidth:获取元素的可视宽  (width+左右的padding)
  console.log(div.clientWidth)        //520
  // 元素.clientHeight:获取元素的可视高  (height+上下的padding)
  console.log(div.clientHeight)       //520
  // 元素.clientTop:上边框
  console.log(div.clientTop)      //10
  // 元素.clientLeft:左边框
  console.log(div.clientLeft)     //10
  // document.documentElement.clientWidth:获取屏幕的可视宽
  console.log(document.documentElement.clientWidth)
  // document.documentElement.clientHeight:获取屏幕的可视高
  console.log(document.documentElement.clientHeight)  
  // offset系列
  // 元素.offsetWidth :  获取元素的占位宽(width+padding+border)
  console.log(div.offsetWidth)        //540
  // 元素.offsetHeight :  获取元素的占位高(height+padding+border)
  console.log(div.offsetHeight)       //540
  // 元素.offsetTop: 当前元素的顶部,到定位父元素的距离,没有定位父元素,到body的距离
  console.log(div.offsetTop)      //8
  // 元素.offsetLeft: 当前元素的左边,到定位父元素的距离,没有定位父元素,到body的距离
  console.log(div.offsetLeft) //8

}
  • 十一、This 与 自定义属性

  • this 

this指向的是当前元素

代码中声明了一个全局函数,是属于浏览器窗口对象的,所以this表示的就是浏览器窗口对象window

function fn() {
    consolo.log(this);
}
fn()
//标签事件属性中的this指向window对象



// 如果将一个全局函数在一个标签属性中调用,如下

<button onclick="fn()">点我试试</button>
function fn() {
    console.log(this)
}
//事件属性函数中的this指向当前操作的标签



// 如果在标签对象的属性上声明了一个函数,此时这个函数属于标签属性,所以函数内部的this指向当前标签对象


<button id="btn">点我试试</button>
var btn = document.getElementById('btn');
btn.onclick = function() {
    console.log(this);
}
  •  自定义属性

// 自定义属性:自己定义
// 固有属性:系统提供的
var oDiv = document.getElementsByTagName("div");

console.log(oDiv[0].tag); //unfined  暂时获取不到直接写在标签上的自定义属性

//1.在js中添加自定义属性 标签.属性名
oDiv[0].tag = true;
console.log(oDiv[0].tag);
  •  十二、事件相关

  •  绑定事件

给元素添加事件,就是绑定事件(注册事件),注册事件分为传统注册方式,监听注册方式

<body>
    <button>传统注册方式</button>
    <button id="jianting">监听注册方式</button>
    <script>
        var btn = document.querySelector('button')
        var jianting = document.getElementById('jianting')
        // 传统注册方式只能进行冒泡,不能进行捕获;而监听注册方式可以冒泡也可以捕获        
        // 传统绑定方式只能绑定一次,如果多次绑定,则会进行覆盖,只保留该元素最后一次绑定的函数
        // 传统绑定事件的解绑方法,是通过元素.事件 = null;
        // 监听绑定事件的解绑事件的方法,是通过在事件的内部进行解绑的
        /* 
             监听注册事件的解绑:
                (1)将解绑事件写在函数里的任何位置,其注册事件只会执行一次;
                (2)将解绑事件写在函数外,那么注册的事件将无效。
                (3)对于监听注册方式的解绑,需要注意事件类型和监听函数必须是相同的,否则解绑无效。
            */
        btn.onclick = function () {
            alert("这是传统注册方式")
            // 绑定事件只发生一次,然后立刻解绑
            btn.onclick = null;
        }
        // 监听注册方式可以给一个元素进行多次绑定
        // 语法格式
        // 元素.addEventListener(type, listener, useCapture);
        // (1)type :必须,事件监听的类型,如 click 、 mouseover等;
        // (2) listener :必须,一个实现了 EventListener 接口的对象,或者是一个函数;
        // (3) useCapture :可选,表示是冒泡还是捕获。值为 true 表示捕获,否则表示冒泡 。
        jianting.addEventListener('click', function () {
            alert('这是监听注册方式')
        })
        /* jianting.addEventListener('click', function () {
            alert('这是第二次监听注册方式')
        }) */
        // 给第二次监听进行解绑
        // 1.先把里面的函数拿出来
        function fn(){
            alert("这是第二次监听注册方式")
            // 3.将解绑事件放到函数里面
            jianting.removeEventListener('click',fn)
        }
        // 2.将函数重新放到原来的事件里面
        jianting.addEventListener('click',fn)
    </script>
</body>
  • 事件流

         事件流包括三个阶段:事件 捕获阶段 (capture phase) 、处于 目标阶段 (target phase) 和 事件冒泡 阶段 (bubbling phase)

<script>
        window.onload = function(){
            // 冒泡事件,是从具体的到非具体事件的一个过程,通俗来说就是,从当前的,逐级向上
            // 获取内部元素
            /* var neibu = document.querySelector('.neibu')
            neibu.addEventListener('click',function(){
                console.log('内部')
            })
            // 获取外部元素
            var waibu = document.querySelector('.waibu')
            waibu.addEventListener('click',function(){
                console.log('外部')
            })
            // 获取body
            document.body.addEventListener('click',function(){
                console.log('body')
            })
            // 获取html
            document.documentElement.addEventListener('click',function(){
                console.log('html')
            })
            // 获取window
            document.addEventListener('click',function(){
                console.log('window')
            }) */

            // 捕获事件     事件捕获是从不明确对象向目标对象的捕获的过程。  通俗的来讲就是从最外层一直到具体的对象
            // 要想设置捕获事件,可以从只能使用事件监听注册方式,不能使用事件传统注册方式;或者是需要把监听注册方法的第三个参数设置为 true
            // 获取内部元素
            var neibu = document.querySelector('.neibu')
            neibu.addEventListener('click',function(){
                console.log('内部')
            },true)
            // 获取外部元素
            var waibu = document.querySelector('.waibu')
            waibu.addEventListener('click',function(){
                console.log('外部')
            },true)
            // 获取body
            document.body.addEventListener('click',function(){
                console.log('body')
            },true)
            // 获取html
            document.documentElement.addEventListener('click',function(){
                console.log('html')
            },true)
            // 获取window
            document.addEventListener('click',function(){
                console.log('window')
            },true)
        }   
    </script>
</head>
<body>
    <div class="waibu">
        <div class="neibu">
            内部
        </div>
    </div>
</body>
  •  十三、ajax

  •  定义

    • ajax 全名 javascript and XML(异步JavaScript和XML)
    • 前后台交互的能⼒ 也就是我们客户端给服务端发送消息的⼯具,以及接受响应的⼯
    • AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
    • AJAX 是与服务器交换数据并更新部分网页的技术,在不重新加载整个页面的情况下。
    • 是⼀个 默认异步执⾏机制的功能,AJAX分为同步(async = false)和异步(async = true)
  •  什么是同步请求(false)

 同步请求是指当前发出请求后,浏览器什么都不能做, 必须得等到请求完成返回数据之后,才会执行后续的代码, 相当于生活中的排队,必须等待前一个人完成自己的事物,后一个人才能接着办。 也就是说,当JS代码加载到当前AJAX的时候会把页面里所有的代码停止加载,页面处于一个假死状态, 当这个AJAX执行完毕后才会继续运行其他代码页面解除假死状态

  • 什么是异步请求(默认true,或者是不填) 

 默认异步:异步请求就当发出请求的同时,浏览器可以继续做任何事, Ajax发送请求并不会影响页面的加载与用户的操作,相当于是在两条线上,各走各的,互不影响。 一般默认值为true,异步。异步请求可以完全不影响用户的体验效果, 无论请求的时间长或者短,用户都在专心的操作页面的其他内容,并不会有等待的感觉。

// 1.创建一个ajax对象
    var ajax = new XMLHttpRequest()
    /* 
    2.配置链接信息
        XMLHttpRequest 对象属性描述(用于和服务器交换数据。)
        使用的是open方法
        open的语法结构
            xhr 对象中的 open ⽅法是来配置请求信息的
            第⼀个参数是本次请求的请求⽅式 get / post / put / ...
            第⼆个参数是本次请求的 url 
            第三个参数是本次请求是否异步,默认 true 表示异步,false 表示同步
            xhr.open('请求⽅式', '请求地址', 是否异步)

            例如:
                ajax对象.open('请求方式','请求地址','本次请求是否异步[不写或者是写true以及默认均是异步处理,false是同步处理]')

    */
    ajax.open('get', 'http://121.37.201.72:8082/system/film/getFilms', true);
    /* 
        3.发送请求
        通过使用send方法进行发送请求
            把配置好信息的 ajax 对象发送到服务端
    */
    ajax.send()
    /*
      这样我们就可以完成ajax的基本请求了,我们确实能把请求发送到服务端如果服务端正常的话,响应也能回到客户端 但是我们拿不到响应
      如果想要拿到响应,我们需要有两个前提条件
          1. 本次 HTTP 请求是成功的,也就是我们下面要说的 http 状态码为 200 ~ 299 ajax对象.status
          2. ajax 对象也有自己的状态码,用来表示本次 ajax 请求中各个阶段
      ajax的状态码    是用来表示一个 ajax 请求的全部过程中的某一个状态
              readyState === 0 : 表示未初始化完成,也就是 open 方法还没有执行 
              readyState === 1 : 表示配置信息已经完成,也就是执行完 open 之后 
              readyState === 2 : 表示 send 方法已经执行完成
              readyState === 3 : 表示正在解析响应内容
              readyState === 4 : 表示响应内容已经解析完毕,可以在客户端使用了
          
 */
    ajax.onreadystatechange = function () {
        // 每次 readyState 改变的时候都会触发该事件
        // 我们就在这里判断 readyState 的值是不是到 4
        // 并且 http 的状态码是不是 200 ~ 299
        if (ajax.readyState === 4 && ajax.status == 200) {
            // 这里表示验证通过
            // 我们就可以获取服务端给我们响应的内容了 接收到后端返回的JSON字符串
            // 将JSON字符串转换成json对象   JSON.parse()
            // console.log(JSON.parse(ajax.responseText).data.list);
            // 将JSON对象转换成json字符串       JSON.stringify()
            let dataList = JSON.parse(ajax.responseText).data.list;
            dataList.forEach(function(item,index){
                // console.log(item.filmTitle)
                // document.write(item.filmTitle) 
                document.body.innerHTML = item.movieReview
            })
        }
    }

  •  回调函数

  •  定义
    • 把函数当作一个参数传到另外一个函数中,当需要用这个函数是,再回调运行()这个函数.

    • 回调函数是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码。(作为参数传递到另外一个函数中,这个作为参数的函数就是回调函数)

    <script>
        function add(num1, num2, callback) {
            var sum = num1 + num2;
            callback(sum);
        }
 
        function print(num) {
            console.log(num);
        }
 
        add(1, 2, print); //3
    </script>
  • ajax的原生封装

function ajax(type,url,success,data){
    // type是请求方式,url是路径,success是回调函数(用来将ajax中获取到的返回值拿出来),data是传参时的参数
    // 1.创建ajax对象
    var xhr = new XMLHttpRequest();
    // 2.建立数据链接    xhr.open(type  请求方式,url  请求数据接口地址,true  是否异步)  
    xhr.open(type,url,true);
    // 3.发送数据请求  xhr.send()
    if(data){
        // 当data的有值得时候
        // 请求头的设置
        ajax.setRequestHeader('Content-Type', 'application/json')
        // 发送
        将自己的
        ajax.send(JSON.stringify(data));
    }else{
        ajax.send()
    }

    // 4.状态监听
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                console.log(xhr.response)
                // 将获取到的JSON字符串装换成对象
                var res = JSON.parse(xhr.response)
                success(res)
            }
        }
    }
}
  •  十四、ES6语法

  • 变量声明

    •  let

// let
// 使用let进行声明变量
// 特点

// 1.不能进行变量提升       
{   
   let a = 20;
   var b = 20
}
   console.log(a)      //not  difind
   console.log(b)     //20

   // 2.只能作用于块级作用域里面,在外面无法打印块级里面的值

   // 3.let不能重复赋值
   let a = 20;
   let a = 30         //这样 会报错
  • const

// 特点
// 只能声明一个常量,声明完之后不能在修改,在声明的时候就要进行初始化赋值
// 其他特点和let一样

const a = 200
a = 300    //这样就会报错,不能更改原来写的值
  • 解构赋值

// 解构赋值 只能确定数组长度或者是对象的内容才能使用
// 如果数据是从后端拿来,只能使用for或者是forEach
let [a,b,c] = [5,8,9]
console.log(a,b,c) // 5 8 9
let ab = {
    name:'123',
    sex: "321",
    num(){
       console.log("猜猜我是谁");
     }
 }

let{name,sex,num} = ab
console.log(name,sex)  //123 321
num()  // 猜猜我是谁

        
  •  元素展开

定义:元素展开    ...  针对于数组和对象的展开

  • 示例 
//    数组
// 用于多个数组进行组合
let a = [123,123,123]
let b = [456,456,456,...a]  //可以将其放到任何一个位置上
console.log(b);
console.log(...a);      //也可以进行打印时展开
    // 对象     只能作用于另外一个对象当中,而无法进行打印展开
let obj1 = {
  name:'123',
  sex:'456'
}
let obj2 = {
   num:50,
   ...obj1
}
console.log(obj2)
// console.log(...obj1);       会报错,无法进行展开打印
  • 箭头函数

基础用法

// 基础用法
const functionName(arg1,arg2,arg3){
	// 函数体
}

 如果函数体只包含一个语句,你可以省略大括号并且该语句的结果会被自动返回。

// 当函数体只包含一条语句时,简写方法
const functionName = (arg1, arg2) => arg1 + arg2;

如果只有一个参数,还可以省略圆括号:

// 当仅有一个参数时的写法
const functionName = arg => arg + 5;

 多参数和无参数时,不能省略小括号

// 传统匿名函数
(function (a, b) {
  return a + b + 100;
});

// 箭头函数(由于有多个参数,所以括号不能省略)
(a, b) => a + b + 100;

const a = 4;
const b = 2;

// 传统无参匿名函数
(function () {
  return a + b + 100;
});

// 无参箭头函数(由于无参数,所以括号不能省略)
() => a + b + 100;

注意:

 函数不是直接返回表达式时,不能省略大括号和return关键字。只有当函数直接返回表达式时,才可以省略大括号。如果函数体有额外的处理,则大括号是必需的,return 关键字也是必需的。箭头函数无法猜测函数体返回什么或何时返回。

// 传统匿名函数
(function (a, b) {
  const chuck = 42;
  return a + b + chuck;
});

// 箭头函数
(a, b) => {
  const chuck = 42;// 进行了额外处理,不是直接返回表达式的情况,所以大括号和return不能省略
  return a + b + chuck;
};
  •  Promise

定义: Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,它可以获取异步操作的消息。

作用: 

Promise的出现主要是解决地狱回调的问题,比如你需要结果需要请求很多个接口,这些接口的参数需要另外那个的接口返回的数据作为依赖,这样就需要我们一层嵌套一层,但是有了Promise 我们就无需嵌套,可以将嵌套结构,通过resolve和reject的调用,执行promise对象的then和catch方法,从而不再嵌套。

 常用方法:

  • then方法

/**
* then方法接受两个参数:

   resolve的回调函数:当状态变成resolve时会回调的函数;
   reject的回调函数:当状态变成reject时会回调的函数;

*
**/
const promise = new Promise((resolve, reject) => {

})

promise.then(res => {
 console.log("res:", res)
}, err => {
 console.log("err:", err)
})

  执行then,Promise的状态
    1、当then方法中的回调函数本身在执行的时候,那么它处于pending状态;
    2、当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;
    3、如果返回的结果是一个Promise呢?那么这个新Promise的状态会决定then返回Promise的状态;
    4、当then方法抛出一个异常时,那么它处于reject状态;

promise.then(res => {
  console.log("res1:", res)
  // 1.直接返回一个值
  return "then function fulfilled"
}).then(res => {
  console.log("res2:", res)
  // 2.返回Promise
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("new promise fulfilled")
    }, 2000);
  })
}).then(res => {
  console.log("res3:", res)
  // 3.抛出一个异常
  throw new Error("error message")
}).catch(err => {
  console.log("err:", err.message)
})
  •  catch()

.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。 用于捕获错误。

var a = 10;
let promise = new Promise(function(resolve,reject){
    // resolve  成功后调用
    // reject   失败后调用
    if(a == 10){
        resolve("成功");
    }else{
        reject("失败");
    }
})
// promise.then(success, fail)
promise.then(res => {
    console.log(res);
},err => {
    console.log(err);
})

// 捕获错误
promise.catch(err => {
    console.log(err);
})
  •  resolve与reject方法

  •  resolve

 有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。

1、参数是一个 Promise 实例

如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。


2、参数是一个thenable对象

thenable对象指的 是具有then方法的对象,比如下面这个对象。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。



3、参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello



4、不带有任何参数

Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

const p = Promise.resolve();

p.then(function () {
  // ...
});  // 此时 p 就是Promise对象
  • reject()

 Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。

   const p = Promise.reject('出错了');
   // 等同于
   const p = new Promise((resolve, reject) => reject('出错了'))
   
   p.then(null, function (s) {
     console.log(s)
   });
   // 出错了
// 生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。   




   const thenable = {
     then(resolve, reject) {
       reject('出错了');
     }
   };
   
   Promise.reject(thenable)
   .catch(e => {
     console.log(e === thenable)
   })
   // true
   // Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。
  • Promise.all()

all()方法的参数都是promise对象 

执行逻辑:

        Promise.all([p1,p2,p3])

        把promise打包,扔到一个数组里面,打包完还是一个promise对象

        如果是all方法,必须确保,所有的promise对象,都是resolve状态,都是成功的状态,否则就报错

let p1 = Promise.resolve("p1成功");

let p2 = Promise.resolve("p2成功");

let p3 = Promise.resolve("p3成功");

Promise.all([p1,p2,p3]).then(res => {
    console.log(res);   // 这里的res是一个有p1,p2,p3里面的resolve组成的数组
   let [res1,res2,res3] = res;
    console.log(res1,res2,res3);
});

// 如果p2是reject
let p1 = Promise.resolve("p1成功");

let p2 = Promise.reject("p2成功");

let p3 = Promise.resolve("p3成功");

Promise.all([p1,p2,p3]).then(res => {
    console.log(res);   // 这里的res是一个有p1,p2,p3里面的resolve组成的数组
   let [res1,res2,res3] = res;
    console.log(res1,res2,res3);
});
// 居然报错了
  •  Promise.race()

Promise.race([p1,p2,p3])

这个和all用法一样,唯一不同之处就是race方法只要最前面一个resolve就可以正常执行,如果排在前面的是reject就报错

let p1 = Promise.resolve("p1成功");

let p2 = Promise.reject("p2成功");

let p3 = Promise.resolve("p3成功");

Promise.race([p1,p2,p3]).then(res => {
    console.log(res);   // 这里的res是一个有p1里面的第一个resolve值
});

如果全部都是reject

let p1 = Promise.reject("p1成功");

let p2 = Promise.reject("p2成功");

let p3 = Promise.resolve("p3成功");

Promise.race([p1,p2,p3]).then(res => {
    console.log(res);   // 因为第一个是reject,所以报错
});

 示例

// 异步处理函数
function foo() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(20)
        }, 3000)
    })
}

// 封装超时函数
function timeoutPromise(delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('超时')
        }, delay)
    })
}


Promise.race([
    foo(),
    timeoutPromise(1000)
]).then(function (res) {
    console.log('res', res)
}, function (err) {
    console.log('err', err)
})
  • async与await

  •  async 的特点
    • await 只能放到async函数中使用
    • 相比generator 语义化更强
    • await后面可以是promise对象,也可以是数字,字符串,布尔值
    • async 函数返回的是一个promise对象
    • 只要await 语句后面的Promise的状态变成reject,那么整个async函数会中断执行
  • 注意事项 
    • await配合async使用
    • 如果await后面的语句出错,函数后面将中断执行
  • 解决报错
    • 使用 try { } catch (){}
    • 添加catch 捕获错误
    •  统一捕获错误
1、使用 try { } catch (){}
async function fn(){
    try{
        await Promise.reject('出错了')
    }catch(e){
        let a = await Promise.resolve("成功了");
        console.log(a);
    }
}




2、添加catch 捕获错误
async function fn(){
    await Promise.reject('出错了').catch(err=>{
        console.log(err);
    })
    let a = await Promise.resolve("成功了");
    console.log(a);
}



3、统一捕获错误
try {
    let f1 = await Promise.resolve('成功了');
    let f2 = await Promise.resolve('成功了');
    let f3 = await Promise.reject('出错了');
}catch(e){}



4、也可以用Promise.all()方法
async function show() {
    let p1 = await new Promise((res, rej) => {
        $.ajax({
            url: 'https://jsonplaceholder.typicode.com/todos/1',
            success: function (data) {
                console.log(data);
                res()
            },
            error: function (err) {
                rej()
            }
        })
    });

    let p2 = await new Promise((res, rej) => {
        $.ajax({
            url: 'https://jsonplaceholder.typicode.com/todos/2',
            success: function (data) {
                console.log(data);
                res()
            },
            error: function (err) {
                rej()
            }
        })
    });

}

let pp = show();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值