Be JS PUA

280 阅读13分钟

2022.10.4

一.JS的组成 :ECMAScript、DOM、BOM

ES是JS的规范
DOM(文档对象模型)是节点,例如DIV是一个元素节点,其中有不少子节点
BOM(浏览器对象模型)操作浏览器

二.JS的使用方法

1> 行内书写: on+事件类型
2> 内 嵌 式: <script></script>
3> 外 联 式: <script src=" "></script>

三.变量

var 赋值  var a = 0
给 xx一个值 以便后续调用xx里的值
变量的赋值 在创建的变量中存储一个值

四.变量命名

由字母(A-Z,a-z),数字(0-9),下划线(_),美元符号($)组成,如:usrAge,num01,__name
严格区分大小写。 var app; 和 var App; 是两个变量
不能以数字开头。
不能是关键字,保留字。例如:var,for,while
遵循驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstNam

五.输入输出语句

 console.log()在浏览器的控制台打印一些我们想要的东西 便于查看 用来给程序员看自己运行时的消息
 alert( );浏览器弹出警示框 主要用来显示消息给用户
 prompt(info); 浏览看弹出输入框,用户可以输入
 document.write() 在浏览器页面直接打印
 

六.初步了解预解析

 浏览器看到的
 
 var  a  = 'abc'
 var box = 123
 console.log(a)
 console.log(box)
 
 解析会先把 变量置顶
 var a
 var box
 console.log(a)     ---> undefined
 console.log(box)   ---> undefined
  a  ='abc'
 box = 123 
 console.log(a)     ---> abc
 console.log(box)   ---> 123
 

七.数据类型

 数据类型:基础数据类型(简单数据类型)和复制数据类型(引用数据类型)
 1,数字类型  --- number类型 整数 浮点数
 2,字符串类型--- (需要用引号包裹)string类型
 3,undefind类型--- 未定义
 4,布尔类型 --- Boolean 返回值true1)和false0) 非零即真
 5null类型 ---空/空对象 var a = null 定义a为空 null本身就是数据
 6object   ---对象类型
 

八.数据检测(其一)

 typeof() 将要检测的数据放入括号内
 typeof 空格 + 数据 
 补充:
 console.log(typeof null) ---> 此时打印出来的数据类型是object类型
 但null本身是null空对象类型
 使用另一种检测方法 
 console.log(object.prototype.tostring.call(null))--->null
 

九.数据类型的转换

1.转为数值类型

 1>Number
   var a = '100'
   console.log(typeof a)--->string
   
   var a = '100'
   console.log(typeof Number(a))
   字符串转时,纯数字转为对应的数字,空字符串和空白字符串转为0
                                   非空非纯数字符串转为NaN
   布尔值: true -->1 false-->0
   undefind --> NaN
   null-->0
2>parsenInt 用来将其他的类型转为整数
   console.log(parsenInt(1.9))--->1
   纯数字或数字开头 否则会NaN
3>parsenFloat 输出为浮点数
  console.log(parsenFloat(1.9))--->1.9
 
 js 隐式转换(- * /) 利用算术运算隐式转换为数值型 ‘12’-0
 
 // 1.parseInt()
var age =prompt('请输入您的年龄');
consolo.log(parseInt(age));  //数字型18
consolo.log(parseInt('3.14'));  //3取整
consolo.log(parseInt('3.94'));  //3,不会四舍五入
consolo.log(parseInt('120px'));  //120,会去掉单位

// 2.parseFloat()
console.log(parseFloat('3.14'));  //3.14
consolo.log(parseFloat('120px'));  //120,会去掉单位


// 3.利用Number(变量)
var str ='123';
console.log(Number(str));
console.log(Number('12'));   

// 4.利用了算术运算 - * /   隐式转换
console.log('12'-0);  // 12
console.log('123' - '120');  //3
console.log('123' * 1);  // 123

2.转字符串类型

1> + ' '  
  console.log( 100 + 300) --->400
  console.log( '100' + 300) --->100300
  当 + 两侧有一个字符串时则输出为字符串类型 a + ‘ ’  (字符串的拼接)
  
2>变量.tostring
  var num = 1; 
  alert(num.toString());
  number , Boolean 可调用 
  undefind , null不可调用 这两个转string可用 拼接或者强制转换
3> string(变量) 强制转换
  var num = 1; 
  alert(String(num));
  
  //1.把数字型转换为字符串型 toString()  变量.toString()
    var num = 10;
    var str = num.toString();
    console.log(str);

   //2.强制转换
    console.log(String(num));
    

3.转布尔类型

 Boolean(变量)
 console.log(Boolean(100)) --->true0即真
 代表空,否定的值会被转换为false,如 ’ ’ , 0, NaN , null , undefined
 其余的值都会被被转换为true
                                                 
                                               

2022.10.5

一.分支语句

1,if分支语句

// 条件成立执行代码,否则什么也不做
if (条件表达式) {
//条件成立执行的代码语句
 }
 

案例:进入网吧

//弹出一个输入框,要求用户输入年龄,如果年龄大于等于 18 岁,允许进网吧
 var a = prompt('请输入您的年龄:');
 if(a >= 18)
 {
  alert('您的年龄合法,欢迎来到老子网吧享受学习的乐趣!');
 }

2.if else语句

// 条件成立,执行if里面代码,否则执行else里面的代码
if(条件表达式)
{
//[如果]条件成立执行的代码
}
else
{
    //[否则]执行的代码
}

案例:判断闰年

接收用户输入的年份,如果是闰年就弹出闰年,否则弹出是平年

算法:能被4整除且不能整除100的为闰年(如2004年就是闰年,1901年不是闰年)或者能够被 400 整除的就是闰年

   var year = prompt('请输入年份');
   if (year % 4 == 0 && year % 100 !=0 || year % 400 ==0)
    {
   alert('这个年份是闰年');
    }
    else
    {
  alert('这个年份是平年');
    }
    

二.循环语句

1.switch语句

switch(表达式){
  case value1:
 //表达式等于 value1 时要执行的代码
 break;
  case value2:
 //表达式等于value2 时要执行的代码
 break;
  default:
 //表达式不等于任何一个value时要执行的代码    
}
 /**
     * while 循环
     *      基于某一个条件, 循环处理 某一段代码
     * 
     * while 语法: while (条件) {要循环执行的 代码}
    */

switch :开关 转换
case :小例子 选项
关键字 switch 后面括号内可以是表达式或值, 通常是一个变量
关键字 case , 后跟一个选项的表达式或值,后面跟一个冒号
switch 表达式的值会与结构中的 case 的值做比较
如果存在匹配全等(===) ,则与该 case 关联的代码块会被执行,并在遇到 break 时停止,整个 switch 语句代码执行结束

如果所有的 case 的值都和表达式的值不匹配,则执行 default 里的代码
执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句

2.三元表达式/三目运算符/问号冒号表达式

语法: 条件? 条件为真时执行:条件为假时执行

3.while循环

 var num = 1        --->初始化条件
 while (num <= 5){  --->条件判断,不符合时会结束循环
 console.log(1)     --->循环执行的代码
 num++              --->改变自身,不写会死循环
 }
 
    

4.do-while循环

do...while 循环
语法: do {要循环执行的代码} while (条件)
和 while 循环的 差异
while 首次执行就判断条件, 条件不符合不执行, 且 停止循环
do...while 首次就执行,不需要判断条件, 执行完毕再去判断条件 , 条件不符合时不执行,且停止循环

 var num = 10;
 while (num < 6) {   // 2. 条件判断, 不符合时结束循环
     console.log(1)  // 3. 循环执行的代码
     num++   // 4. 改变自身, 如果不写, 死循环
 }

var num = 0
do {
   console.log(1)
   num++
} while (num < 6)
/**
* var num = 10
* do {...} while (num < 6)
* 
*  首次执行
*          1. 直接执行 {...} 代码, 所以会打印 1, num++
*          2. 判断条件 num < 6 吗  此时 num 一定大于 6 ,所以条件为 false
* 

5.for循环语句

 for(初始化变量;条件表达式;操作表达式)
{
//循环体
}

案例

   for(var i = 1; i<=10; i++  )
            {
                console.log('娘子晚安哈');
            }
    // 用户输入次数
        var num = prompt('请输入次数:');
        for(var i = 1; i<= num ;i++)
            {
                console.log('娘子晚安哈');
            }
  

求1-100所以的整数和

    var sum = 0;
    for (var i = 1; i <= 100; i++) 
    {
        var sum = sum + i;
    }
        console.log(sum);
   

1000到2000是4的倍数不是100的倍数

    var num = 0 //加入计数器
    for(var i=1000;i<2000;i++ ){
          if(i % 4 == 0 && i % 100 !== 0 ){
             document.write(i + ' ') 
             num++ 
             if(num == 4){   //计时器4个一换行
               document.write('<br>')
               num = 0  //计时器清0
          }
      }      
    }

水仙花

   //100-1000的个 十 百 三次方相加 等于本数字
    for(i = 100;i <1000;i++ ){
    // 123
    var  baiw = parseInt(i/100)
    var  shiw = parseInt((i % 100)/10)
    var  gew  = parseInt(i % 10)
    var sum = baiw**3 +shiw**3 + gew**3
    if(sum == i ){
    console.log(sum+'水仙花');
    }
    }
    

补充:表示返回右侧的变量式值得x次方 ,x是右边的数字 a**3就是a得三次方

嵌套循环 外层循环执行一次 内层循环会完整的执行一次

九九乘法表

    for(var i=1; i<=9;i++){
        document.write('<br>')
       for(var j=1; j<=i;j++ ){
           var sum = i*j
           document.write(i+'*' + j + '=' + sum + ' &emsp;' + '&emsp;')
       }
    }
    

应用题苹果3元,鸭梨2元,桃子1元,共买100个,共计200元的方案

   for( var p = 0;p <= 66; p++ ){
        for (var y = 0; y <= 100; y++ ){
         for( var t = 0 ; t <= 200 ;t++){
            var gs = 100;  var qs = 200
            if(gs == p + y + t && qs == p*3 + y*2 + t*1){
            document.write('苹果' + p + '个' + '鸭梨' + y + '个' + '桃子' + t + '个' +          '<br>')
            } 
         }
        } 
    }

五行五列依次递减的@

      for (i = 0; i <= 4; i++){
              for( k = i; k <= 4; k++){
                 document.write('@'+' ');
              }
              document.write('<br>')
        }
        

四行四列依次递增的@

      for (i = 0; i < 4; i++){
              for( k = 0; k <= i; k++){
                 document.write('@'+' ');
              }
              document.write('<br>')
        }

打印五行五列的五角星

  var star = '';
  for(var j = 1;j<=5;j++)
    {
   for (var i = 1; i <= 5; i++)
    {
     star += '☆'
   }
  //每次满5个星星就加一次换行
  star +='\n'  
   }
  console.log(star);
  

6.流程控制语句

break 关键字的应用
continue 关键词的应用
共同点:都可以打断
不同点:
break 当满足一个条件时停止循环
continue 当满足一个条件时,停止本轮循环,后续循环继续执行

2022.10.6

一.函数

函数可以理解为一个盒子
函数可以帮助我们在项目中多个地方使用到的功能(代码段)抽离出来(拿到另一个 盒子中,这样可以不用重复书写)在需要的地方直接调用。
写一个函数
(1).定义函数
(2).调用函数

1.函数的定义

语法:function() --->关键字 表声明后面跟一段代码是函数 ()--->内部书 参数
{} ---> 书写函数 调用执行时的代码
两种定义函数方式
(1)赋值式定义(匿名函数)
var fn=function(){} --->fn为函数名
(2)声明式定义(具名函数)
function 函数名(){}

2.调用函数

语法:函数名()

3.声明式函数和赋值式函数

(1)书写不同
var fn=function(){}
function fn(){}
(2)打印时声明函数会带上函数名,赋值函数不会
(3)调用时有差异
声明式可以在函数定义前调用
赋值式不可以在函数顶以前调用

4.函数的参数

参数(形参合实参)
形参: function 函数名(形参,形参)

function fn1(a,b){} --->相当于函数内放入两个变量,他们的值由实参决定
调用:fn1(1,2) --->此时内容为实参,实参与形参一一对应 a为1 b为2

若实参少于形参,那前边形参对应接受值,没有实参对应的值为undefind
若形参数少于实参数,那么一一对应后,多余的实参无法获取

5.函数的返回值

function add(a,b){
 return a + b
} 
var sum = add(1,2)
console.log(sum) ---> 3

函数会默认返回值 我们可以不写return 函数会默认在代码最后一行写 return undefind

6.中断函数

return 具有中断功能 若不想中断函数 把return放在最后一行

7.函数的预解析

(1)函数的预解析可能会遇上同名变量的变量提升,直接以函数为主
(2)解析之后会把函数提升到当前作用域最顶层

二.作用域

1.作用域

变量使用区间,变量不是说声明在哪里都可以使用,有自己的使用范围

2.作用域分两种

(1)全局作用域::JS给提供了一个叫window的全局作用域,可以理解为script标签内的作用域就是全局作用域,全局变量都会被挂载在window对象上
(2)局部作用域:在JS中有且只有函数可创建局部作用域(函数作用域),在局部作用域内,声明的变量叫局部变量,局部变量不会被挂载到window对象上。

3.作用域链

(1)变量访问规则:变量访问全在当前作用域内查找,找到直接拿来用,若没有找到会去上层作用域查找,若持续上层找不到则会报错。
(2)变量赋值规则:会在当前作用域内查找,若找不到则一直上找,若还未找到会直接定义在全局作用域内并赋值。
(3)作用域链:在查找时会在当前作用域内查找。找到就用,找不到会去上层一直找到全局作用域。我们把向上一层一层的查找所构成的一个链条 叫做作用域链
补充:作用域链指挥向上查找,不会向下

4.递归函数

一个函数调用自身并设置了返回(归)称为递归函数

function fn(n){
 if(n == 1) reture 1  ---> return 叫归 
 n*fn(n-1)  --->不断 调用自身 叫递 
}

5.关于函数的一些案例

(1)形参和实参的使用

  fn(111,222,333)
console.log(fn.length);

function add(a,b){
return a*b
}
var sum = add (2,3)
console.log(sum);

(2)函数水仙花 使用

  function ll(a){
// 123
  var baiw = parseInt(a / 100)
  var shiw = parseInt( a % 100 /10)
  var gew =  a % 10
  var sum = baiw**3 + shiw **3 + gew**3
  if ( sum == a){
    return true
  } 
  else{
    return false
  }
}
 var su = ll( 153 )
 console.log(su);

(3)函数实现4的倍数且不是100的倍数

function ff(a,b){
for(i = a;i < b;i++){
   if(i % 4 == 0 && i % 100 !== 0 ){
         document.write(i + ' ');
         js = 0
         if( js == 4){
          document.write('<br>')
          js = 0
         }
   }
}
}
ff(2000,4000)

(4)函数 编写 几行几列

     function fn( a , b){
        for(i = 1;i <= a; i++){
             document.write('<br>')
            for(k = 1; k <= b; k++){
             document.write('*')
            }
       }
    }
     fn(5,5)
   

(5)函数实现 两数字 相加 且两个都为 number类型

     function ff( z , x ){
         if( typeof z !== 'number' || typeof x !== 'number'){
              console.log('z 或 x 其中至少有一个不是number类型');
              return false 
         }
         // console.log(z + x);
        
         return sum = z + x
        
     }
    var sum = ff(10,'20')
    console.log(sum);
 //    console.log(typeof(sum));

(6)函数判断是不是质数

 function fn(a){
     sum = 0 //如果sum变化代表 不是质数
     for ( i = 2 ;i < a; i++){
          if ( a % i == 0){
            sum += 5 
          } 
          if ( sum == 0){
             return true
          }
         else{
             return false
          }
        
     }
 }
 var aa = fn(11)
 console.log(aa);
 var aa1 = fn(12)
 console.log(aa1);
 

(7)两个数的最大公约数

function fn(a,b){
    if( a > b){
      for(var i = a; i >= 1 ; i-- ){
         if( a % i == 0 && b % i == 0){
             return i
         }
      }
    }
    else{
        for( var j = b; j >= 1 ; j-- ){
         if( b % j == 0 && a % j == 0){
             return j
         }
    }
}
          
}
var sun = fn(90,15)
console.log(sun);

(8)第一位是1 第二位是 1 第三位是前两位相加 递归

    function fn( n){
        if( n == 1 || n == 2){
           return 1
        }
        return fn(n-1) + fn(n -2)
    }
    var sum = fn(10)
    console.log(sum);
    

(9)计算3/2+4/3+...+ (n+1)/n

 var n = prompt('请输入一个数字')-0
    function fn(n){
        if(n == 2 ){
             return 3/2
        }
        return (n + 1)/n + fn(n-1)
    }
    var sum = fn(n)
    alert(sum)
    

(10)使用函数对一个四位数加密
加密规则:
1. 每一位上的数字 +5 然后使用 10的余数替代
2. 一三交换位置, 二四交换位置
举例:
输入 1234
1. 每一位上的数字 +5 ===> 6789
2. 使用 10 的余数代替 ===> 6789
3. 一三 二四 交换位置 ===> 8967
输入 5655
1. 每一位上的数字 +5 ===> 0100
2. 使用 10 的余数代替 ===> 0100
3. 一三 二四 交换位置 ===> 0001 (这里需要打印0001, 不能打印1)

       var r = 0,z = 0;
        // 2749
        // 7294
        // 9472
  function fn(a,b,c,d){
        a = (a + 5)%10;
	b = (b + 5)%10;
	c = (c + 5)%10;
	d = (d + 5)%10;
        //一三交换
	r = a;
	a = c;
	c = r;
        //二四交换
	z = b;
	b = d;
	d = z;
	console.log(a,b,c,d);
}
	fn(2,7,4,9);
            

2022.10.9

一.对象

对象是一种数据类型,复杂数据类型(引用数据类型)
函数---对象---数组--->引用数据类型

1.对象的创建两种方式

(1)字面量形式创建

 var obj ={}  //空对象
 var obj ={
  name:'qian',
  oa: 100
 } 
 //声明一个变量,内部值是一个对象,这个对象属性是是name 属性值是qian(多对象用逗号间隔)
//对象内部通常存储的以键值形式存储 例如:name:'hi'
//name --->自定义属性名(key)参考变量的命名规范,同时也接受数字开头,数字命名时数字key回跑最上面
//'hi'---->给对应属性名赋值(value)

(2)通过内置构造函数创建

 var obj =new Object()
 

二.如何操作对象(增删改查)

1.点语法

 var obj = {
      name:'zhao'
 }
console.log(obj.name)  --->zhao  查
obj.age = 666 ---> 增
delete obj.name --->删
obj.name = 'list '--->改

2.中括号语法(数组语法)

var obj = {
      name:'zhao'
 }
console.log(obj['name'])  --->zhao  查
obj.['age'] = 666 ---> 增
delete obj['name'] --->删
obj.['name'] = 'list '--->改

3.中括号语法与点语法的区别

(1)符合变量命名规范或规则 无差异
(2)不符合则有差异,例如数字或者特殊符号只能通过中括号语法
(3)一般点语法居多,数字,特殊符号,变量必须使用中括号语法

三.循环遍历对象

通过for...in循环拿到对象的每一个key

for(var key in 对象名){
   console.log(key)
   console.log(key,对象名[key]) ---> key 获取key ,对象名[key]获取value 不需引号
}

四.数组

存放一组数据的集合

1.创建数组的方法

(1)字面量

  var arr = [] //创建一个变量内部存储一个空数组
  var arr = [1,'2',ture,undefined]

(2)内置构造函数

  var arr = new Array()
  console.log(arr.lenght) ---> 0
  var arr = new Array(10)
  console.log(arr.lenght) ---> 10 只有构造函数的单数字是规定数组长度
  var arr = new Array(123)
  console.log(arr.lenght) ---> 3
  

2.索引

var arr = [1,2,3,4,5,6]
           0 1 2 3 4 5 --->索引(下标)
arr.lenght-1  --->数组的最后一项
console.log(arr[2]) --->3
console.log(arr[arr.lenght-1]) --->6

3.数组的排序

(1)冒泡排序法

var arr = [9, 6, 3, 1, 4, 7, 8, 2, 5];
console.log('原始数组: ', arr)
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - 1 - i; j++) {
    if (arr[j] > arr[j + 1]) {
        var temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
    }
  }
}

//数组累加
// var arr = [2,3,4,5,1]
// var sum = 0
// for (i = 0 ; i <=arr.length-1 ; i ++){
//      sum  +=  arr[i]
// }
// console.log(sum);



//数组中最大的值
// var arr = [2,3,5,6,1,4]
// var arr1 = [0]
// for(i= 0; i < arr.length ;i++ ){
//     if( arr[i] > arr1[0]){
//          arr1[0] = arr[i]
//     } 
// }
// console.log(arr1[0]);


//将数组第一位 第二位换位置
// var arr = [1,2,3]
// var temp = arr[0]
// arr[0] = arr[1]
// arr[1] = temp
// console.log(arr);

(2)选择排序法

 /**
     *  选择排序
     *      逻辑:   假设元素中数组最小的哪一项为 0
     *                  然后遍历数组, 找到数组中最小的哪一项的下标,
     *                  将其替换之前记录的索引
     *              然后将两个位置的数据对换
    */
    var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7]
    // 下标    0  1  2  3  4  5  6  7  8
    console.log('原始数组arr: ', arr)

    /**
     *              第?次循环      假设谁是最小值       循环开始        和谁交换
     *  k == 0          1               0               1               0
     *  k == 1          2               1               2               1
     *  k == 2          3               2               3               2
    */

    for (var k = 0; k < arr.length; k++) {
        // 1. 假设数组中第 0 个 是最小数字的索引
        var minIndex = k
        // 2. 遍历数组, 找到数组中最小的哪一项的下标, 将其替换之前记录的下标
        for (var i = k + 1; i < arr.length; i++) {
            if (arr[i] < arr[minIndex]) {
                minIndex = i
            }
        }
        // 3. 遍历结束, 找到最小的索引 将两个位置的数据 对换
        var temp = arr[k]
        arr[k] = arr[minIndex]
        arr[minIndex] = temp
    }
    console.log('处理完数据后的arr: ', arr)

4.数组的常用方法

(1)在数组中新插入一些数据

  * push<br>
    * 语法: `数组名.push(数据)`<br>
    * 作用: 向数组末尾添加数据<br>
    * 返回值: 追加数据后, 数组最新的长度<br>
     var arr = [1,2,3]
     var num = arr.push(100)
     console.log(arr) ---> [1,2,3,100]
     console.log(num) ---> 4
* unshift<br>
    * 语法: `数组名.unshift(数据)`<br>
    * 作用: 向数组开头添加数据<br>
    * 返回值: 添加数据后, 数组最新的长度<br>
    var arr = [1,2,3]
     var num = arr.unshift(100)
     console.log(arr) ---> [100,1,2,3]
     console.log(num) ---> 4
     

(2)在数组中删除一些数据

* pop<br>
    * 语法: `数组名.pop()`<br>
    * 作用: 删除数组最后一条数据<br>
    * 返回值: 被删除的数据<br>
     var arr = [1,2,3]
     var num = arr.pop()
     console.log(arr) ---> [1,2]
     console.log(num) ---> 3
     
* shift<br>
    * 语法: `数组名.shift()`<br>
    * 作用: 删除数组第一条数据<br>
    * 返回值: 被删除的数据<br>
     var arr = [1,2,3]
     var num = arr.shift()
     console.log(arr) ---> [2,3]
     console.log(num) ---> 1

(3)常用方法

    /**
     *  reverse; sort; splice; slice;
     * 
     *  1. reverse
     *      语法: 数组.reverse()
     *      作用: 反转数组
     *      返回值: 反转后的数组
     * 
     *  2. sort
     *      语法: 数组.sort()
     *          * 参数
     *              * 数组.sort(function (a, b) {return a - b})
     *              * 数组.sort(function (a, b) {return b - a})
     *      作用: 根据参数 对数组数据 进行排序(可以从大到小, 也可以反过来)
     *              * 不传参数: 会将数据转为字符串 一位一位的对比
     *              * 传参:
     *                  * 回调函数(其实就是传参的时候传入的那个函数)内 进行
     *                      a - b   那么会按照数字 大小 升序排序
     *                  * 回调函数内 b - a 那么会按照数组 大小 降序排序
     *      返回值: 排序后的数组
     * 
     *  3. splice (类似与 剪切)
     *      * 语法: 数组.splice(开始索引, 多少个)
     *              数组.splice(开始索引, 多少个, 插入数据1, 插入数据2, 插入数据3, ....)   
     *      * 作用: 截取数组部分内容, 并 选择性 插入内容
     *      * 返回值: 截取出来的部分内容组成的新数组
     * 
     *  4. slice (类似与 复制)
     *      * 语法: 数组.slice(开始索引, 结束索引)
     *          * 包前不包后 包括开始索引位置数据, 但不包括结束索引
     *          * 可以填写负整数, 表示倒数第几个
     *                  (其实就是 length + 负整数)
     *          * 如果不传递 第二个参数, 默认是 length(一直到最后)
     *          * 如果不传递 第一个参数, 默认是 0
     *      * 作用: 复制数组的部分内容
     *      * 返回值: 复制出来的部分内容组成的新数组
     * 
     *  splice 和 slice 的差异(一定是一道面试题, 并且高频)
     *      * 参数含义不同
     *      * splice 相当于 剪切, 所以会改变原数组
     *          slice 相当于 复制, 所以不会改变原数组
    */

    // var arr = [3, 2, 1, 4, 5, 100, 1000, 101]
    // // 下标:   0  1  2  3  4  5     6     7
    // console.log('原始数组: ', arr)

    // var arr1 = arr.reverse()
    // console.log(arr1) 
    
    // var arr1 = arr.sort()
    // console.log(arr1)

    // var arr1 = arr.sort(function (a, b) {return a - b})
    // console.log(arr1)

    // var arr1 = arr.sort(function (a, b) {return b - a})
    // console.log(arr1)

    // var arr1 = arr.splice(1, 3)
    // console.log(arr1)
    // var arr1 = arr.splice(1, 3, 'n', 'w', 'e', 'hhh')
    // console.log('截取后的 arr: ', arr)
    // console.log('arr1: ', arr1)

    var arr = [3, 2, 1, 4, 5, 100, 1000, 101]
    // 下标:   0  1  2  3  4  5     6     7
    console.log('原始数组: ', arr)

    // var arr1 = arr.slice(1, 3)
    // console.log('slice 处理后的数组arr: ', arr)
    // console.log(arr1)     // 2  1

    // var arr1 = arr.slice(1, -2)    // -1  相当于 length - 1    ---> 7
    // console.log(arr1)   // [2, 1, 4, 5, 100]

    // var arr1 = arr.slice(4) // 如果 不传递第二个参数, 默认从开始下标复制到数组最后
    // console.log(arr1)   // [5, 100, 1000, 101]

    var arr1 = arr.slice()
    console.log(arr1)   // [3~101]
    

(4).

 /**
     * concat; join; indexOf; lastIndexOf
     * 
     *  1. concat
     *      语法: 原始数组.concat(数组1, 数组2, ....)
     *      作用: 进行数据拼接, 把参数的所有数组或者数据, 
     *              拼接 到 原始数组
     *      返回值: 拼接好的数组
     * 
     *  2. join
     *      语法: 数组.join()
     *      作用: 使用连接符 把数组内的每一个数据拼接成一个字符串
     *              连接符 根据参数来, 不写(不传参数, 默认为 , )
     *      返回值: 连接好的数据(字符串)
     * 
     *  3. indexOf (O 是大写, 不是小写)
     *      语法: 数组.indexOf(要检查的数据);
     *              数组.indexOf(要检查的数据, 开始索引)
     *      作用: 从前到后 检查该数据 第一次 在该数组 内出现的 索引
     *      返回值: 如果找到了这个数据, 返回第一次出现的索引
     *              如果没找到 返回 -1
     * 
     *  4. lastIndexOf
     *      语法: 数组.lastIndexOf(要检查的数据);
     *              数组.lastIndexOf(要检查的数据, 开始索引)
     *      作用: 从后向前 去查找 数据 第一次在数组内 出现的索引位置
     *      返回值: 如果找到了数据, 返回第一次出现的索引
     *              如果没找到 返回 -1
    */
    var arr = [1, 2, 3, 3, 2, 1]
    // 下标     0  1  2  3  4  5
    console.log('原始arr数据: ', arr)

    // var arr1 = arr.concat([4, 5, 6], 666, 'a', true)
    // console.log('拼接完成后的数据: ', arr1)

    var arr1 = arr.join('\\')
    console.log(arr1)

    // var arr1 = arr.indexOf(2)
    // console.log(arr1)   // 1
    // var arr2 = arr.indexOf(200)
    // console.log(arr2)   // -1
    // var arr3 = arr.indexOf(2, 2)
    // console.log(arr3)   // 4

    // var arr1 = arr.lastIndexOf(2)
    // console.log(arr1)   // 4
    // var arr2 = arr.lastIndexOf(2, 1)
    // console.log(arr2)   // 1
    // var arr3 = arr.lastIndexOf(200)
    // console.log(arr3)   // -1

5.回调函数

+ 是一种函数的调用方式
    + 概念:
      => 把 函数A 当做参数传递到 函数B 内
      => 在 函数B 内利用形参的方式调用 函数A
      => 管 函数A 叫做 函数B 的回调函数(callback)
    + 使用:
      => 当你封装和 异步相关 的代码
      => 当你封装和 循环相关 的代码
      
      
      封装一段代码, 能帮我循环遍历一个数组
      参数1: 你需要遍历哪一个数组
      参数2: 你需要在遍历时做的事情
      
    // 我想封装一个函数, 帮我遍历数组, 并且能随着遍历做一些我想做的事情
    // function fn(你要遍历的数组, 你要做的事情) {
    //   for (你要遍历的数组) {
    //     你要做的事情()
    //   }
    // }

    // // 将来使用的时候
    // fn(数组, 事情)

function fn(arr, cb) {
  for (var i = 0; i < arr.length; i++) {
    cb(arr[i], i)
  }
}

// 将来使用的时候
fn([ 10, 20, 30, 40 ],function (item, index) { console.log(item, index) })

6.数组的遍历方法

 1. forEach()
    + 语法: 数组.forEach(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 遍历原始数组
    + 返回值: 没有 undefined

  2. filter()
    + 语法: 数组.filter(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 对原始数组内数据进行过滤
    + 返回值: 一个新的数组
      => 存放的是原始数组内满足条件的那些内容
    + 注意: 以 return 的形式书写 过滤条件
    
     var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
      var res = arr.filter(function (item) {
      return item > 300
    })
    console.log('返回值 : ', res)
    
    

  3. find()是一个不完整遍历
    + 语法: 数组.find(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 查找数组内满足条件的第一个
    + 返回值:
      => 如果数组内有满足条件的数据, 那么就是第一个满足条件的数据
      => 如果数组内没有满足条件的数据, 那么就是 undefined
    + 注意: 以 return 的形式书写 查找条件
    
    var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
    var res = arr.find(function (item) {
      return item % 10 === 0
    })
    console.log('返回值 : ', res)
    

  4. findIndex()
    + 数组.findIndex(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 查找数组内满足条件的第一个数据所在的索引位置
    + 返回值:
      => 如果数组内有满足条件的数据, 那么就是第一个满足条件的数据所在的索引位置
      => 如果数组内没有满足条件的数据, 那么就是 -1
    + 注意: 以 return 的形式书写 查找条件
    
     var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
       var res = arr.findIndex(function (item) {
      return item % 10 === 0
    })
    console.log(res) // 0
    
    

  5. map()
    + 数组.map(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 映射数组
      => 对原始数据进行操作, 返回一个操作以后的结果
    + 返回值: 是一个新数组
      => 新数组的长度和原始数组一模一样
      => 新数组内的数据是原始数组中每一个数据操作过的样子
    + 注意: 以 return 的形式书写 映射条件
    
    var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
      var res = arr.map(function (item) {
      return item * 10
    })
    console.log('返回值 : ', res)
    
    

  6. every()
    + 数组.every(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 判断数组内是否每一个都满足条件
    + 返回值: 一个布尔值
      => true: 说明数组内所有项都满足条件
      => false: 说明数组内至少有一个不满足条件
    + 注意: 以 return 的形式书写 判断条件
    
    var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
      var res = arr.every(function (item) {
      console.log(item)
      return item >= 100
    })
    console.log(res)
    
    

  7. some()
    + 数组.every(function (item, index, origin) {})
      => item: 数组的每一项
      => index: 数组的索引
      => origin: 原始数组
    + 作用: 判断数组内是否有某一个满足条件
    + 返回值: 一个布尔值
      => true: 说明数组内至少有一个满足条件
      => false: 说明数组内所有数据都不满足条件
    + 注意: 以 return 的形式书写 判断条件
    
    var arr = [ 100, 200, 300, 400, 500 ]
     console.log('原始数组 : ', arr)
     var res = arr.some(function (item) {
      return item > 500
    })
    console.log('返回值 : ', res)
    
    

  8. reduce()
    + 数组.reduce(函数, 初始值)
      => 函数: function (prev, item, index, origin) {}
        -> prev: 初始值或者上一次的计算结果
      => 初始值: 选填, 不写的时候, 默认使用数组的 [0] 位置数据当做初始值
    + 作用: 叠加
    + 返回值: 最终的叠加结果
    + 注意: 以 return 的形式书写 叠加表达式
    

/*
  reduce 循环遍历数组 [ 100, 200, 300, 400, 500 ]
    => 初始值 = [ 100, 200, 300, 400, 500 ].splice(0, 1)
    => 剩下的数组 = [ 200, 300, 400, 500 ]
    第一次: 因为你没有传递初始值, 把数组的 [0] 截取掉了, 当做初始值
      prev === 100
      item === 200
      return 300
    第二次:
      prev === 300
      item === 300
      return 600
    第三次:
      => prev === 600
      => item === 400
      => return 1000
    第四次:
      => prev === 1000
      => item === 500
      => return 1500
  循环结束
*/
var arr = [ 100, 200, 300, 400, 500 ]
console.log('原始数组 : ', arr)
 var res = arr.reduce(function (prev, item) {
   console.log('prev : ', prev)
   console.log('item : ', item)
   console.log('-----------------')
   return prev + item
 })
 console.log('返回值 : ', res)
 
 

8.数组塌陷

 /*
  数组塌陷(小人炸火车车厢,车厢向左前进,小人炸完一车厢会向右前进,炸不完全)
    + 塌陷: 当你删除数组中的数据, 从删除位置向后的数据, 索引会向前递进
    + 困扰: 当你删除以后, 还要继续遍历数组的时候, 会少东西
    + 解决:
      => 方案1: 不让数组塌陷, 倒着循环数组
      => 方案2: 退一步, i--
        -> 注意: 什么时候删除, 什么时候执行 i--
*/

var arr = [ 100, 200, 200, 200, 200, 200, 300, 400 ]
console.log('原始数组 : ', arr)

// 循环遍历数组, 每次删除一个
for (var i = 0; i < arr.length; i++) {
  arr.splice(i, 1)
}
console.log('删除之后 : ', arr)
解决塌陷方案1: 倒着循环数组
for (var i = arr.length - 1; i >= 0; i--) {
  arr.splice(i, 1)
}
console.log('删除之后 : ', arr)

// 解决塌陷方案2: 退一步
for (var i = 0; i < arr.length; i++) {
  if (arr[i] === 200) {
    arr.splice(i, 1)
    i--
  }
}
console.log('删除之后 : ', arr)

9.数组去重

  /*
  数组去重
    + 目的: 去除数组中的重复项
*/

// 准备一个原始数组
var arr = [ 1, 1, 1, 1, 1, 1, 4, 2, 3, 2, 1, 2, 3, 4, 2, 1, 2, 3, 4 ]
console.log('原始数组 : ', arr)
// 结果 [ 1, 4, 2, 3 ]

// 方案1:
// 思路:
//   1. 直接遍历
//   2. 拿到当前这个, 和当前以后的进行比较, 是否有一样的
//   3. 只要有一样的, 就干掉一个
for (var i = 0; i < arr.length; i++) {
  // 当前这个: arr[i]
  // 如何知道后面有没有了: indexOf(查找谁, 从哪一个索引开始)
  //   查找谁 ? arr[i]
  //   哪开始 ? i + 1
  // 如果后面找到了, 返回值就是找到的那个一样的数据的索引位置
  // 如果后面没找到, 返回值 -1
  // 只要不是 -1, 就得干掉一个
  var index = arr.indexOf(arr[i], i + 1)
  if (index !== -1) {
    arr.splice(index, 1)
    i--
  }
}
console.log('去重之后 : ', arr)


// 方案2:
// 思路:
//   1. 排序
arr.sort()
console.log('排序之后 : ', arr)
//   2. 遍历
//     判断, 当前这个 和 下一个, 只要一样, 随便删除一个
for (var i = 0; i < arr.length; i++) {
  // 2-1. 判断
  if (arr[i] === arr[i + 1]) {
    arr.splice(i, 1)
    i--
  }
}
console.log('去重之后 : ', arr)


  // 方案3:
// 思路:
//   1. 准备一个新数组
//   2. 把原始数组内每一项依次插入到新数里面
//      判断, 新数组内没有, 才插入
var newArr = []
for (var i = 0; i < arr.length; i++) {
  // 拿到 arr 内的每一个准备插入到 newArr 内
  if (newArr.indexOf(arr[i]) === -1) {
    newArr.push(arr[i])
  }
}
console.log('去重之后 : ', newArr)


// 方案4:
// 思路:
//   1. 创建一个对象
//      特点: 键名不能重复, 一样就是修改
//      特点: 可以用纯数字当做键名
var obj = {}
//   2. 遍历原始数组, 把每一个数据当做 obj 内的 键名 来使用
for (var i = 0; i < arr.length; i++) {
  var item = arr[i]
  // 把 item 当做 obj 内的键名来使用
  obj[item] = 'sb'
}
//   3. 把原始数组清空
arr.length = 0
// console.log('清空之后 : ', arr)
//   4. 遍历 obj, 把每一个 键名依次 插入到 arr 内
for (var k in obj) {
  // 随着循环, k 分别是 obj 内的每一个 键名, 是字符串类型
  arr.push(k - 0)
}
console.log('去重之后 : ', arr)


// 方案5:
// 步骤1: 利用 Set 数据结构
//   特点: 不允许存储重复数据
// 语法: var s = new Set([ 数据1, 数据2, 数据3, ... ])
// var s = new Set([ 100, 200, 100 ])
// console.log(s)
// var s = new Set(arr)
// console.log(s)

// 步骤2: 把 Set 数据结构还原成一个数组
// 方法1: Array.from(数据)
//       返回值: 把该数据还原成一个数组
// var r1 = Array.from(s)
// console.log(r1)
// // 方法2: 使用 ... 运算符   展开运算符
// var r2 = [ ...s ]    // [1, 4, 2, 3]
// console.log(r2)

// 书写
var r1 = Array.from( new Set(arr) )
var r2 = [ ...new Set(arr) ]
console.log(r1)
console.log(r2)

10.基本数据类型和复杂数据类型的区别

/*
  基本数据类型 和 复杂数据类型 的区别

  存储
    + 基本数据类型: 直接把值存储在 栈内存 里面
    + 复杂(地址/引用)数据类型: 把数据放在堆内存内存储, 把数据地址放在栈内存

  赋值
    + 基本数据类型的赋值: 就是直接值的复制, 赋值完毕, 两个变量没有关系
    + 复杂数据类型的赋值: 是进行地址的复制, 赋值完毕, 两个变量操作一个存储空间

  比较
    + 基本数据类型: 进行 值 的比较
    + 复杂数据类型: 进行 地址 的比较
*/

2022.10.12

一.认识字符串

认识字符串

  • 是一个 JS 内的基本数据类型 String

    包装数据类型(了解)
    + 在 JS 内, 字符串/布尔/数值 也是包装数据类型
    + 平时存储的时候, 是按照基本数据类型的形式存储
    + 当你使用该数据的时候, 会瞬间转换成 复杂数据类型 的形式让你使用
    + 等你使用完毕, 再次转换会基本数据类型的形式存储

    创建
    + 字面量方式
    => var str = 'hello'
    => var str = "hello"

      // 字面量方式
    var s1 = 'hello'
    var s2 = "hello"
    console.log(s1)
    console.log(s2)
    console.log(s2 === s1)
    
    
  • 内置构造函数方式

     => var str = new String('hello')
     // 内置构造函数
    var s3 = new String('hello')
    console.log(s3)
    console.log(s1 + 100)
    console.log(s2 + 100)
    console.log(s3 + 100)
    

    结构

    • 字符串内每一个内容也是按照 索引进行 排列
    • 索引: 从 0 开始, 依次 +1

二.模板字符串

模板字符串
    + 在 2015 年扩展了一种定义字符串的方式
    + 使用 反引号(``) 定义字符串
      => 管 反引号(``) 定义的字符串叫做 模板字符串

  特点:
    1. 可以换行书写
    2. 可以直接在字符串内解析变量, 当你需要解析变量的时候, 书写 ${ 变量 }
    

三.字符串的基本操作

  字符串的基本操作

  1. length 属性
    + 是一个只读的属性
    + 读: 字符串.length
      => 得到: 该字符串的长度, 也就是该字符串由多少个字符组成

  2. 索引属性
    + 是一个只读的属性
    + 读: 字符串[索引]
      => 得到:
        -> 如果字符串有该索引位置, 那么就是该索引位置的字符
        -> 如果字符串没有该索引位置, 那么就是 undefined

  3. 遍历
    + 使用循环遍历 字符串
    + 因为字符串也是按照 索引排列
    

四.字符串的常用方法

    /*字符串常用方法
    + 注意: 所有字符串方法, 都不会改变原始字符串, 以返回值形式给出结果

  1. charAt()
    + 语法: 字符串.charAt(索引)
    + 返回值:
      => 如果字符串内有该索引位置, 那么就是该索引位置的字符
      => 如果字符串内没有该索引位置, 那么就是 空字符串('')
      var str = 'hello world'
      console.log(str)
      var res = str.charAt(1)
      console.log(res)
      

  2. charCodeAt()
    + 语法: 字符串.charCodeAt(索引)
    + 返回值:
      => 如果字符串内有该索引位置, 那么就是该索引位置字符的 编码(unicode)
      => 如果字符串内没有该索引位置, 那么就是 NaN
      var res = str.charCodeAt(1)
        console.log(res)
        

  3. toUpperCase()
    + 语法: 字符串.toUpperCase()
    + 返回值: 原始字符串内所有字母转换成大写以后的结果
    var res = str.toUpperCase()
    console.log(res)


  4. toLowerCase()
    + 语法: 字符串.toLowerCase()
    + 返回值: 原始字符串内所有字母转换成小写以后的结果
    var res = str.toLowerCase()
    console.log(res)
    

  5. substr()
    + 语法: 字符串.substr(开始索引, 多少个)
    + 返回值: 截取出来的部分字符串
    // 表示 从 [2] 开始, 向后截取 7 个字符位置的内容
    var res = str.substr(2, 7)
    console.log(res)
    

  6. substring()
    + 语法: 字符串.substring(开始索引, 结束索引)
    + 返回值: 截取出来的部分字符串
    + 特点: 包前不包后
     // 表示从 [2] 截取到 [7], 包含 [2] 位置字符, 不包含 [7] 位置字符
    var res = str.substring(2, 7)
    console.log(res)


  7. slice()
    + 语法: 字符串.slice(开始索引, 结束索引)
    + 返回值: 截取出来的部分字符串
    + 特点: 包前不包后, 填写负整数
     // 表示从 [2] 截取到 [7], 包含 [2] 位置字符, 不包含 [7] 位置字符
    var res = str.slice(-9, -4) // -4 等价于 str.length + -4
    console.log(res)
    

  8. replace()
    + 语法: 字符串.replace(换下字符, 换上字符)
    + 作用: 在原始字符串内使用 换上字符 替换掉 换下字符
    + 注意: 只能替换出现的第一个
    + 返回值: 替换好的字符串
     // 把 str 字符串内的 **第一个** 'l' 字符替换成 '*'
    var res = str.replace('l', '*')
    console.log(res)
    

  9. split()
    + 语法: 字符串.split(分隔符)
    + 作用: 按照分隔符把字符串分开
    + 返回值: **一个数组**
      => 该数组内是把原始字符串按照分隔符分开的每一个部分
      var str = '2022-10-3'
    // 表示使用 '-' 把 str 分隔成 若干个 部分
    var res = str.split('-')
    // 如果填写的是 '', 那么按照索引逐位分开
    var res = str.split('')
    console.log(res)
    

  10. indexOf()
    + 语法: 字符串.indexOf(检测的字符串片段, 开始索引)
    + 返回值:
      => 如果原始字符串内有该字符串片段, 那么就是该字符串片段的开始索引
      => 如果原始字符串内没有该字符串片段, 那么就是 -1
      var res = str.indexOf('l', 5)
        console.log(res)
        

  11. lastIndexOf()
    + 语法: 字符串.lastIndexOf(检测的字符串片段, 开始索引)
    + 返回值:
      => 如果原始字符串内有该字符串片段, 那么就是该字符串片段的开始索引
      => 如果原始字符串内没有该字符串片段, 那么就是 -1
    + 注意: 从后向前检索
    var res = str.lastIndexOf('l', 8)
    console.log(res)
    

  12. concat()
    + 语法: 原始字符串.concat(字符串1, 字符串2, ...)
    + 返回值: 拼接好的字符串
     var res = str.concat('你好', '世界')
     var res = str + '你好' + '世界'
     console.log(res)
     

  13. trim()
    + 语法: 字符串.trim()
    + 返回值: 去除原始字符串内首尾空格后的结果
    

  14. trimStart() / trimLeft()
    + 语法:
      => 字符串.trimStart()
      => 字符串.trimLeft()
    + 返回值: 去除原始字符串内开始位置空格的结果

  15. trimEnd() / trimRight()
    + 语法:
      => 字符串.trimEnd()
      => 字符串.trimRight()
    + 返回值: 去除原始字符串内结束位置空格的结果
*/

五.查询字符串

JS 内, 对字符串进行了一些区分(人为)<br>
    + 普通字符串                'asdjhagsdjhk'
    + 数字字符串                '1234567890'
    + html格式字符串            '<span>asdasd</span>'
    + 查询字符串(querystring)   'key=value&key2=value2'
      => & 分开了多少条数据
      => = 分开了每一条数据的 键 和 值
  查询字符串
    + 如何把 对象数据结构 转换成 查询字符串
    + 如何把 查询字符串 转换成 对象数据结构
    
  //案例
  // 对象 转换成 查询字符串
     var obj = { name: 'Jack',age: 18 }
     var str =''
     for( var k in obj){
         str = str + `${k}=${obj[k]}&`
     }
     var s1 = str.slice(0,-1)
     console.log(s1);

 // 查询字符串 转换成 对象
     var str = 'name=Jack&age=18'
     var obj ={}
     str.split('&').forEach(function(item){  //这时输出的是数组形式 要获取数组中的每一项 需要遍历
        var  t = item.split('=')
        obj[t[0]] = t[1]
     })
     console.log(obj);
     

六.json字符串

/*
  JS 内, 对字符串进行了一些区分(人为)
    + 普通字符串                'asdjhagsdjhk'
    + 数字字符串                '1234567890'
    + html格式字符串            '<span>asdasd</span>'
    + 查询字符串(querystring)   'key=value&key2=value2'
      => & 分开了多少条数据
      => = 分开了每一条数据的 键 和 值
    + json格式字符串
      => '{ "name": "Jack", "age": 18 }'
      => '[ { "name": "Jack" }, { "name": "Jack" } ]'
      => 要求: key 和 value 必须被双引号包裹, 数字和布尔除外

  1. 把 JS的数据结构 转换成 json格式字符串
  2. 把 json格式字符串 转换成 JS的数据结构
*/

// 1. 把 JS的数据结构 转换成 json格式字符串
// 语法: JSON.stringify(JS的数据结构)
// 返回值: 一个合法的 json 格式字符串
var obj = { name: 'Jack', age: 18, gender: '男' }
console.log(obj)
console.log(typeof obj)
// 把 obj 转换成 json 格式字符串
var str = JSON.stringify(obj)
console.log(str)
console.log(typeof str)


// 2. 把 json格式字符串 转换成 JS的数据结构
// 语法: JSON.parse(json格式字符串)
var str = '{"name":"Jack","age":18,"gender":"男"}'
console.log(str)
console.log(typeof str)
// 把 str 当做 json 格式字符串转换成 JS 的数据结构
var obj = JSON.parse(str)
console.log(obj)
console.log(typeof obj)

七.字符串的案例 仔细看

//  1. 统计字符出现的次数
    var str = 'abcabc'
    var obj = {} //准备一个空对象 对象形式为 key:value  key存 字符串的字符 value存字符出现的次数
    for(i = 0 ; i < str.length;i++ ){  //遍历字符串中的每一个字符
       var t = str[i]  //字符串 依次存在 变量t中
       if( obj[t] !== undefined){  //若obj对象中有 此字符串 则 字符串的值 +1
          obj[t]++
       }
       else{
          obj[t] = 1  //若obj对象中没有 此字符串 则 对此字符串进行赋值 为1 并存储在对象obj中
       }
    }
    console.log(obj);
   
    
// 2. 反转字符串
    var str = 'abcdefg'
    // 方案一 循环(正反循环都可以) 存储在空字符串中
    var res =''
    // for( i = str.length-1 ;i >= 0;i--){
    //   res += str[i] 
    // }
    for(i = 0 ;i <str.length;i++ ){
       res = str[i] + res
    }
    console.log(res);

    //方案二 转为数组 反转 之后 进行拼接
    var str = 'abcdefg'
    var s2  = str.split('').reverse().join()
    console.log(s2); 
    
    
// 3. 替换敏感词
    // 方案1 利于查找 替换敏感词 同时把替换完的新字符串赋值给str
    var str = 'hdHHasHHgh' 
    var s = 'HH'
    while( str.indexOf(s) !== -1){
       str = str.replace(s,'**')
    }   
    console.log(str);

    // 方案2  利用split 把敏感词当作连接符 输出数组 之后利用join用**拼接在一起并输出字符串形式
    var str = 'hdHHasHHgh' 
    var s2 = str.split('HH').join('**')
    console.log(s2);

// 4. 批量替换敏感词
    var str = 'hdHHasHHgNNh'
    var list = [ 'HH', 'NN' ]
    list.forEach(function(item){       //forEach遍历list数组 
     str = str.split(item).join('**')  // 敏感词当连接符 之后 **连接 重新赋值给 str
    })
    console.log(str);
 
 

2022年10月13日

一.数学常用方法

/*
  数学常用方法
    + 一系列操作数字的方法

  1. random()
    + 语法: Math.random()
    + 返回值: 一个 0 ~ 1 之间的随机小数, 有可能包含 0 但是绝不可能包含 1

  2. round()
    + 语法: Math.round(数字)
    + 返回值: 对该数字进行四舍五入取整以后的结果

  3. ceil()
    + 语法: Math.ceil(数字)
    + 返回值: 对该数字进行向上取整以后的结果

  4. floor()
    + 语法: Math.floor(数字)
    + 返回值: 对该数字进行向下取整以后的结果

  5. abs()
    + 语法: Math.abs(数字)
    + 返回值: 该数字的绝对值

  6. pow()
    + 语法: Math.pow(底数, 指数)
    + 语法: Math.pow(谁, 的多少次方)
    + 返回值: 取幂结果

  7. sqrt()
    + 语法: Math.sqrt(数字)
    + 返回值: 该数字的算数平方根

  8. max()
    + 语法: Math.max(数字1, 数字2, 数字3, ...)
    + 返回值: 若干个数字内的最大值

  9. min()
    + 语法: Math.min(数字1, 数字2, 数字3, ...)
    + 返回值: 若干个数字内的最小值

  10. PI
    + 语法: Math.PI
    + 得到: 一个近似 π 的值
*/

二.保留小位数

 /*
  保留小数位
    + 语法: 数字.toFixed(你要保留多少位小数)
    + 返回值: 以 字符串 的形式返回保留好小数位的数字, 小数位不够的时候用 0 补齐
*/

三.转换进制

/*
  转换进制(了解)
    + 十进制数字转换成其他进制
      => 语法: 数字.toString(你要转换的进制数)
      => 返回值: 以字符串的形式返回转换好的进制数字
      => 参数范围: 2 ~ 36

    + 其他进制数字转换成十进制
      => 语法: parseInt(你要转换的数字, 你把这个数字当做几进制)
      => 返回值: 转换好的十进制数字, 数值类型
*/

// 1. 十进制数字转换成其他进制
var n = 8
var res = n.toString(16)
console.log(res)

// 2. 其他进制数字转换成十进制
var n = 100
// 把 n 这个数字当做一个 二进制 数字, 转换成十进制数字
var res = parseInt('ff', 16)
console.log(res)

四.范围内的随机整数

function randomNum(x, y) {
return Math.floor(Math.random() * (Math.abs(y - x) + 1)) + Math.min(x, y)
 }
 
 //案例(用到了上面的randomNum)
 // 封装函数, 获取一个随机颜色字符串 十六进制形式
 function randomColor() {
  // 1. 准备一个序列, 里面包含 0 1 2 3 4 5 6 7 8 9 a b c d e f
  // var list = '0123456789abcdef'

  // 2. 准备变量接受结果
  var color = '#'

  // 3. 重复生成
  for (var i = 0; i < 6; i++) {
    // 3-1. 生成一个随机索引
    var index = randomNum(0, 15)
    // 3-2. 把 index 当做索引来访问 list 内的某一个数据
    var s = index.toString(16)
    // 3-3. 组装
    color += s
  }

  return color
}

var res = randomColor()
console.log(res) // #xxxxxx


//案例
//生成一个 4为 验证码 且不重复 数字 加字母
var code = ''
for( i = 0; i < 4;i++){
   var s = randomNum(0,35).toString(36)
    code.indexOf(s) == -1 ? code += s : i--
}
console.log(code);

五.认识时间对象

/*
  认识时间对象
    + 是 JS 内的一个复杂数据类型, 叫做 Date
    + 专门用来存储时间相关信息的

  创建时间对象
    + 内置构造函数方式
    + 语法: var time = new Date()
    + 得到: 当前终端的时间

  创建指定之间节点的时间对象
    + 语法: var time new Date(参数)
    + 传递数字
      => 传递一个数字
        -> 该数字表示 毫秒数
        -> 表示从 格林威治时间 向后顺延的毫秒数
      => 传递多个数字
        -> 多个数字分别表示 年 月 日 时 分 秒 毫秒
        -> 注意: 月份位置 0 表示 1 月, 11 表示 12 月
        -> 注意: 所有时间信息位置都是可以自动进位的
    + 传递字符串
      => 'YYYY-MM-DD HH:mm:ss'
      => 'YYYY/MM/DD HH:mm:ss'
      => 注意: 年月日和时分秒之间有一个空格
      => 注意: 月份位置, 1 表示 1 月, 12 表示 12 月

  格林威治时间(计算机元年)
    + 1970110000 毫秒
*/

// 创建时间对象
// var time = new Date()
// console.log(time)
// console.log(typeof time)


// 创建指定之间节点的时间对象
// 1. 传递一个数字
// 表示创建的是从 格林威治时间 向后顺延 1000ms 的时间节点
// var time = new Date(86400000)
// console.log(time)

// 2. 传递多个数字
// var time = new Date(2005, 11, 31, 23, 59, 59, 999 + 1)
// console.log(time)

// 3. 传递字符串
// var time = new Date('2008-8-8 20:00:00')
// var time = new Date('2008/8/8 20:00:00')
// console.log(time)

六.时间对象的常用方法

  /*
  时间对象的常用方法
      获取一套              设置一套
    getFullYear()       setFullYear()
    getMonth()          setMonth()
    getDate()           setDate()
    getHours()          setHours()
    getMinutes()        setMinutes()
    getSeconds()        setSeconds()
    getMilliseconds()   setMilliseconds()
    getDay()            -
    getTime()           setTime()
*/

/*
  获取一套
*/

// var time = new Date()
// console.log(time)

// 1. getFullYear()
// 语法: 时间对象.getFullYear()
// 返回值: 该时间对象内的 年份信息
// var year = time.getFullYear()
// console.log(year)

// 2. getMonth()
// 语法: 时间对象.getMonth()
// 返回值: 该时间对象内的 月份信息
// 注意: 0 表示 1 月, 11 表示 12 月
// var month = time.getMonth()
// console.log(month)

// 3. getDate()
// 语法: 时间对象.getDate()
// 返回值: 该时间对象内的 日期信息
// var date = time.getDate()
// console.log(date)

// 4. getHours()
// 语法: 时间对象.getHours()
// 返回值: 该时间对象内的 小时信息
// var hours = time.getHours()
// console.log(hours)

// 5. getMinutes()
// 语法: 时间对象.getMinutes()
// 返回值: 该时间对象内的 分钟信息
// var minutes = time.getMinutes()
// console.log(minutes)

// 6. getSeconds()
// 语法: 时间对象.getSeconds()
// 返回值: 该时间对象内的 秒钟信息
// var seconds = time.getSeconds()
// console.log(seconds)

// 7. getMilliseconds()
// 语法: 时间对象.getMilliseconds()
// 返回值: 该时间对象内的 毫秒信息
// var ms = time.getMilliseconds()
// console.log(ms)

// 8. getDay()
// 语法: 时间对象.getDay()
// 返回值: 该时间对象内的 星期信息
// 注意: 0 表示 周日, 1 ~ 6 表示 周一 ~ 周六
// var week = time.getDay()
// console.log(week)

// 9. getTime()
// 语法: 时间对象.getTime()
// 返回值: 该时间对象内的 时间戳 信息
// 时间戳: 从 格林威治时间 到 该时间节点 的毫秒数
// var t = time.getTime()
// console.log(t)


/*
  设置一套
*/

// var time = new Date()
// console.log(time)

// 1. setFullYear()
// 语法: 时间对象.setFullYear(年份数字)
// 设置该时间对象内的年份信息
// time.setFullYear(2008)
// console.log(time)

// 2. setMonth()
// 语法: 时间对象.setMonth(月份数字)
// 注意: 0 表示 1 月, 11 表示 12 月
// 设置该时间对象内的月份信息
// time.setMonth(6)
// console.log(time)

// 3. setDate()
// 语法: 时间对象.setDate(日期信息)
// 设置该时间对象内的日期信息
// time.setDate(22)
// console.log(time)

// 4. setHours()
// 语法: 时间对象.setHours(小时数字)
// 设置该时间对象内的小时信息
// time.setHours(23)
// console.log(time)

// 5. setMinutes()
// 语法: 时间对象.setMinutes(分钟数字)
// 设置该时间对象内的分钟信息
// time.setMinutes(35)
// console.log(time)

// 6. setSeconds()
// 语法: 时间对象.setSeconds(秒钟数字)
// 设置该时间对象内的秒钟信息
// time.setSeconds(55)
// console.log(time)

// 7. setMilliseconds()
// 语法: 时间对象.setMilliseconds(毫秒数字)
// 设置该时间对象内的毫秒信息
// time.setMilliseconds(789)
// console.log(time.getMilliseconds())

// 8. setTime()
// 语法: 时间对象.setTime(时间戳信息)
// 直接使用时间戳来定位时间节点
// time.setTime(5000)
// console.log(time)

七.获取时间差

/*
  获取时间差
    + 最终目的: 封装函数, 获取两个时间节点之间的时间差
*/

// 问题1: 是否需要参数 ?
//   需要两个参数, 分别是 两个时间节点
// 问题2: 是否需要返回值 ?
//   需要一个返回值
//     需要一个能包含四个信息的返回值, 四个信息分别是 天 小时 分钟 秒钟
//   要么返回一个数组: [ 1, 2, 3, 4 ]
//   要么返回一个对象: { day: xxx, hours: xxx, minutes: xxx, seconds: xxx }
function diffTime(start, end) {
  // 1. 计算出相差的毫秒数
  // 结束时间节点的时间戳 - 开始时间节点的时间戳
  // 顺便换算成秒
  var sub = Math.ceil((end.getTime() - start.getTime()) / 1000)
  // console.log(sub)


  // 2. 换算
  // 2-1. 换算天
  var day = parseInt(sub / (60 * 60 * 24))
  // console.log(day)
  // 2-2. 换算小时
  var hours = parseInt(sub % (60 * 60 * 24) / (60 * 60))
  // console.log(hours)
  // 2-3. 换算分钟
  var minutes = parseInt(sub % (60 * 60) / 60)
  // console.log(minutes)
  // 2-4. 换算秒钟
  var seconds = sub % 60
  // console.log(seconds)

  // 3. 组装一个对象
  var obj = {
    day: day,
    hours: hours,
    minutes: minutes,
    seconds: seconds
  }

  // 4. 返回这个对象
  return obj
}


// 将来我们使用的时候
var t1 = new Date()
var t2 = new Date('2022-12-31 23:59:59')
var res = diffTime(t1, t2)
document.write(`
  <div>
    距离过年还有 : <br>
    <span>${ res.day }${ res.hours }${ res.minutes }${ res.seconds } 秒</span>
  </div>
`)

总结:
// 时间差
function diffTime(start, end) {
var sub = Math.ceil((end.getTime() - start.getTime()) / 1000)
return {
day: parseInt(sub / (60 * 60 * 24)),
hours: parseInt(sub % (60 * 60 * 24) / (60 * 60)),
minutes: parseInt(sub % (60 * 60) / 60),
seconds: sub % 60
  }
}

2022.10.14

一.定時器

 /*
  定时器
    + 浏览器提供的一个 JS 内异步执行代码的机制
    + 异步:
      => 非异步(同步): JS 执行代码的基本规则
        -> 从上到下从左到右依次执行代码
        -> 上面一行代码没有执行完毕, 下面一行代码等待
      => 异步: 当 JS 代码在执行过程中遇到异步代码的时候
        -> 不会执行该异步内容, 而是把该异步内容放在 队列 内等待
        -> 继续向下执行同步代码
        -> 等待所有同步代码执行完毕
        -> 再来队列内执行异步代码

  开始定时器
    1. 延时定时器
      => 语法: setTimeout(函数, 数字)
      => 作用: 在指定时间以后, 执行一遍函数
      => 函数: 在一段时间以后执行的代码
      => 数字: 单位是毫秒, 表示在多少时间以后

    2. 间隔定时器
      => 语法: setInterval(函数, 数字)
      => 作用: 每间隔一段时间, 执行一遍函数
      => 函数: 需要执行的代码
      => 数字: 单位是毫秒, 表示间隔多少时间

  定时器的返回值
    + 不区分定时器种类
    + 返回值就是一个数字, 表示你是页面上的第几个定时器
    + 作用: 用来关闭定时器使用的

  关闭定时器
    + 不区分定时器种类, 只要给出的定时器返回值是对的, 就可以关闭指定定时器
    + 语法:
      => clearTimeout(定时器返回值)
      => clearInterval(定时器返回值)
*/

案例

  /*
  案例 - 倒计时

  分析:
    + 每间隔 1000ms 获取一次 当前时间 和 目标时间 之间的时间差
    + 把时间差渲染页面页面的指定位置
    + 在这个过程中:
      => 每间隔 1000ms 是否需要获取一次当前时间
      => 每间隔 1000ms 是否需要获取一次目标时间
*/

// 获取目标时间
var target = new Date('2022-10-14 18:00:00')

// 每间隔 1000ms 执行一次代码
var timer = setInterval(function () {

  // 获取当前时间
  var current = new Date()

  // 获取当前时间和目标时间的时间差
  var res = diffTime(current, target)

  // 组装一个内容插入到页面上
  var str = `距离出去浪 还有: ${ res.day }${ res.hours } 小时 ${ res.minutes } 分钟 ${ res.seconds } 秒`

  // 把 str 输出在页面上
  // 语法: 元素.innerText = 值
  box.innerText = str

  // 判断
  if (res.day === 0 && res.hours === 0 && res.minutes === 0 && res.seconds === 0) {
    // 关闭定时器
    clearInterval(timer)
  }

}, 1000)

案例

   <button id = 'bu'>点击获取验证码</button>
  //编写一个倒计时 的点击获取验证码 
    var f = true // 设置一个开关 倒计时的时候 点击无效
    bu.onclick = function () {
        if (f ==  false) return 
        f =  false
        bu.innerText = `再次获取验证码5s`
        var count = 5

        var timer = setInterval(function(){
            count--
            bu.innerText = `再次获取验证码${count}s`
            // console.log(count);  
            if (count <= 0) {
                clearInterval(timer)
                bu.innerText =`点击获取验证码`
                f = true
            }     
        },1000)
     }

二.認識BOM

1. 认识 BOM

  • Browser Object Model 浏览器对象模型
  • 私人: 一整套操作 浏览器相关内容 的属性和方法
  • 特点:
    => 由浏览器提供的 属性和方法
    => 在不同的浏览器内表现形式不一样
    => 在不同浏览器的兼容情况不一样
  • 语法: 基本上都是 window.xxx, 在书写的时候可以省略 window. 不写
    => 例子: 弹出层
    => 标准语法: window.alert()
    => 书写: alert()
  • 操作部分:
    => 弹出层
    => 历史记录
    => 地址栏
    => 标签页
    => 滚动条
    => ...

2.浏览器的可视窗口尺寸

  • 语法:
    => 宽度: window.innerWidth
    => 高度: window.innerHeight
    • 注意: 获取到的尺寸是包含滚动条在内的尺寸

3.浏览器的弹出层

   1. 提示框
    + 语法: window.alert('提示文本')
    + 表现: 一段提示文本 + 确定按钮
    + 返回值: undefined

  2. 询问框
    + 语法: window.confirm('提示文本')
    + 表现: 在 提示框的基础上 + 取消按钮
    + 返回值: 一个布尔值
      => 如果用户点击的是确定按钮, 返回 true
      => 如果用户点击的是取消按钮, 返回 false

  3. 输入框
    + 语法: window.prompt('提示文本')
    + 表现: 在 输入框的基础上 + 文本框
    + 返回值:
      => 如果用户点击的是取消按钮, 那么就是 null
      => 如果用户点击的是确定按钮, 那么就是 文本框内的内容(如果没有输入就是 空字符串)
        -> 注意: 拿到的值是一个字符串类型, 哪怕输入的是数字, 也是字符串类型
        

4.浏览器的常见事件

 /*
  浏览器的常见事件
    + 依赖浏览器的行为而触发的事件

  1. load
    + 语法: window.onload = function () {}
    + 时机: 当前页面所有资源( html, css, js, 图片, 视音频, 等 )加载完毕后触发
    + 常用:
      => 当你在 body 内书写 js 代码的时候, 并且操作了页面元素的时候

  2. resize
    + 语法: window.onresize = function () {}
    + 时机: 当前页面可视窗口尺寸改变的时候触发(不管横向还是纵向, 只要改变就会触发, 一直改变一直触发)
    + 常用: 一般用来捕获横屏

  3. scroll
    + 语法: window.onscroll = function () {}
    + 时机: 浏览器滚动条滚动的时候触发(不管横向还是纵向, 只要改变就会触发, 一直改变一直触发)
*/

5.浏览器卷去的尺寸(滚动条定位)

/*
  浏览器卷去的尺寸(滚动条定位)

  卷去的高度
    + 语法:
      => document.documentElement.scrollTop
        -> 当前页面有 DOCTYPE 标签的时候能获取到尺寸
      => document.body.scrollTop
        -> 当前页面没有 DOCTYPE 标签的时候能获取到尺寸
    + 兼容:
      => var 自己定义一个变量 = document.documentElement.scrollTop || document.body.scrollTop

  卷去的宽度
    + 语法:
      => document.documentElement.scrollLeft
        -> 当前页面有 DOCTYPE 标签的时候能获取到尺寸
      => document.body.scrollLeft
        -> 当前页面没有 DOCTYPE 标签的时候能获取到尺寸
    + 兼容
      => var 自己定义一个变量 = document.documentElement.scrollLeft || document.body.scrollLeft
*/

6.浏览器滚动到

/*
  浏览器滚动到
    + 定位浏览器卷去的尺寸
    + 语法: window.scrollTo(参数)

  参数方式1: 传递数字
    + window.scrollTo(x, y)
      => x: 横向滚动条位置
      => y: 纵向滚动条位置
    + 注意: 必须传递两个参数, 一个会报错
    + 注意: 只能进行瞬间定位, 不能平滑滚动

  参数方式2: 传递对象
    + window.scrollTo({ left: xxx, top: yyy })
    + 注意: 可以只书写一个方向
    + 注意: 默认是瞬间定位, 如果需要平滑滚动, 设置对象内第三个成员 behavior: 'smooth'
*/

7.浏览器的标签页

 /*
  浏览器的标签页

  1. 打开新的标签页
    + 语法: window.open('地址')

  2. 关闭当前标签页
    + 语法: window.close()
*/

8.浏览器的地址栏

/*
  浏览器的地址栏
    + 在 window 下有一个成员叫做 location, 是一个对象, 记录的就是和地址栏相关的信息


  href 属性
    + 是一个读写的属性
    + 读: window.location.href
      => 得到: 该地址栏完整地址
    + 写: window.location.href = '地址'
      => 作用: 修改当前地址栏地址, 跳转页面

  reload 方法
    + 语法: window.location.reload()
    + 作用: 重新加载当前页面(就是刷新)

  扩展: 浏览器的地址栏
    + https://www.xhl.com:443/a/b/c/index.html?a=100&b=200#abc
      => http(s)                传输协议
      => www.xhl.com            域名(为了找到网络世界内的某一个电脑)
      => 443                    端口号(0 ~ 65535)
      => /a/b/c/index.html      地址(为了找到指定的文件)
      => ?a=100&b=200           查询字符串(queryString) 不影响页面的打开, 给当前页面的一些信息
      => #abc                   哈希(hash) 进行当前页面的网页定位
*/

9.浏览器的历史记录

/*
  浏览器的历史记录
    + 在 window 下有一个成员叫做 history, 是一个对象, 里面记录的都是历史记录相关的操作信息

  1. 回退
    + 语法: window.history.back()
    + 作用: 回退到上一条历史记录, 等价于 ← 按钮

  2. 前进
    + 语法: window.history.forward()
    + 作用: 前进到下一条历史记录, 等价于 → 按钮

  3. 跳转
    + 语法: window.history.go(参数)
      => 正整数: 前进
      => 0: 刷新
      => 负整数: 回退
*/

10.浏览器的本地存储 - storage

/*
  浏览器的本地存储 - storage
    + storage: 仓库
    + storage 在浏览器分成两种
      => localStorage       永久存储
      => sessionStorage     会话存储(关闭浏览器页面就消失了)
      

  特点:
    1. 不管你存储的是什么内容, 都会变成字符串
    2. 只能存储字符串类型数据
    3. 存储大小: 20MB 左右
    4. 按照域名存储: 哪一个域名存储的, 哪一个域名使用(本地文件使用一个 file://)
*/

/*
  localStorage

  设置: window.localStorage.setItem(key, value)
  获取: window.localStorage.getItem(key)
  删除: window.localStorage.removeItem(key)
  清除: window.localStorage.clear()
*/
/*
  sessionStorage

  设置: window.sessionStorage.setItem(key, value)
  获取: window.sessionStorage.getItem(key)
  删除: window.sessionStorage.removeItem(key)
  清除: window.sessionStorage.clear()
*/

11.浏览器的本地存储 - cookie

   /*
  浏览器的本地存储 - cookie


  特点:
    1. 按照域名存储
      + 哪一个域名存储, 哪一个域名使用
      + 必须把页面在服务器打开才能使用
    2. 存储大小
      + 4KB 左右
    3. 存储格式
      + 只能是 'key=value; key2=value2; key3=value3'
    4. 存储时效性
      + 默认是 会话级别时效(关闭浏览器就会消失)
      + 可以手动设置过期时间
    5. 操作性
      + 前端可以操作(JS)
      + 后端可以操作(任何一个语言)
    6. 请求自动跟随
      + 只要 cookie 空间内有内容, 那么当前页面发送的请求是可以自动携带的

  如何在服务器启动页面
    + 简单借助 vscode 的插件来实现
    + 下载一个插件叫做 live server
    + 将来打开页面的时候, 使用 右键单击, 选择 open with live server
*/


/*
  设置 cookie
    + 语法: document.cookie = 'key=value'
    + 注意: 一次只能设置一条
*/

// 设置 cookie
// document.cookie = 'a=100'

/*
  设置一条带有过期时间的 cookie
    + 语法: document.cookie = 'key=value;expires=时间对象'

  说明:
    + 当你设置带有过期时间的 cookie 的时候
    + 你给的时间对象不管是什么时区, 都会当做世界标准时间使用
    + 例子:
      => 你设置的时候设置的是 16:34
      => cookie 拿到 16:34 会当做世界标准时间使用
      => 该 cookie 会在世界标准时间 16:34 过期, 被自动删除
      => 世界标准时间的 16:34 是北京时间 00:34 分

  设置一条 30s 以后过期的 cookie
    + 拿到当前时间节点
    + 向前调整 8 个小时
    + 在向后顺延 30s 就可以了
*/
var time = new Date()
document.cookie = 'a=100;expires=' + time

设置一条 30s 以后过期的 cookie
var time = new Date()
var t = time.getTime() - 1000 * 60 * 60 * 8 + 1000 * 30
利用这个时间戳, 再次设置 time 这个时间对象去进行时间节点的定位
time.setTime(t)
设置 cookie
document.cookie = 'a=100;expires=' + time


/*
  读取 cookie
    + 语法: document.cookie
    + 得到: 完整的 cookie 字符串
*/

var c = document.cookie
console.log(c)

var obj = {}
c.split('; ').forEach(function (item) {
  var t = item.split('=')
  obj[ t[0] ] = t[1]
})
console.log(obj)

1.封装函数设置 cookie

    // 将来使用的时候
    //   设置一条 a=100 这样的 cookie, 过期时间就是 会话级别过期
    //setCookie('a', 100)
    //   设置一条 b=200 这样的 cookie, 过期时间就是 30s 以后
    //setCookie('b', 200, 30)
 
function setCookie(x, y, z) {
        // 设置一条 30s 以后过期的 cookie
        var time = new Date()
        var t = time.getTime() - 1000 * 60 * 60 * 8 + 1000 * z
        // 利用这个时间戳, 再次设置 time 这个时间对象去进行时间节点的定位
        time.setTime(t)
        // 设置 cookie
        document.cookie = `${x}=${y};expires=` + time
    }
    setCookie('a' , 100, 5)
    

2.封装函数获取 cookie

    // 将来使用的时候
    //var res = getCookie()
    // res 得到的就是一个对象, 里面包含所有的 cookie 内容
    
    // res 得到的就是一个对象, 里面包含所有的 cookie 内容
    document.cookie = 'a=100'
    document.cookie = 'b=100'
    document.cookie = 'c=100'
    function getCookie() {
        var c = document.cookie
        var obj = {}
        c.split('; ').forEach(function (item) {
            var t = item.split('=')
            obj[t[0]] = t[1]
        })
        return obj
    }
     var res = getCookie()
     console.log(res);
     
     

2022.10.17

一.认识DOM

+ Document Object Model
    + 文档对象模型
    + 私人: 一整套操作 文档流 相关内容的属性和方法
    + 其实就是操作页面上的元素
      => 删除某一个标签
      => 操作元素样式
      => 操作元素类名
      => 操作元素属性
      => 操作元素内容
      => ...

  例子: 我想让页面上的 某一个 div 背景颜色从 红色 变成 蓝色
    + 步骤1: 找到你要操作的那一个 div 标签
      => var "变量" = 你要操作的那个 div 标签
    + 步骤2: 对该标签进行操作
      => "变量" 设置它的背景颜色为 蓝色
      

二.获取元素的方式

 非常规元素
    + html: document.documentElement
    + head: document.head
    + body: document.body

  常规元素
    1. 根据元素的 id 名进行获取
      => 语法: document.getElementById('id名')
      => 返回值:
        + 如果页面上有该 id名 对应的元素, 那么就是这个元素
        + 如果页面上没有该 id名 对应的元素, 那么就是 null
        
    2. 根据元素的 类名 进行获取
      => 语法: document.getElementsByClassName('类名')
      => 返回值: **是一个伪数组**
        + 如果页面上有该 类名 对应的元素, 那么有多少获取多少, 放在伪数组内返回
        + 如果页面上没有该 类名 对应的元素, 那么就是一个空的伪数组
        
    3. 根据元素的 标签名 进行获取
      => 语法: document.getElementsByTagName('标签名')
      => 返回值: **是一个伪数组**
        + 如果页面上有该 标签名 对应的元素, 那么有多少获取多少, 放在伪数组内返回
        + 如果页面上没有该 标签名 对应的元素, 那么就是一个空的伪数组
        
    4. 根据 选择器 获取一个元素
      => 语法: document.querySelector('选择器')
      => 返回值:
        + 如果页面上有该 选择器 对应的元素, 那就是个该选择器对应的 第一个 元素
        + 如果页面上没有该 选择器 对应的元素, 那么就是 null
        
    5. 根据 选择器 获取一组元素
      => 语法: document.querySelectorAll('选择器')
      => 返回值: **是一个伪数组**
        + 如果页面上有该 选择器 对应的元素, 那么有多少获取多少, 放在伪数组内返回
        + 如果页面上没有该 选择器 对应的元素, 那么就是一个空的伪数组


  伪数组:
    + 长得和数组一样
    + 是一个数据结合, 内部按照索引排列
    + 但是不能使用数组常用方法
    
    

三.操作元素样式

 1. 获取元素行内样式
    => 语法: 元素.style.样式名
    => 得到: 元素该样式的值(前提: 只有行内样式能拿到值)

  2. 获取元素非行内样式(内嵌式, 外链式)
    => 语法: window.getComputedStyle(元素).样式名
    => 得到: 元素该样式的值, 不管是行内还是非行内, 都能拿得到值

  3. 设置元素行内样式
    => 语法: 元素.style.样式名 = '样式值'
    => 作用: 设置元素的行内样式


  注意: 如果样式名涉及了 中划线(-), 需要使用 驼峰命名 或者 数组关联语法
  ele.style.backgroundColor = 'orange'  驼峰
  ele.style['font-size'] = '40px'  数组关联语法
*/

四.案例-回到顶部

 需求:
    1. 随着滚动条的滚动
      => 当超过临界点(350)
        -> 顶部通栏出现         设置 top 样式值是 0
        -> 回到顶部按钮出现      设置 display 样式值是 block
      => 当小于临界点(350)
        -> 顶部通栏隐藏         设置 top 样式值是 -80px
        -> 回到顶部按钮隐藏      设置 display 样式值是 none

    2. 点击回到顶部按钮
      => 让滚动条滚动到顶部
      
      <style>
* {
  margin: 0;
  padding: 0;
}

body {
  height: 5000px;
}

.header {
  width: 100%;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  background-color: skyblue;
  color: #fff;

  position: fixed;
  top: -80px;
  left: 0;

  /* 过渡动画 */
  transition: top .3s linear;
}

.goTop {
  width: 50px;
  height: 50px;
  font-size: 22px;
  line-height: 25px;
  text-align: center;
  position: fixed;
  right: 50px;
  bottom: 50px;
  cursor: pointer;
  background-color: orange;
  color: #fff;

  display: none;
}
      <div class="header">顶部通栏</div>
      <div class="goTop">回到顶部</div>
      


// 0. 获取到需要操作的元素
var headerBox = document.querySelector('.header')
var goTopBtn = document.querySelector('.goTop')


// 1. 随着滚动条的滚动
// 1-1. 需要随着滚动条的滚动实时进行判断, 判断两个内容是出现还是消失
// 应该需要一个浏览器滚动事件, 可以随着滚动实时触发
window.onscroll = function () {
  // 1-2. 获取到浏览器卷去的高度
  var scrollTop = document.documentElement.scrollTop || document.body.scrollTop

  // 1-3. 判断
  if (scrollTop >= 350) {
    // -> 顶部通栏出现         设置 top 样式值是 0
    headerBox.style.top = 0
    // -> 回到顶部按钮出现      设置 display 样式值是 block
    goTopBtn.style.display = 'block'
  } else {
    // -> 顶部通栏隐藏         设置 top 样式值是 -80px
    headerBox.style.top = '-80px'
    // -> 回到顶部按钮隐藏      设置 display 样式值是 none
    goTopBtn.style.display = 'none'
  }

}


// 2. 点击回到顶部按钮
goTopBtn.onclick = function () {
  // 2-1. 让滚动条滚动到顶部
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  })
}

五.操作元素属性

元素属性
  + 属性就是书写在标签身上的键值对, 用来描述当前标签使用的
  + 属性:    键="值"

元素的属性分类
  + 原生属性
    => W3C 规范内带有的属性, 属性对标签有特殊的描述意义
  + 自定义属性
    => W3C 规范内没有的属性, 是我们自己书写的, 用于记录一些信息使用的, 对标签没有特殊意义
  + H5 自定义属性
    => 规定, 在书写的时候以 data- 开头
    => 书写: data-属性名=属性值
    
    
    
 /*
  操作元素属性

  操作原生属性
    + 读: 元素.属性名
    + 写: 元素.属性名 = 值
    + 特殊:
      => 有一种特殊的原生属性, 叫做 布尔类型 属性
      => 类似于 checked / selected 等属性
      => 在 JS 内拿到的值是一个 布尔值, 当你设置的时候, 也是使用 布尔值 设置即可

  自定义属性
    + 设置: 元素.setAttribute(key, value)
    + 获取: 元素.getAttribute(key)
    + 删除: 元素.removeAttribute(key)
    + 注意: 设置完毕以后, 获取到的一定是一个 字符串 类型
    + 注意: 该方法可以设置原生属性, 但是不推荐

  H5 自定义属性
    + 每一个元素天生自带一个成员叫做 dataset, 是一个类似对象的数据结构
    + 内部记录的是该元素身上所有 data- 开头的自定义属性
    + 对 H5 自定义属性的操作, 就是对这个 dataset 数据的操作


  注意: 以上所有操作元素属性的方式方法均不去操作 类名 和 样式
*/

六.案例-密码可视化

 <input type="password"><button>眼睛</button>

 <script>
/*
  密码可视化

  需求:
    + 当你点击 "眼睛" 的时候
    + 切换 input 标签的 type 属性的值
      => text 和 password 进行切换
*/

// 0. 获取元素
var inp = document.querySelector('input')
var btn = document.querySelector('button')


// 1. 书写一个点击事件
btn.onclick = function () {
  // 1-1. 拿到 input 当前的 type 值
  var state = inp.type

  // 1-2. 进行设置
  // 判断进行设置
  if (state === 'text') {
    inp.type = 'password'
  } else {
    inp.type = 'text'
  }
}

七.案例-全选

<style>
* {
  margin: 0;
  padding: 0;
}

.box {
  width: 100px;
  padding: 20px;
  border: 3px solid orange;
  border-radius: 15px;
  margin: 50px auto;
}

hr {
  margin: 20px 0;
}
/*
  案例 - 全选

  需求:
    1. 点击全选按钮的时候
      => 如果全选按钮是 选中状态, 那么所有选项都设置为 选中状态
      => 如果全选按钮是 未选中状态, 那么所有选项都设置为 未选中状态

    2. 点击每一个选项按钮
      => 判断所有的选项按钮
      => 如果所有的都是 选中状态, 那么全选按钮设置为 选中状态
      => 只要有任何一个选项按钮是 未选中状态, 那么全选按钮设置为 未选中状态
*/


 // 0. 获取元素
var allBtn = document.querySelector('input')
var btns = [ ...document.querySelectorAll('.item') ]
//var btns = Array.from(document.querySelectorAll('.item'))

// 1. 点击全选按钮的时候
// 1-1. 给全选按钮绑定一个点击事件
allBtn.onclick = function () {
  // 1-2. 拿到全选按钮的选中状态
  var state = allBtn.checked

  // 1-3. 给 所有的选项按钮, 也就是 btns 内的每一个元素
  //   因为你要给 每一个选项按钮设置(元素)
  //   btns 是一个伪数组, 内部的每一个才是元素
  for (var i = 0; i < btns.length; i++) {
    // btns[i] 就是 btns 内的每一个, 也就是每一个选项按钮
    btns[i].checked = state
  }
}


// 2. 点击每一个选项按钮 方法一
for (var i = 0; i < btns.length; i++) {
  btns[i].onclick = handler
}
function handler() {
  allBtn.checked = btns.every(function (item) { return item.checked === true })
}


// 2. 点击每一个选项按钮  方法二
// 2-1. 循环遍历
// for (var i = 0; i < btns.length; i++) {
//   btns[i].onclick = handler
// }
// // 事件处理函数
// function handler() {
//   // 2-2. 统计 btns 内有多少个选中的
//   // 2-2-1. 准备一个计数器
//   var count = 0
//   // 2-2-2. 遍历 btns
//   for (var i = 0; i < btns.length; i++) {
//     if (btns[i].checked) count++
//   }

//   // 2-3. 给全选按钮绑定选中状态了
//   //   如果 count === btns.length 为 true, 应该给 allBtn 设置选中状态为 true
//   //   如果 count === btns.length 为 false, 应该给 allBtn 设置选中状态为 false
//   allBtn.checked = count === btns.length
// }


八.操作元素类名

/*
  操作元素类名
    + 目的: 为了批量操作样式


  1. className
    + 等价于原生属性的操作
    + 读: 元素.className
      => 得到: 该元素的完整类名字符串
    + 写: 元素.className = '值'
      => 注意: 完全覆盖式的书写
    + 追加: 元素.className += ' 值'

  2. classList
    + 每一个元素身上自带一个成员叫做 classList, 一个类似数组的数据结构, 记录的是该元素的所有类名
    + 添加: 元素.classList.add('类名')
    + 删除: 元素.classList.remove('类名')
    + 切换: 元素.classList.toggle('类名')
      -> 原先有就删除, 原先没有就添加
      适合选项卡 等项目
*/

九.案例-选项卡

  <style>
* {
  margin: 0;
  padding: 0;
}

div {
  width: 500px;
  height: 360px;
  border: 3px solid #333;
  margin: 50px auto;
  display: flex;
  flex-direction: column;
}

div > ul {
  height: 60px;
  display: flex;
}

div > ul > li {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 20px;
  color: #fff;
  background-color: skyblue;
  cursor: pointer;
}

div > ul > li.active {
  background-color: orange;
}

div > ol {
  flex: 1;
  position: relative;
}

div > ol > li {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: purple;
  color: #fff;
  font-size: 100px;

  display: none;
}

div > ol > li.active {
  display: block;
}
  • 1
  • 2
  • 3
  1. 1
  2. 2
  3. 3
   /*
      案例 - 选项卡(tab切换)
    + 致命问题: 循环绑定事件内, 不能使用 var 定义的循环控制变量

  需求:
    + 点击每一个 按钮 的时候
      => 只有当前按钮有 active 类名, 其他的都没有
      => 只有和当前按钮索引对应的 盒子 有 active 类名, 其他的都没有
    + 例子:
      => 你点击的是 [0] 的, 那么只有 [0] 的按钮和 [0] 的盒子有 active 类名
      => 你点击的是 [1] 的, 那么只有 [1] 的按钮和 [1] 的盒子有 active 类名
      => 你点击的是 [2] 的, 那么只有 [2] 的按钮和 [2] 的盒子有 active 类名
*/

// 0. 获取元素
var btns = document.querySelectorAll('ul > li')
var boxs = document.querySelectorAll('ol > li')

 // 1. 循环遍历
 for (var i = 0; i < btns.length; i++) {
  // btns[i] 是每一个 按钮元素

  // 1-1.
  // 给 每一个按钮 添加了一个叫做 data-index 的自定义属性, 记录的是该元素的索引
  btns[i].dataset.index = i

  // 1-2.
  btns[i].onclick = function () {
    // 当前这个按钮的索引
    var index = this.dataset.index - 0

    // 给 btns 和 boxs 内每一个去掉 active 类名
    for (var j = 0; j < boxs.length; j++) {
      btns[j].classList.remove('active')
      boxs[j].classList.remove('active')
    }

    // 给 btns 和 boxs 内 [index] 个添加 active 类名
    btns[index].classList.add('active')
    boxs[index].classList.add('active')
  }
}

十.操作元素内容

 /*
  操作元素内容

  1. innerText
    + 是一个读写的属性
    + 读:
      => 语法: 元素.innerText
      => 得到: 该元素内的所有文本内容
    + 写:
      => 语法: 元素.innerText = '值'
      => 作用: 完全覆盖式的书写该元素的内容, 不会识别 html 格式字符串


  2. innerHTML
    + 是一个读写的属性
    + 读:
      => 语法: 元素.innerHTML
      => 得到: 该元素内的所有内容(包含超文本内容), 以字符串的形式返回给你
    + 写:
      => 语法: 元素.innerHTML = '值'
      => 作用: 完全覆盖式的书写该元素的内容, 会识别 html 格式字符串


  3. value
    + 是一个读写的属性, 专门用来操作 表单元素(input/textarea/select)
    + 读:
      => 语法: 元素.value
      => 得到: 该元素的 value 值
    + 写:
      => 语法: 元素.value = '值'
      => 作用: 完全覆盖式的书写该元素的 value 值
*/

十一.案例-渲染页面

   /*
  案例 - 渲染页面
    + 用数据的方式来组装我们的 html 页面结构
    + 需求: 用数据渲染一个用户表格

  套路:
    1. 书写 html + css 内容
      + 重复的内容只写一遍即可
    2. 使用数据组装一个 合法的 html 格式字符串
      + 按照你在 html 内容中书写的内容进行复制即可
    3. 把组装好的字符串插入到指定标签内即可
*/

  <style>
table {
  width: 500px;
  text-align: center;
  margin: 30px auto;
}
 </style>
 
 
 <table border="1" cellspacing="0">
<thead>
  <tr>
    <th>序号</th>
    <th>姓名</th>
    <th>性别</th>
    <th>年龄</th>
    <th>操作</th>
  </tr>
</thead>
<tbody>
  <!-- JS 渲染 -->
</tbody>
 </table>
 
 


// 0. 准备数据
var users = [  { id: 1, name: 'Jack', age: 18, gender: '男' },  { id: 2, name: 'Rose', age: 20, gender: '女' },  { id: 3, name: 'Tom', age: 22, gender: '男' },  { id: 4, name: 'Jerry', age: 24, gender: '男' }]

// 0. 获取元素
var tbodyEle = document.querySelector('tbody')

// 组装一个合法的 html 结构字符串, 用来渲染页面
// 组装的逻辑: 其实就是在做叠加
tbodyEle.innerHTML = users.reduce(function (prev, item) {
  return prev + `
    <tr>
      <td>${ item.id }</td>
      <td>${ item.name }</td>
      <td>${ item.gender }</td>
      <td>${ item.age }</td>
      <td>
        <button>编辑</button>
        <button>删除</button>
      </td>
    </tr>
  `
}, '')