js部分笔记

js 基础 ---->js高级

day01

js的三个书写方式

1.行内式

2.内嵌式

3.外链式

四个常用的js方法

alert()提示弹框

prompt()弹出输入框

console.log ( ) 控制台输出消息

document.write( ) 把内容写入页面body 里面

变量命名规范

1.能使用那些符合规格的字符:数字,字母,$符,_下划线。

2.不能用数字开头

3.不能使用js里面具有特殊功能的单词-------关键字、保留字。

4.区分大小写

5.命名语义化----建议使用驼峰命名(多个单词的组合)

​ 大驼峰:所有单词首字母大写;

​ 小驼峰:第一个单词首字母小写,其他单词首字母大写

数据类型:

基本数据类型(值类型、简单数据类型):number ,string , boolean ,null ,undefined ,es6新增symbol

复杂数据类型(引用类型):函数Function,数组Array,对象Object,时间Date,正则表达式RegExp

类型转换 (三种):

1.其他转为数字:number()、parseInt()、parseFloat ( )

Number(数据) // 把其他的类型转换为数字
parseInt(数据) // 把字符串转换为整数
parseFloat(数据) // 把字符串转换为小数

2.其他转为字符串:String()、. toString()

String(数据)
(数据).toString() // 小数和null、undefined在使用的时候要小心

3.其他转为布尔:Boolean()

以下6种情况会转为false ,其他转为true

0,’ ‘,false,null,undefined,NaN。

day02

一、操作符

运算符 + - * / %

+ 操作符的作用有:

  1. 字符串相连
  2. 数字相加
1. 字符串 + 其他 = 字符串
会把其他类型 转换为 字符串 , 两个字符串连接到一起
2. 数字 + 数字 = 数字
会把其他类型 转换为 数字 ,再相加

-操作符的作用就是数字相减

- 
都是优先把非数字的转换为数字,再运算
var res3 = '456' - 123; 
console.log(res3); // 输出 数字 333
var res4 = 'abc' - 123;
console.log(res4); // 输出NaN
这是因为,数字和字符串在相减的过程中,会把字符串隐式转换成数字,再相减。但是如果字符串在转换的过程中,无法转换成数字,就会转换成NaN,再计算就无法得到一个正确的数字结果

*操作符的作用是两个数字相乘

/操作符的作用是两个数字相除

%操作符的作用是两个数字求模(得到余数)

a % b  取模运算:
	a能不能被b整除  无法整除的部分就是余数
    取模就是 得到a除以b的余数  

    比如:奇偶数判断

隐式转换

隐式转换是指在数据在参与运算的过程中,数据根据操作符的运算规则自动进行的数据类型转换

  • 加法会发生字符串拼接的情况
  • 减法、乘法、除法……默认都会调用Number( )

比较运算符

<  >      >=  <= 
以上都是和数学里面的比较是一样的规则

== 
  判断两个值是否相等(数字和字符串)
console.log(5 % 2 == 0);

!=
  判断两个值不相等
console.log(5 % 2 != 0);

===
  判断类型和值是否相等
console.log(undefined === null);
!==
  判断类型和值是否不相等
  
//特殊的 NaN 和谁都不相等  也不等于自己
// 如何验证一个数据, 不是NaN
//  isNaN(数据) 判断一个数据是否是NaN
console.log(isNaN(NaN)) //  NaN是一个NaN, 所以得到的是true
console.log(isNaN(123)) //  123不是一个NaN, 所以得到的是false

补充算术操作符

自增自减运算符 ++ – 自增和自减用法一样

数据++;
++数据;

  • 不同点(在运算中):

    • 数据++ 先拿数据原本的值进行计算,计算完后,再自增
    • ++数据 先自增,自增的结果来参与计算

赋值操作符

  赋值运算符  =
  执行过程:
	 先执行 = 右边的代码,得到结果,再给 = 的左边

  var num = 30;
  // num = num + 20;
  // 简写方式
  num += 20;
  console.log(num); // 50

  // -= *= /= %=  

逻辑操作符

逻辑运算符的主要作用是连接多个条件,我们要掌握的比较运算符有

&&    ||

&& 用在需要多个条件同时成立的时候

// 用户在登录的时候要用户名和密码同时正确才能登录
var userName = prompt('请输入用户名');
var password = prompt('请输出密码');
console.log(userName === 'admin' && password === '123456');
// 只有 && 两边的 结果都是 true ,最终结果才是 true

|| 用在只需要任意条件成立的时候

// 只要年龄小5岁或者身高小于120cm就可以免费乘坐
var age = parseInt(prompt('请输入你的年龄'));
var height = parseFloat(prompt('请输入你的身高'));
console.log(age < 5 || height < 120);
// 只要 || 两边的结果有一个是true,最终结果就是true

! 用于颠倒是非的时候

var res = true;
console.log(!res);
console.log(!!res);// 转布尔值
// 这里暂时用不到,在后面做具体效果的时候都用,那个时候我们再学习具体的使用

操作符的优先级

观察代码

var res = 5 + 2 * 3;
console.log(res); // 11

在上述代码中,执行过程是先计算 2*3 再和 5 相加的。在js中的操作符很多,我们要认识到它们之间是有计算的优先顺序的,这个优先顺序我们称为优先级

记忆一下下面的计算优先级

1. 第一优先级: . [] ()                 字段访问、数组下标、函数调用
2. 第二优先级: ++ -- !				一元运算符
3. 第三优先级: *  /  %				二元运算符 乘法、除法、取模
4. 第四优先级: +  -					二元运算符 加法、减法
5. 第五优先级: >   >=   <   <=         比较运算符
6. 第六优先级: ==   !=    ===    !==   比较运算符
7. 第七优先级: &&					逻辑与
8. 第八优先级: || 					逻辑或
9. 第九优先级: = += -= *= /= %=        赋值

上面是具体的优先级,但是平时我们不会把很多的操作符放在一起运算,所以我们大致记住

  1. 括号先算
  2. 其次算算术
  3. 再次算比较
  4. 然后算逻辑
  5. 最后算赋值

二、流程控制

js里面的代码是有执行顺序的,通过一些特殊的方式控制那些代码如何执行 —— 流程控制

顺序结构

按照从上到下的顺序,一行不漏的执行

分支结构

在逻辑上有多个分支,只会选择一个分支执行

循环结构

重复的代码,可以使用循环的方式实现多次

表达式

可以得到一个结果的代码 ,比如:

// 下面都可以称为表达式
12; // 结果是12
a++; // 结果是 a值加1
5 > 6; // 结果是 false
// ...

语句

语句可以理解为一个行为,一般在行为和行为之间,都会使用 ; 隔开

console.log(12); // 行为就是输出了一个12在控制台
alert('helloworld'); // 行为就是弹出了个提示框
var a = 10;

简而言之:一个程序可以由多个语句组成,一个语句可以由多个表达式组成

三、分支结构

从多个分支里面选择一个 —— 作用 : 判断

判断一下一个人的性别,如果是男的,让他上男厕

if/else结构

只有一个条件的判断:

if( 条件表达式 ){
   条件表达式的结果是true的时候要执行的代码
}

var gender = prompt('请问您的性别是男的吗');

if( gender === '男' ){
  alert('男厕所在二楼的最东边,请去吧');
}

两个条件的判断:

if( 条件表达式 ){
   条件表达式的结果是true的时候要执行的代码
}else {
  条件表达式的结果是false的时候要执行的代码
}

var gender = prompt('请告诉我你的性别');
if(gender === '男'){
  alert('男厕所在二楼的最东边,请去吧');
}else {
  alert('女厕所在3楼的西边');
}

多个条件的判断:

if( 条件表达式1 ){
   条件表达式1的结果是true的时候要执行的代码
}else if(条件表达式2){
  条件表达式2的结果是true的时候要执行的代码
}else if(){
         
}
// 如果还有更多的判断,继续写 else if ()

else {
  以上的条件都不为true,就会执行这里的代码
}


var num1 =  +prompt("请输入一个数字(1~7):");

if(num1 === 1){
    console.log("星期一");
}else if(num1 === 2){
    console.log("星期二");
}else if(num1 === 3){
    console.log("星期三");
}else if(num1 === 4){
    console.log("星期四");
}else if(num1 === 5){
    console.log("星期五");
}else if(num1 === 6){
    console.log("星期六");
}else if(num1 === 7){
    console.log("星期日");
}else{
    // 这里的代码,当上面所有条件都不成立, 就执行这里的代码
    console.log("请务必输入1-7");
}

练习:

  1. 任意输入两个数,求两个数最大值,在弹窗中显示最大值(练习if-else结构)

  2. 判断分数区间,分数在90到100的为A,80到89的为B,70到79的为C, 60到69为D,60以下为E (练习if-else-if 结构)

     // 注意: 数学中 3 < x < 10 的写法在js中不存在,  要改成  3 < x  && x < 10
     var score = 11;
     console.log(3 < score < 10); // true
     console.log(3 < score && score < 10); // false
    

switch结构

在js里面如果是比较固定值,推荐使用swtich-case结构

语法:

switch (变量){
  case 要比较的固定的值1:
    变量和 固定的值1  ===   的时候要执行的代码
    break;
  case 要比较的固定的值2:
    变量和 固定的值2  ===   的时候要执行的代码
    break;
  case 要比较的固定的值3:
    变量和 固定的值3  ===   的时候要执行的代码
    break;
  default:
    当以上所有的条件都不成立的时候,代码在这里执行
    break;
}

举例:

switch(num){
    case 1: alert("星期一");break;
    case 2: alert("星期二");break;
    case 3: alert("星期三");break;
    case 4: alert("星期四");break;
    case 5: alert("星期五");break;
    case 6: alert("星期六");break;
    case 7: alert("星期日");break;
    default: alert("请输入正确的数字:1-7"); break;
}

细节

  1. 小阔号里面的变量 全等于 case 后面的值得时候,这个case后面的代码就会被执行

  2. default不是必须的,如果小阔号里面的变量都不等于所有的case后面的值,才会执行default 后面的代码

  3. break的作用是结束判断,如果后面没有写break,则代码会继续往下执行

  4. .变量和固定值的比较是 === 严格等于

三元表达式(补充)

三元(三目)表达式的使用是简写if-else结构

语法:

表达式1 ? 表达式2 : 表达式3
// 如果表达式1 成立, 那么就执行表达式2
// 如果表达式1 不成立, 那么就执行表达式3
//例如: 求二个数字中谁更大
var a = 10; var b = 20;
var max = a > b ? a : b;
console.log(max);

总结:

if/else结构,多用于判断区间、不定值判断

switch-case 只能用于定值判断

四、循环结构

在js中,如果我们要连续输出同样的一句话多次,会比较麻烦

//输出 xxx,不愧是你!! 6 次
console.log('不愧是你!!');
console.log('不愧是你!!');
console.log('不愧是你!!');
console.log('不愧是你!!');
console.log('不愧是你!!');
console.log('不愧是你!!');

同样的代码我们写了6次,这样是不好的,重复多次时,我们使用循环结构结构

for循环

语法:

for(初始化表达式 ; 条件表达式 ; 递增或者递减表达式){
  循环体(需要重复执行的代码)
}

for(var count = 0;count < 6; count++){
  console.log('javascript天下无敌!!!');
}

执行过程:

1.先执行初始化表达式

2.判断条件是否成立

3.如果成立,执行循环体

4.执行递增表达式

重复2~4,直到第2步的条件为false,就结束循环

练习:
  1. 求1~10之间的所有整数和
  2. 在控制台输出1到10的数字中偶数的累加和

嵌套for循环

// 需求:在浏览器中用*打印一个矩形形
****
****
****
****
 var str = "";
  for (var i =0; i < 4; i++) {
    
    for (var j =0; j < 4; j++) {
      str = str += "*";
    }
    str = str += "\n";
  }
  console.log(str);

day03

1.数组 Array

//数组:数据的集合
//类似于文件夹,将同类数据放在一个文件夹内
let arr =[10,20,30,40] ;

//通过 arr[索引]  获取数组中的每一项
//索引(也叫下标)是从0开始的 

//数组的增删改查
//增 数组中没有则增,有则改
//增
arr[5] = 80; 
//改,也叫重新赋值
arr[0] = 100; 
//删 
arr.splice(1,1)
//查 
 console.log(arr[0],arr);   //控制台输出数组arr 中的第0 个元素----10
 //如果数组中某项的值为空 则返回undefined
console.log(arr[4],arr[10]) //undefined,undefined

数组的遍历

 var arr = [10, 20, 30, 40, 50];
 //方法1、
         for(var i=0;i<arr.length;i++){
           console.log(i,arr[i]);// i 索引   arr[i]值
        }
//方法2、
        for (var key in arr){
            console.log(key, arr[key]);// key 索引   arr[key]值
        }

计算多个数字的和

  // 机器人案例 请输入  1,2,3  格式的数据,我们帮你求和
   var ste = prompt('请输入1,2,3格式的数据(英文,),我们帮你求和')

   let arr =ste.split(',')   //将得到的字符串用splice 方法切割得到一个新的数组
   console.log(arr);  //['1','2','3'......]
   let sum = 0;
   for (var i=0;i<arr.length;i++){
        sum +=  Number(arr[i])  //遍历数组的每一项,转为数字类型,并累加
   }
   console.log(sum);

获取当前时间

 //获取当前时间

    // 1.获取时间对象
    var myDate = new Date ();

    //2.获取时间对象上的年月日、时分秒
    let y = myDate.getFullYear();
    
    let m = myDate.getMonth()+1;

    let d = myDate.getDate()

    let h =myDate.getHours()

    let ms =myDate.getMinutes()

    let s = myDate.getSeconds()
    // console.log(y,m,d,h,ms,s);
// 希望输出结果为: 2022年02月28日  19时46分26秒
// 当 时 分 秒 月 日是个位数的时候需要在前面添加 0

let arr =[m,d,h,ms,s ]
let newArr=[]
arr.map(item=>{
    if(item<10){
         item = '0'+item
    }
    
    console.log(item);
    newArr.push(item)
                                                
})
console.log(newArr);

let btn = document.getElementById(['btn'])
btn.onclick=function(){
    alert('当前时间是'+y + '年'+ newArr[0] +'月' +newArr[1] +'日  '+newArr[2] + "时" +newArr[3]+'分'+newArr[4] + '秒');

    // alert('当前时间是'+y + '年'+ arr[0] +'月' +arr[1] +'日  '+arr[2] + "时" +arr[3]+'分'+arr[4] + '秒');
}

随机数获取

    let arr = ['歌曲1','歌曲2','歌曲3','歌曲4','歌曲5','歌曲5','歌曲7'];
 //random获取7以下的随机正数
console.log(Math.random()*7);

 //floor向下取整,获取7以下的正整数
console.log(Math.floor(Math.random()*7)); 
//获取数组中随机项
let ind = Math.floor(Math.random()*arr.length)
console.log(arr[ind]);

求数组的和,平均值,最大值 ,最大值的索引

// 1. 求一个数组中所有数字的” 总和“ 和” 平均值“
    // 2. 求数组中所有数字的最大值
    // 3. 求数组中最大值的索引

    let arr =[1,8,14,7]
    let sum = 0;
    arr.forEach(item=>{
        //求和
        sum +=item
    })
	//求平均值
    let  mean = sum/arr.length
    console.log(sum,mean);

//求最大值 方法1
    let max =0
    let inx =0
   arr.forEach((item,index)=>{
      if(item>max){
          
          max=item  //最大值
          inx = index //最大值的索引
      }
   })
 console.log(max,inx); 
//求最大值 方法2
 console.log(Math.max(...arr)); //最大值

day04

函数:所有编程语言中都是重要的概念

有一段代码需要重复执行(在不同环境) -----使用函数

函数语法:
1.函数声明式(定义式)
funtion 函数名 (){
	函数体 ----- 企图重复运行的代码
}
2.函数的调用式
函数名();

函数命名方式(小驼峰),建议首个单词使用动词 get set create

funtion getNickName() {
	console.log('张三是一个法外狂徒!!!');
}

注意:函数声明之后,不会执行,一定要调用,调用之后才会执行

getNickName();

函数传参

 // 需求: 每次调用函数,人可能不是张三
        // 思路: 将死的具体的数据 变成 可修改的变量

        // 函数参数: 函数体内 会动态变化的值 使用 参数来代替
        /*
            函数参数的语法:
            function 函数名(形参){------ 形式参数(占位)
                // var 形参 = 实参;
                函数体
            }
            
            函数名(实参)---------------- 实际参数(具体的内容)
        */

        function getNickName(name) {
            // 相当于 声明了变量  var name = "张三";
            console.log(name+"是一个法外狂徒!!");
        }


        getNickName("张三");
        getNickName("阿四");

函数参数的使用

  // 目的: 学会 使用函数 传递 多个参数 (原则上 实参数 == 形参数)

        // 原则上,形参可以写无数个,事实上写超过8个都罕见
        // 参数和参数之间使用 , 

        function getNickName(name, nick) {// 形参
            //相当于  var 形参 =  实参  没有实参 就是声明未赋值
            console.log(name + "是一个" + nick + "!!");
        }


        // getNickName("张三","法外狂徒");// 实参
        // getNickName("阿四","域外狂魔");

        // 不正经的传参

        // 1.实参>形参    多余的参数 没有意义 
        getNickName("张三", "法外狂徒", 50);   //张三是一个法外狂徒!!



        // 2.实参<形参   相当于 声明变量未赋值  返回undefined
        getNickName("张三");  //张三是一个undefined!!
        getNickName();   //undefined是一个undefined!!

回调函数

回调函数就是一个被作为参数传递的函数。

        // 回调函数: 当一个函数作为另一个函数的参数使用,这个函数参数就是回调函数

        function fn1(f) {
            // f 是 回调函数
            /*
            相当于 
            var f  =  fn2 ------- 函数本身
            */
            console.log("函数1");
            f();
        }

        function fn2() {
            console.log("函数2");
        }
        fn1(fn2);

函数式思维

        函数思维:
        1. 一段代码 企图重复去写------它就是一个功能(函数)------过程叫做函数封装
        2. 函数中什么值是会变化(参数)
        3. 这个函数需不需要得到某个值(返回值)

1.求n-m之间所有数的和

//n~m之和
    function Fn(n, m) {
        let getSum = 0
        for (var i = n; i <= m; i++) {
            getSum += i

        }
        return getSum
    }
    console.log(Fn(1, 5)); 
    console.log(Fn(2, 5));

函数调用不调用有本质的区别

   function fn(a, b) {
            return a + b
        }


        var sum = fn(10, 30);//  将函数调用式赋值给变量------ 得到的是返回值
        var fn1 = fn;        //  将函数名 赋值 给变量--------得到的是 函数 本身

        console.log(sum);
        console.log(fn);

        //       声明一个函数  fn = xxx  又将 fn的值(函数本身) 赋值给了 fn1
        // 比如   声明一个变量 a = 10   又将a的值(10) 赋值给 b

        var a = 10, b;
        b = a;

函数其他写法 :

函数表达式

        // 函数表达式  
        // var 变量 = 匿名函数 
        /*
            function(){}  匿名函数 
        */
        var fn = function(a,b){
            return a+b
        }

        console.log(fn(10,20)); //得到函数返回值 --- 30
        console.log(fn);  //得到函数本身

立即执行函数

自调用函数,匿名函数自执行---- 函数经典结构

/* 
语法:
      (function(形参){
			函数体
            })(实参)

*/
     (function (a,b) {
            console.log(a+b);
        })(10,20);

js的作用域

1.全局作用域 2. 局部作用域 (只有当前作用域生效)

 // 3个作用域: 1. 全局作用域   2. 作用域1包含fn1作用域  3.作用域2包含fn2作用域
        /* 此时就形成一个作用域"链"结构  (只有函数可以产生作用域链)
        总结:
        1. 所有代码必有一个作用域-----全局作用域
        2. 如有有函数会产生一个作用域----局部作用域
        3. 函数中还有一个函数,就会再产生一个作用域
        4. 此时 产生了一个 **由内而外访问的** 链式结构------ 作用域链
        5. 最终全局都找不到----报错 */
        
      var a = 10;// 全局变量
        function fn1(){
            var a = 20;// fn1局部变量
            function fn2(){
                var a = 30;// fn2局部变量
                console.log(a); // 3. 使用fn2局部变量   30
            }
            console.log(a);// 2. 使用fn1局部变量   20
            fn2();// 调用fn2函数
        }
        console.log(a);// 1. 使用全局变量   10
        fn1();// 调用fn1函数 
        

js预解析

js是解释性语言 (有一个解析器)

执行过程 :1.预解析 2.代码从上往下执行

	   var a;
        console.log(a); //①  undefined
        a = 123;
        console.log(a); //②  123

        console.log(f); //③ 函数

        f(); //④ "函数声明提升"

预解析规则

1、变量和变量同名,解析后,只有一个变量声明

2、函数和函数同名,后面的会覆盖前面的

3、函数和变量同名,只有函数声明提前,忽略变量;变量的值会覆盖函数

4.函数表达式只会提升变量声明,并且函数表达式不能先调用再声明,会报错

day05

arguments参数

  function Fn(a,b){
         console.log(a,b);
         return a+b
     }

     console.log(Fn(1,2,3));  // 3------只计算了前两位数的和,实参数 > 形参数 a=1,b=2
     console.log(Fn(1));      //  NaN ---实参数 <形参数  a=1,b=undefined

    //  arguments 参数集合 是个伪数组 有长度有索引
    let num =0
    function Fn1(){
      
    
       for(var i=0;i<arguments.length;i++){
            num += arguments[i]
       }
       console.log(num);
    }
    Fn1(1,2,3)

短路运算

逻辑运算符 && 且 || 或 !取反

 //  逻辑运算符  && 且    || 或   !取反
        // console.log(1>2 && 1<2);

        // && 一假全假   左边为假,右边不再读取(短路)
        console.log(2 && 0); // 0  false
        console.log(0 && 2); // 0  false
        console.log(3 && 2); // 2  true
        console.log(null && 0); // null  false

        // 取决于谁得到谁  



        // || 一真全真  左边为真,右边不再读取(短路)
        console.log(2 || 0); // 2  true
        console.log(0 || 2); // 2  true
        console.log(3 || 2); // 3  true
        console.log(null || 0); // 0  false

        // ! 颠倒是非  取反 做逻辑判断
        console.log(!0);  //true 
        console.log(!1);  //false
        console.log(!true);  //false

万物皆对象

        console.log(typeof Math);// 数学对象 object 是对象类型

        var date = new Date();
        console.log(typeof date);// 日期对象
        // var arr = new Array();
        var arr = [1,2,3];
        console.log(typeof arr);// 数组对象
        console.log(typeof document);// 文档对象

创建对象

字面量创建对象

      var obj = {};

js内置构造函数创建对象

      var obj = new Object();
 /*重点: 对象只有两个成员
            动态行为: 相当于js里面的函数  -------------------- 对象的**方法**
            描述信息: 相当于js中的变量------------------------ 对象的**属性**
        */
		//创建对象
		var obj = new Object();
        // 给对象添加**属性** (描述信息)
        obj.name = "欧阳三"; 
        //  给对象添加**方法** (动态行为)
        obj.eatFn = function(){
            console.log("今天吃食堂");
        }
        console.log(obj);
	   //获取 对象的属性和方法----------------------------------------
       // *** obj.属性名----------可以得到属性值  
        console.log(obj.name);
         // *** obj['属性名']----------可以得到属性值  
        console.log(obj['name']);
        // *** obj.方法名()----------可以调用对象的方法
        obj.eatFn(); 
       // *** 对象的属性或方法的  修改和添加
        // 如果存在-----修改
        // 如果不存在---添加
        obj.name = "阿四"; // 修改
        obj.email = "asan13524@163.com"; // 添加
        obj.eatFn = function () { // 修改
            console.log("爱吃螺蛳粉");
        }
        obj.eatFn();
		 // 对象属性的删除  delete (关键字) 删除的是一整个键值对 (了解)
        // delete obj.age;
        obj.age = null;

        console.log(obj);
		
   

对象是一个无序的键值对数据集合

  // *** 字面量创建对象,可以创建时候添加属性和方法
        // var arr = [10,20,30];

        // 对象的内部: 键值对  key:value
        //                    键:值
        // 键值对和键值对之间用,隔开
        var obj = {
            //  属性
            name:"欧阳三",
            age:20,
            // 方法
            eatFn:function(){
                console.log("爱吃螺蛳粉");
            },
            sayFn:function(){
                console.log("喜欢抬杠");
            }
        }   
        console.log(obj);
        //发现打印的属性和方法是无序的

        //总结: 对象是一个无序的键值对组成的数据集合

工厂函数创建对象

需求: 用对象来描述,它的名字叫来福,它有黄色的毛hair,它有四条腿leg和一条尾巴tail,它喜欢吃骨头,喜欢跑到隔壁村找翠花

创建100个对象(并且,名字,颜色都不一样,其他内容一样)

函数封装的思维: 名字和颜色用参数代表,其他的内容,放在函数内,循环使用,提高代码复用性。

​ **** 工厂函数 创建 对象:

优点: 批量创建对象

参数: name,hair 可变的值

返回值: 创建出来的新对象

   function createObj(name, hair) {
            var obj = new Object();
            // obj.name=name
            //     key   value(参数)
            obj.name = name;
            obj.hair = hair;
            obj.leg = 4;
            obj.tail = 1;
            obj.eat = function () {
                console.log("喜欢吃骨头");
            };
            obj.lick = function () {
                console.log("喜欢跑到隔壁村找翠花");
            }
            return obj;
        }

        var d1 = createObj("来福", "黄色");
        var d2 = createObj("旺财", "黑色");
        var d3 = createObj("二狗", "粉色");
        console.log(d1,d2,d3);

遍历对象

   // 遍历对象
        // 字面量创建对象
        var obj ={
            name:'张三',
            age:12,
            eatFn:function (){
                console.log('今天吃鸡蛋炒饭');
            },
            asyFn:function(){
                console.log('今天天气真好!');
            },
            key:'啥也不是!!!'
        }
        // console.log(obj);
        //对象的内部都是键值对 ------ key:value
        for (var key in obj){
            console.log(key); //获取到对象中所有的键值对的key(键名)

            console.log(obj.key); //只获取到对象中键值对的key值为key的value值,并且对象有几个键值对就循环几次,打印几次

            console.log(obj[key]); //key 是变量,  对象[key] 获取value值
        }

        obj['eatFn']() //今天吃鸡蛋炒饭-----一般不用

数据类型(首字母大写)

基本数据类型

String Number Boolean Null Undefined Symbol(ES6新增)BigInt(谷歌67新增)

复杂数据类型

Object Array Function

遍历复杂数组

<body>
    <!-- <table   >
        <tr><td>姓名</td><td>年龄</td></tr>
        <tr><td>张三</td><td>23</td></tr>
        <tr><td>李四</td><td>26</td></tr>
        <tr><td>王五</td><td>18</td></tr>
        <tr><td>留流</td><td>11</td></tr>
    </table> -->
</body>
<script>
    // 复杂数组
    // 数组和对象内部value值,理论上可以是任何类型的数据
    let arr=[
        {name:'张三',age:23},
        {name:'李四',age:26},
        {name:'王五',age:18},
        {name:'留流',age:11}
    ]
    // 外层遍历数组,内层遍历对象
    for(var i=0;i<arr.length;i++){
        for (key in arr[i]){
            console.log(arr[i][key]);
        }
    }
    // 渲染表格
    let str = `  <table> <tr><td>姓名</td><td>年龄</td></tr>`

        for(var i=0;i<arr.length;i++){
            str+='<tr >'
                for(var key in arr[i]){
                    str+='<td>'+arr[i][key] +'</td>'
                    

                }
                str+='</tr>'   
        }
        str += '</table>'
        document.write(str)
    // 渲染列表

</script>

day06

快速获取对象的key和value

Object.keys(对象)

Object.values(对象)

数组array.findIndex(需要获取索引的值)

Math对象

Math.random( )   取随机数

Math.floor( )  向下取整

Math.ceil( )   向上取整

Math.abs( )   获取绝对值

Math.max( )  获取最大值

Math.min( )   获取最小值

String 对象

split( 字符)     //通过某个字符进行字符串切割,返回一个新数组

chatAt( index )  //获取字符串的index对应的某个字符

indexOf( 字符)   //获取字符对应的 在字符串中的索引值,如果字符串中没有则返回-1

substring( start, end )  //截取字符串,从索引start 截取到 end,包含start,不包含end

      console.log(str1.substring(2)); // 2~最后  只传一个参数 start到结尾

      console.log(str1.substring(2, 4)); // 2~3

substr( start, n)   //截取字符串,从索引start开始,截取 n 个字符

      console.log(str1.substr(2)); // 只传一个参数 start到结尾

      console.log(str1.substr(2, 4)); //索引2开始 4个字符

      console.log(str1.substr(2, 5)); // 5个字符
splace(old, new)    //使用新字符串替换旧字符串(只匹配到字符串中出现的第一次该字符)
splaceAll(old, new)  //使用新字符串替换旧字符串(匹配字符串中出现的所有该字符)

Array 对象

1.添加删除方法-----改变了原数组
push()        //在数组结尾追加元素
pop()         //删除数组最后一个元素
unshift()     //在数组最前面插入元素
shift()       //删除数组最前面的元素

2.数组翻转----改变了原数组
reverse()

3.splice操作数组----改变了原数组
splice(index)    //只传一个参数,从索引index到结尾
splice(0)        //清空数组
splice(index, n) //传两个参数,从索引index开始,删除n个元素
splice(index,n,参数,参数......) //传多个参数  使用第2个参数后面的参数 替换删除的元素

--------------上面的方法都改变了原数组------------下面的方法不会改变原数组,重点在返回值--------

1.slice(start, end) //从索引start 到 end 截取数组的值(包含start 不包含end)
2.indexOf()  //和字符串一样,数组中有这个值则得到索引(第一次出现的值),没有则返回 -1
3.join(字符)  //将数组转成字符串(并通过某个字符链接)
4.数组的遍历
4.1 forEach(回调函数)   //有两个参数:数组项和索引,没有返回值
4.2 map(回调函数)       //有两个参数:数组项和索引,有返回值
4.3 filter(回调函数)     //也叫过滤器    语法上和forEach一样  返回过滤后的数据
       var ret = arr.filter(function(item,index){
            return item<50
        })
5.concat()  //数组合并(从左往右进行合并) 
var newArr = arr1.concat(arr2)


获取时间戳

 //创建当前时间对象
var date = new Date(); 
 //获取时间戳 方法1
var chuo1 = date.getTime();
 //获取时间戳 方法2
 var chuo2 = +new Date(); //做了隐式转换
// 用时间戳--获取时间对象
var oldDate = new Date(1637226997383);
 console.log(oldDate);  //Thu Nov 18 2021 17:16:37 GMT+0800 (中国标准时间)

把数组的首尾两个元素互换

var arr =["鹿晗", "王俊凯", "蔡徐坤", "彭于晏", "周杰伦", "刘德华", "赵本山"];

var m = arr[0];

arr[0] = arr[arr.length-1];
arr[arr.length-1] = m;
console.log(arr)

使用Math对象,制作一个16进制 的随机颜色

<style>
	.box{
 		width: 100px;
 		height: 100px;
		background-color: #D58EE9;
	}
</style>

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

<script>
	   //   题目提示:16进制包括 “ 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F ”
        //   例:调用 “#f23a4b” 

        //  0~9   10   10
        //  0~15  10   16    16进制  逢16进1    10----A      15----F
        function getColor(){
     		  var arr = ['0', "1", "2", "3", "4", "5", "6", "7", "8", "9",'A','B','C','D','E','F'];
      		 var str = '#';
      		 
      		 for(var i=0;i<6;i++){
      		 	str += arr[Math.floor(Math.random()*arr.length)];
      		 }
      		 return str
        
       }
        
              console.log(getColor());
</script>
        // 2. 字符串:“abaasdffggghhjjkkgfddsssss3444343”,问题如下: 
        /*
          1、 字符串的长度 ------- length
          2、 取出指定位置的字符,如:0,3,5,9等 ----- charAt
          3、 查找指定字符是否在以上字符串中存在,如:i,c ,b等 ----- indexOf() == -1
          4、 替换指定的字符,如:g替换为22,ss替换为b等操作方法 ----- replace()
          5、 截取指定开始位置到结束位置的字符串,如:取得1-5的字符串---- substr  substring
          6、 *** 找出以上字符串中出现次数最多的字符和出现的次数 
          7、 遍历字符串,并将遍历出的字符两头添加符号“@” 
        */

        // 6. ******** 数据统计  计算出每个字符出现多少次
        /*  ***** 思路: 使用对象,预期的数据类型
             obj = {
                 a:2,
                 b:1,
                 ....
             }
          */


        //  6.1 遍历字符串
        var str = "abaasdffggghhjjkkgfddsssss3444343";
        var obj = {};
        for (var i = 0; i < str.length; i++) {
            // console.log(str[i]);
            // 6.2 存储 当前 元素 
            var cur = str[i];
            // 6.3 合成一个对象
            if (obj[cur]) {
                // 6.5 如果出现过,次数累加
                obj[cur]++;
            } else {
                // 6.4 第一次出现 初始化为1
                obj[cur] = 1;
            }
        }

        console.log(obj);

        // 6.6 遍历对象
        var max = 0;
        var maxVal = null;
        for (var k in obj) {
            if (max < obj[k]) {
                max = obj[k];
                maxVal = k;
            }
        }

        console.log("出现最多的字符是:" + maxVal + "-----------出现了" + max + "次");


        // 7. 遍历字符串,并将遍历出的字符两头添加符号“@” 
        // console.log("@"+str+"@");
        var newStr = ""
        for (var i = 0; i < str.length; i++) {
            if (i == 0) {
                newStr = "@" + str[i];
            } else if (i == str.length - 1) {
                newStr += str[i] + "@";
            }else{
                newStr += str[i];
            }
        }

        console.log(newStr);

js 进阶day1-5

js day-01

获取元素

var _box = document.getElementById("box"); //通过id名获取元素
var _p = document.getElementsByTagName("p"); //通过标签名获取元素
var _ele = document.getElementsByClassName("ele");  //通过类名获取元素
var _username = document.getElementsByName("username"); 通过name 属性获取元素

H5新增2种方法
 var _box = document.querySelector("#box");
 var _ele = document.querySelectorAll("p.ele");

为多个元素绑定事件

事件三要素:
			1.事件源     被触发的对象
			2.事件类型     click , mouseover  ,change
			3.事件处理程序    执行的代码 (函数的形式)
			
			
var btn= document.getElementById('btn');	
btn.onclick = function(){

	var _p = document.getElementsByTagName('p');
	
	for(var i = 0; i < _p.length; i++ ){
		_p[i].innerText = '我们是p标签'}
}

排他思想

  // 需求: 排他思想(套路) ---- 点击当前按钮高亮显示(自律),兄弟元素取消高亮

        // 1.获取元素集合
        var btns = document.getElementsByTagName("button"); // 伪数组

        // 2. 遍历伪数组,给每个元素绑定事件
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function(){
                // 4. 排他思想核心: 初始化思维 
                // 改变当前元素之前,让所有元素都取消背景色
                for (var j = 0; j < btns.length; j++) {
                    btns[j].style.background = "none";
                }

                // 强调: 事件绑定第一件事,测试事件绑定成功没有
                // console.log(this);
                // 3. 当前按钮(事件源) 高亮显示
                this.style.background = "#cfc";
            }
        }

day-02

表单元素相关属性

非空判断 初始化输入框

value 值       checked 选中效果      disabled 禁用表单项  常用做非空校验 


  var btn = document.getElementsByTagName("button")[0];
  var txt = document.getElementsByTagName("input")[0];
        
        btn.onclick = function(){
        	var _va = txt.value;
        	if(_va){    // 非空判断
        		console.log(_va)
        	
        	}else{
        		alert("输入框不能为空哦!")
        	}

            txt.value = "";  //初始化表单元素的值为空
        }

动态设置class

 1.  ele.className = "class1 class2...."   添加/删除 类名

2.  ele.classList.add("box");-------- 添加类名
3.  ele.classList.remove("box");-------- 删除类名
 思路: 修改样式, 预先设计好样式,写逻辑的时候 直接操作类名
 
   getId("btn").onclick=function(){
          
            /* getId("box").style.width = "200px";
            getId("box").style.height = "200px";
            getId("box").style.background = "#cfc"; */ //  直接修改 样式

            // ***** 思路: 修改样式, 预先设计好样式,写逻辑的时候 直接操作类名

            // ****** 1. ele.className = "class1 class2...."   修改/删除 类名(保留原有的类名)
            // getId("box").className = "dv box";
            // getId("box").className = "";


            // ****** 2. ele.classList.add("box");-------- 添加类名
            //    ele.classList.remove("box");-------- 删除类名

            // console.log(getId("box").classList);
            // getId("box").classList.add("box");
            getId("box").classList.remove("dv");
        }

开关灯思想

// 开关灯
//判断 当前状态,进行修改   


 getId("btn").onclick=function(){   //1.事件绑定 
 
  if(document.body.className){ // "bg"------ true -------    // 判断有没有这个类名  有则删除 无则添加  
             
                document.body.classList.remove("bg");
                this.innerText = "关灯";
                
            }else{ // ""  ------ false-------- 
               
                this.innerText = "开灯";
                document.body.classList.add("bg");
            }
 }
 
 
 
 
 
 开关思想: 使用变量决定一个状态 由变量的值来决定业务逻辑-----注意点:逻辑写完之后,修改状态
 
  var flag = true;

        getId("btn").onclick = function () { //1.事件绑定 

            if (flag) { //flag------ true -------//  判断有没有这个类名  有则删除 无则添加  

                document.body.className = "";
                this.innerText = "关灯";
                flag = false;

            } else { // ""  ------ false-------- 

                this.innerText = "开灯";
                document.body.className = "bg";
                flag = true;
            }
        }
 
 
 

全选反选 案例

需求:
            1. 全选功能: 点击全选, 列表选框全部选中   点击全部不选,列表选框全部不选中
            2. 反选功能: 点击列表选框, 但凡发现一个列表选框未选中, 全选框未选中 
                                    如果列表选框全部选中, 全选框选中
       
            3. 反选按钮: 列表选框取反(满足反选的逻辑)
            
         
         
      1. 全选功能   
      var _put = getEle("j_tb", 'input');
        getId('j_cbAll').onclick = function () {

            console.log(this);
            for (var i = 0; i < _put.length; i++) {

                _put[i].checked = getId('j_cbAll').checked;
                getId('txt').innerText = getId('j_cbAll').checked ? '全不选' : '全选';
            }

        }
        
        
        


	点击列表选框, 但凡发现一个列表选框未选中, 全选框未选中  如果列表选框全部选中, 全选框选中
                                   
		
        for (var i = 0; i < _put.length; i++) {


            _put[i].onclick =function() {

		 思路: 假设所有选框都是选中状态, 遍历所有选框,找到一个未选中, 全选状态 改为false
            var flag = true;


            for (var j = 0; j < _put.length; j++) {

                if (!_put[j].checked) {
                    flag = false;
                }




            }
            getId('j_cbAll').checked = flag;

            getId('txt').innerText = getId('j_cbAll').checked ? '全不选' : '全选';


        }

        }
        
        

         // 反选按钮
         // 1.点击按钮  每个列表选框选中状态改变  取反
         // 2.全选按钮 和 每个列表选框 状态 跟着改变 

        getId("rev").onclick = function () {

            for (var i = 0; i < _put.length; i++) {
                _put[i].checked = !_put[i].checked;



            }
            
            和上面不占一样,可以做函数封装
             var flag = true;


            for (var j = 0; j < _put.length; j++) {

                if (!_put[j].checked) {
                    flag = false;
                }




            }
            getId('j_cbAll').checked = flag;

            getId('txt').innerText = getId('j_cbAll').checked ? '全不选' : '全选';


        }        
  

day-03

节点案例

**** 获取父元素--------单数

   ele.parentNode  父级节点-------节点包含元素

 ele.parentElement  父级元素

 ele.childNodes   子级节点      

 ele.children   子级元素
 点击按钮 切换 p标签背景颜色  
        
 getId('btn').onclick = function(){
            var _box = getId('box').childNodes;
            console.log(_box);
            for(var i=0;i<_box.length;i++){

                if( _box[i].nodeName == 'P'){
                    _box[i].style.background = '#cfc';
                }
            }
        }
        

自定义属性 的 操作

 ele.getAttribute("属性名")---------获取自定义(标签属性)属性的属性值
 ele.setAttribute("属性名","属性值")------ 设置(新增,修改)自定义属性
ele.removeAttribute("属性名")-----------删除自定义属性节点

动态创建列表

 var names = ["杨过", "郭靖", "张无忌", "张三丰", "乔峰", "段飞", "丁棚"];
 
 //方法一 使用innerHTML-----字符串思维(所见即所得)

        getId('btn').onclick = function () {

            if (!getId('box').innerText) {  //非空校验  如果盒子内容为空 执行里面的代码
                //getId('box').innerText  false--空   取反  true 执行里面的代码
                var uu = document.createElement('ul');
                getId('box').appendChild(uu);

               for (var i = 0; i < names.length; i++) {

                    uu.innerHTML += '<li>' + names[i] + '</li>';

                 }

            

            }
            
            
            //方法二   用 document.createElement("元素名称")------创建一个元素节点(对象)
             // *** 父元素.appendChild(子元素)------ 将元素添加到DOM中
            
                    getId('btn').onclick = function () {

            if (!getId('box').innerText) {  //非空校验  如果盒子内容为空 执行里面的代码
                //getId('box').innerText  false--空   取反  true 执行里面的代码
                
                var uu = document.createElement('ul');
                getId('box').appendChild(uu);

  				 names.forEach(function(item){   //也可以用forEach()遍历数组   item是数组的项
                    var lis = document.createElement('li');
                    lis.innerText = item;
                       uu.appendChild(lis);

                })

            }


        }

替换和删除节点

 // 需求1:  ul的最前和最后插入新节点

        getId("btn1").onclick = function () {
            // console.log(this);
            // 最前插入新元素节点
            var newLi = document.createElement("li");
            newLi.innerText = "最前插入新元素节点";
            // **** 父元素.insertBefore(新节点,参照节点);  在参照节点之前插入新节点
            getId("uu").insertBefore(newLi, getId("uu").children[0]);
        }
        getId("btn2").onclick = function () {
            // console.log(this);
            // **** 父元素 最后插入新元素节点  appendChild()
            var newLi = document.createElement("li");
            newLi.innerText = "最后插入新元素节点";
            getId("uu").appendChild(newLi);
        }

        // 需求2: 实现 替换节点和删除节点的功能

        var dels = document.getElementsByClassName("del");
        var reps = document.getElementsByClassName("rep");
        
 		 // 替换li (使用新的li 替换 旧的li)
            reps[i].onclick = function () {
                var newLi = document.createElement("li");
                newLi.innerText = "新元素";
                // **** 父元素.replaceChild(新节点,旧节点)------使用新节点替换旧节点
                getId("uu").replaceChild(newLi,this.parentElement);
            }
        }

        for (var i = 0; i < dels.length; i++) {
            // 删除li
            dels[i].onclick = function () {
                // console.log(this.parentElement);
                // ******** 父元素.removeChild(子节点)------节点删除(不能删除自己)
                // 用ul删除li
                getId("uu").removeChild(this.parentElement);
            }

          

day-04

事件的三个阶段

事件的三个阶段
1. 捕获阶段(由外向里)  2.目标阶段    3.冒泡阶段(由里向外)


事件对象 event

事件对象  event  
书写位置   事件执行程序的 形参     有兼容性

btn.onclick = function( e ){
 var e = e || window.event;   //IE8 兼容
	
}

阻止事件冒泡

阻止事件冒泡 

btn.onclick = function( e ){
 var e = e || window.event;   //IE8 兼容
	
	if(e.stopPropagation){
	e.stopPropagation();  //W3C 标准
	}else{
	e.cancelBubble;      //IE8 兼容
	}
}

阻止事件默认行为

//阻止事件默认行为   ---比如 点击按钮刷新了表单页面
        getId("btn").onclick = function (e) { 
            var e = e || window.event;
            if (event.preventDefault) {
                event.preventDefault(); // W3C标准-----IE8不支持
                console.log("preventDefault");
            } else {
                event.returnValue = false; // IE8 特有   亲测火狐有效
                console.log("returnValue");
            }
        }

事件委托

  // 事件委托 e.target     给动态添加的元素绑定事件  
  
        // 需求1: 点击按钮,添加一条 li
        getId("btn").onclick = function () {
            var newLi = document.createElement("li");
            newLi.innerHTML = "新列表<button>按钮</button>"
            getId("uu").appendChild(newLi);
        }
        
        
        // 需求2: 点击li的按钮,获取当前 li 的text
        // e.target 只委托给 页面本来就存在的 父级
        
        getId("uu").onclick = function(e){
            var e = e || window.event;
            var tar = e.target;
             //此时 tar  是 ul  里面 的所有元素对象

            if(tar.nodeName =="BUTTON"){
                // this ---- ul
                // tar------- button
                // tar.parentElement---- li
                console.log(tar.parentElement.innerText);
            }
        }                                                                                                                                                                                                                                                                                                                                                                                           
        
        e.target可以用来实现事件委托,该原理是通过事件冒泡(或者事件捕获)给父元素添加事件监听
        e.target指向引发触发事件的元素

事件监听 – 2级事件

  // 需求:事件监听的第三个参数 
        // addEventListener(参数1,参数2,参数3)
        
/*  参数1:事件类型
    参数2:事件处理程序
    参数3:事件的执行阶段(布尔值)
                true: 捕获阶段执行
                false: 冒泡阶段执行 (默认)
*/


   getId("box").addEventListener("click", function () {
            console.log("第二次点击盒子");
        })  //默认为false 可以不写

事件解绑

btn.onclick = function(){
	console.log('点击成功');
}

//  0级事件解绑
removeBtn.onclick =  function(){
  btn.onclick = null;
}


//  2级事件解绑
  function fn1() {//命名函数
            console.log("第一次点击");
        }

        function fn2() {
            console.log("第二次点击");
        }
        getId("btn").addEventListener("click", fn1);
        getId("btn").addEventListener("click", fn2);


        getId("removeBtn").onclick = function () {
            // 解绑 第一次的 事件绑定
            /*  getId("btn").removeEventListener("click", function () {
                 console.log("第一次点击");
             }) */

            // 问题: 绑定的第一个事件函数 和 解绑的函数不是一个函数 ---- 两个引用地址
            // 注意点: 绑定的函数必须要解绑的函数是同一个引用地址   所以不能用匿名函数,要用命名函数
            getId("btn").removeEventListener("click", fn1);
        }


day 05

吸顶导航案例

  // 需求: 1. 鼠标滚动 滚动的到相应的位置, 吸顶导航停留在顶部,不会随着鼠标滚动而滚动
        //       2. 鼠标回滚的时候, 回滚到相应的位置, 吸顶导航 也回到最初的位置

        // 思路:
        // 1. 页面滚动的事件  window.onscroll = function(){}
        // 2. 监听两个值  1. 初始值  2.内容滚动的值
        // 3. 判断   什么情况下吸顶  什么情况下回到初始位置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        body {
            padding: 0;
            margin: 0;
        }
        #nav {
            width: 100%;
            height: 60px;
            background: pink;
            color: #fff;
            line-height: 60px;
            text-align: center;
            padding: 0;
            margin: 0;
        }
        #nav li{
           
            height: 60px;
          list-style: none;
        }
        .fix {
            position: fixed;
            top: 0;
            left: 0;
        }


    </style>
</head>
<body>
    <div class="boxtent">
        <h2>我要隐藏了</h2>
        <h2>我要隐藏了</h2>
        <h2>我要隐藏了</h2>
        <h2>我要隐藏了</h2>
         <ul id="nav">
            <li>标题、标题、标题、</li>
           
        </ul>
        <div class="box">
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
            <p>滚动内容,,,啦啦啦啦</p>
        </div>
    </div>


    <script>
         //获取标题的id
    var nav_tops = document.querySelector('#nav');
    // 获取导航条距页面顶部的距离
    var titTop = nav_tops.offsetTop;
    console.log('titTop',titTop);
    //设置滚动监听事件
    document.onscroll = function() {
            //获取当前滚动距离 
            var scrollTop= document.body.scrollTop || document.documentElement.scrollTop;//这里是一个兼容 有的浏览器支持body 有的支持documentElement
            //如果滚动距离大于导航条距顶部距离
            console.log('scrollTop',scrollTop);
            if (scrollTop> titTop) {
                    //如果卷进去的距离大于导航栏到顶部的距离的话,导航栏设置fixed 固定在当前位置
                    nav_tops.className = "fix";
            }else {
                    //如果卷进去的距离小于导航栏到顶部的距离的话,设置导航条不是固定定位
                    nav_tops.className = "";
            }
    }

    </script>
</body>
</html>

单次定时器

  // 目的: 学习 单次定时器  的设置和清除的语法
/*
            语法: 
            设置单次定时器: setTimeout(function(){},time)    
            过time时间之后再执行某代码   
            
            清除单次定时器: clearTimeout(name)   name 定时器名称
        */
        
  // 声明定时器名称  一般会用timer
        var timer = setTimeout(function () {   // 异步函数  浏览器加载到这段代码的时候,暂时不执行,满足一定条件之后再执行
            console.log("01-我今天感觉自己突然行了!!!");
        }, 3000)

        // 点击按钮之后   清除单次定时器
        // 一般情况,也不会清除单次定时器
        btn.onclick = function () {
            clearTimeout(timer);
            console.log("02-突然有感觉自己不行了!!!");
        }

循环定时器

  // 目的: 学习  循环定时器  的设置和清除的语法

        /*
            语法:
            设置循环定时器: var timer = setInterval(function(){},time)
                            每隔time的时间,就执行一次函数中的代码段
            清除循环定时器: clearInterval(timer)   timer 定时器名称
        
        */


        // 1. 设置
        var timer = setInterval(function () {
            console.log("我已经js进阶成功!!!");
        }, 1000)


        // 2. 清除
        btn.onclick = function () {
            clearInterval(timer);
            console.log("我要进入更高的阶段了!!!");
        }

随机点名系统

        // 需求:  1. 模拟后台数据   做页面渲染
        //        2. 点击点名按钮之后  光标在 列表内部 随机显示    改掉按钮文字
        //        3. 点击停止按钮之后  光标停留在某个元素上    不再随机闪烁   改掉按钮文字


        // 1. 模拟后台数据   做页面渲染
        //创造虚拟后台数据
        var arrs = ["宋江", "卢俊义", "吴用", "公孙胜", "林冲", "花荣", "鲁智深", "武松", "李逵", "晁盖", "燕青", "潘金莲", "阎婆惜", "关胜", "秦明", "呼延灼", "陈达", "张青", "刘唐", "李俊", "张顺", "高俅", "孙二娘", "戴宗", "朱仝", "方腊", "阮小二", "李瓶儿", "庞春梅", "白胜", "吕方", "董平", "穆春", "宋清", "柴进", "施恩", "李忠", "周通", "杜兴", "时迁", "曹正", "宋万", "杨志", "镇关西", "西门庆"];


        // 1.1 遍历数据
        arrs.forEach(function (item, index) {
            // console.log(item);
            // 1.2 列表渲染
            var divNode = document.createElement("div");
            divNode.innerText = item;
            divNode.className = "name"; //添加设置好样式的对应 类名
            box.appendChild(divNode);
        })


        // 3.2 将tim 变量   初始化timer  一般来说会初始为null
        var timer = null;

        // 2. 点击点名按钮之后  光标在 列表内部 随机显示
        // 2.1 使用开关思想
        var flag = true; // 文字显示 点名 
        btn.onclick = function () {
            // 3.1 预解析
            // var timer;  xxxxx
            // console.log(this.innerText);

            if (flag) {
                // 文字显示 点名 
                console.log("点名业务逻辑");
                // 2.2 光标在 列表内部 随机显示
                // 使用循环定时器
                timer = setInterval(function () {
                    // 2.5 排他思想----初始化----每次进来都没有背景色
                    for (var i = 0; i < arrs.length; i++) {
                        box.children[i].style.background = "";
                    }

                    //2.3 随机显示? random    思路: 光标----背景色     元素列表中随机找一个元素设置背景色
                    // box.children   盒子的子元素集合    索引 --- 随机数
                    // box.children[myIndex] 随机的一个元素   myIndex-----0~length-1之间的随机数
                    var myIndex = Math.floor(Math.random() * arrs.length);
                    // 2.4 设置背景颜色
                    box.children[myIndex].style.background = "red";
                }, 10)


                flag = false;
            } else {
                console.log("停止业务逻辑");
                // 3. 点击停止按钮之后  清除定时器
                clearInterval(timer);
                // 两次点击(点名和停止)
                // console.log(timer);
                flag = true;
            }
            this.innerText = flag ? "点名" : "停止";
        }

js 高级day 1-7

day01

let 声明变量的特点

  <h3>let声明变量的特点(重要)</h3>
    <script>
        // 需求: 使用let解决var的问题

        // 1. 不能先使用,再声明
        /* // console.log(a);
        let a = 10;
        console.log(a); */

        // 2. 不能重复定义一个变量
        /* let a = 10;
        let a = 20; */
    

        // **** 5.let 没有预解析


        // 3. 不会造成全局变量污染的
        for(let i=0;i<5;i++){
            // 将i变成局部变量
            // console.log(i);
        }

        // console.log(i);
        // **** 4.拥有块级作用域(ES6)   {}内的会形成一个作用域
        {
            let a = 10;
        }
        // console.log(a);
    </script>

const 声明常量的特点

    // 需求: 使用 const声明 常量
        // 变量-------可以修改可以变量
        // 常量-------不修改,恒常不变


        // 个人习惯: 常量首字母大写,区分变量,也有人全部大写

        // 1. 不能先使用,再声明(没有预解析)
        /* console.log(Data);
        const Data = 10; */

        // 2. 一旦声明必须赋值
        // const DATA;

        // 3. 赋值之后 不能修改
        /* const DATA = 10;
        DATA = 20; */


        // 4. 拥有块级作用域
        /* {
            const DATA = 10;
            // console.log(DATA);
        }

        console.log(DATA); */
       
 // const声明一个常量,这个常量是引用数据类型(对象,数组,函数....)

        /* 
        为什么不能修改: 因为改变了引用地址
        
        const Arr = [10,20,30];
        Arr = [1,2,3];
        console.log(Arr);// 一旦赋值(引用地址)不能修改 */



        const Arr = [10,20,30];
        Arr[1] = 200;
        console.log(Arr);// 为什么可以修改: 因为引用地址没变过,改的是值

        //**** 特点5. 引用类型的值可以修改

模板字符串

//字符串拼接:   +号 和 ''
 console.log("我叫" + name + ",今年" + age + "岁了,我是一个" + gender + "孩子");

//模板字符串:  反引号`` 和  ${} 
console.log(`我叫${name},今年${age}岁了,我是一个${gender}孩子`)

对象解构

对象解构的语法 ***** 
      
           var obj = {
            name: "骡窝窝",
            age: 1,
            type: "jQuery项目"
        }
//1. 对象解构: 将对象中的值 提取出来,赋值给变量 
//注意点: key要和变量同名才可以解构
       //语法:   let {变量,变量,变量..}  =  对象
 		let {name,age,type} = obj;
		console.log(name,age,type);

//2. 将对象的一部分值赋值给变量--------部分解构
// **** 解构之后重命名  
      //语法:  let {对象对应的key:重命名之后的变量名} = obj;
        let {name:myName} = obj;		
       console.log(myName);

  // 3.解构 内置对象的方法 
        // let {变量} = Math内置对象    {random:fn}
        let { random } = Math;
        console.log(random());

数组解构

let arr = [10,20,30];
//数组解构,将数组中的值赋值给变量
 //语法: let [变量,变量。。。] = arr

//1.完全解构   let [变量,变量] = arr
let [a,b,c]=arr;
console.log(a,b,c);

//2.部分解构 (按顺序--补全逗号---占位)
let [a,b,c,d] =arr;
 console.log(a, b, c, d);// 变量>数组个数--解构失败
//得到undefined  ----10 20 30 undefined

  
    let [, b] = arr;
	 console.log(b);//20
	let [, , c] = arr;
	 console.log(c);//30

        // 3. 复合解构 
        let arr2 = [10, 20, 30, [100, 200, 300]]; // 二维数组

        let [a, b, c, [x, y, z]] = arr2;

        console.log(a, b, c, x, y, z);

// ES6 是为了简化代码, 当你发现不能简化的时候, 用ES5

字符串解构

// 需求:解构一个字符串(本质上和数组解构是一样的)
        // 字符串有索引有长度,不能使用数组方法------本质上是一个伪数组

        let str = "申总好厉害!!";
		let [a,b] = str;
        console.log(a,b);

交换两个变量的值

//ES5写法  设置一个中间变量
var a=10,b=20;
var m = a;
a = b;
b = m;
console.log(a,b);

//ES6写法
let a=10,b=20;
[a,b]=[b,a];
console.log(a,b); // 20 10

对象的简化写法

  // 需求: 将多个变量的打包成一个对象(对象的key和变量名同名)

        let name = "张三",
            age = 20,
            gender = "男";

        function eat() {
            console.log("爱吃螺蛳粉");
        }

        // ES5 写法
       let obj = {
            name: name,
            age: age,
            gender: gender,
            eat: eat,
        } 

        // ES6 对象的简化写法
        // 语法: 如果对象的key和变量名同名,可以只写key不写value
        // 对象解构反向操作
        let obj = {name ,age, gender, eat};
        console.log(obj);

函数设置默认值

 	 function add(a, b, c, d) {
            return a + b + c + d;
      }

        console.log(add(1, 2, 3, 4));// 10
        console.log(add(1, 2));// number+undefined = NaN 


        // ES5 解决方案
        // 函数调用少传参,会出现业务逻辑问题-------短路
         function add(a, b, c, d) {
            a = a || 0;
            b = b || 0;
            c = c || 0;
            d = d || 0;
            return a + b + c + d;
        } 



        // ES6 --------- **** 设置函数参数默认值
        // 语法:  function fn(形参 = 默认值){}   当形参是undefined时候,赋值为默认值
        function add(a=0, b=0, c=0, d=0) {
            return a + b + c + d;
        }
        console.log(add(1, 2, 3, 4)); // 10
        console.log(add(1, 2)); //3

对函数参数进行解构赋值

 // 终极需求: 实现$.ajax的传参方式----想办法创建一个这样的函数,并获取参数(url,type)
        /* $.ajax({
            type:"",
            url:"",
            data:{}
        }) */


        // 1. 数组参数解构------顺序
        function fn([x, y, z]) {
            // 不加[]-------相当于 let x = arr ,y,z 
            // 加了[]-------相当于 let [x, y, z] = arr;
            console.log(x, y, z);
        }
        fn([10, 20, 30]); 


        // 2. 对象参数解构------无序
        function ajaxFn({url,type,data}){
            // 加了{}------相当于 let {url,type,data} = obj
            console.log(url,type,data);
        }

        ajaxFn({
            type:"GET",
            data:{name:"张三"},
            url:"xxxx"
        })

参数的解构赋值 —解决报错的问题

function ajax({url='xxx.com',type='GET',data={}} = {}){
	console.log(url,type,data);
}
  ajaxFn();
  // 需求: 解决 函数参数解构赋值  报错问题 
   		// 如果不传参-----相当于 let {url,type,data} = undefined   报错
            // 1. 如果传参{}-----相当于 let {url,type,data} = {}  ---- **解决报错** 
            //             -----  设置默认值{}  得到 三个 undefined
            // 2. 解决 undefined 问题 -------  给每个参数都设置默认值

rest 参数 基本语法

 // 需求: 解决实参>形参的问题

//剩余参数设置
        // ES5: 使用arguments
        function add(a,b,c) {
            // console.log(arguments);
            var sum = 0;
            for(var i=0;i<arguments.length;i++){
                sum+=arguments[i];
            }
            console.log(sum);
        }
        add(10, 20, 30, 40, 50); 


        // ES6: rest参数
         /* 注意点: 1. rest得到的是真数组 
                2. 重点是...   不是rest, rest只是一个叫法
                3. 可以获取剩余参数
                4. Rest参数必须是最后一个形参 */
    
        function add(...rest){
            // console.log(rest);// 转化为一个真数组[10, 20, 30, 40, 50]
            let sum = 0;
            rest.forEach(function(item){
                sum+=item
            })
            console.log(sum);
        }
		add(10, 20, 30, 40, 50); 

      

       
        // 获取剩余参数
         function fn(a,...b){
            console.log(a,b);
        }
        fn(1,2,3); 


        // 剩余参数 放在中间---报错
        function fn(a, ...b, c) {
            console.log(a, b, c);
        }
        fn(1, 2, 3, 4, 5, 6, 7, 8, 9);//报错

拓展运算符,

也叫rest运算符,俗称叫“尾巴”解构

数组合并,对象合并

 // 拓展运算符: 将数组或对象中的值一个一个的拿出来
        let arr = [10, 20, 30];
        console.log(...arr);

        let obj = {
            name: "张三",
            age: 20
        };
        // ...obj-------->name:"张三",age:20
        console.log(...obj);


        let str = "abc";
        // ...str------>"a","b","c"
        console.log(...str);




        // 使用场景:
        // 1. 函数传参使用拓展运算符

        /* function fn(a,b,c){
            console.log(a,b,c);
        }

        fn(...arr); */


        // console.log(Math.max(10,20,80));
        // console.log(Math.max(...arr));


        // 2. 合并数组
        let arr1 = [1, 2, 3];
        let arr2 = [10, 20, 30];
        let newArr = [...arr1, ...arr2];
        // 不影响原数组
        newArr[2] = 300;
        // console.log(newArr);
        // console.log(arr1);


        // 3. 对象合并
        let obj1 = {
            name: "张三1",
            age: 20,
            gender: "男"
        }

        let obj2 = {
            name: "张三2",
            email: "zhangsan@163.com"
        }

        // 拓展运算符
        let newObj1 = {...obj1,...obj2};
        // *** 注意点: 对象的key不能重复的,后面的会覆盖前面的,比如name

        // Object.assign key做对象的合并, 将第二个以及后面的对象参数合并到第一个对象参数中
        // let newObj2 = Object.assign({}, obj2, obj1);
        // 第一个参数传{}目的: 不改变原对象
        let newObj2 = Object.assign(obj2, obj1);
        // console.log(newObj1);
        // console.log(newObj2);



        // 4. 在解构赋值中使用
        // 在解构赋值中,可以获取数组或字符串解构中剩余的值(不是rest参数)
        let arrx = [10,20,30,40,50,60,70,80,90];
        let [a,b,c,...d] = arrx;
        console.log(a,b,c,d);

        let strx = "申总好厉害!!!";
        let [x,y,...z] = strx;
        console.log(x,y,z);



合并数组
let a =[1,2,3];
let b = [4,5,6];
let c =[…a , …b];
console.log(c); // [1,2,3,4,5,6]

字符串转为数组
[ …‘siva’ ] // [‘s’,‘i’,‘v’,‘a’]

浅拷贝
//数组
var a = [1,2,4];
var b = […a];
a.push(6);
console.log(b); //[1,2,4]

//对象
var a= {a:1};
var b ={…a};
a.a =5 ;
console.log(b.a); //1

day02

箭头函数

	    箭头函数写法的注意点:
        1. 函数体只有一句话,可以省略{}不写
        2. 函数体只有一句话(并且要返回), {}和return都可以不写
        3. 函数只有一个参数,可以省略()不写
        4. 反之,多个参数,多行函数体----肯定不能简写
        5. ****如果需要返回一个对象,不能简写(函数的{}和对象的{}打起来了)
        6. ****arguments在箭头函数中不能使用,但是可以使用rest参数


   
        // 1. 无参无返
        let fn1 = () => console.log("今天是个靓仔");
        fn1();

        // 2. 无参有返
        let fn2 = () => "靓仔";
        console.log(fn2());

        // 3. 有一个参数的函数
        let fn3 = a=>console.log(a);
        fn3(3);


        // 4. 多参数,多行函数体,还有返回
        let fn4 = (x,y)=>{
            let sum = x+y;
            return sum;
        }
        console.log(fn4(1,2));

        // 5. 返回一个对象
        /*
            预期的返回数据类型
            {
                x:1,
                y:2
            }
        */
        let fn5 = (a,b)=>{
            return {x:a,y:b};
        }
        console.log(fn5(1,2));

        // 6. arguments的使用
        // let fn6 = ()=>{
        //     console.log(arguments);//报错
        // }
        let fn6 = (...a)=>{
            console.log(a);
        }
        fn6(1,2,3,4,5);

this 指向

1.全局指向window

2.对象中----- 指向该对象,只有对象方法调用,函数作用域内的this才指向对象;

事件中—指向事件源

3.箭头函数中----指向外层作用域

4.构造函数 ------指向该实例对象指向的引用地址

5.call,apply 方法 ----指向借用的对象

Promise

Promise 的三个状态:

默认 pending

成功 resolve( ) ------> fulfilled

失败 reject ( ) ------> rejected

语法:
var flag = true;
var p = new Promise((resolve,reject)=>{
	if(flag){
		resolve('成功返回')
	}else{
		reject('抛出异常')
})

p.then(data=>{
	console.log(data);
}).catch(error=>{
	console.log(error);
})

/*
promise的两个方法 all  race

1. Promise.all([多个Promise对象])   
应用场景: 页面一进来,就要加载三个ajax,只有三个全部成功,才可以渲染页面 -----类似于&&
特点: 
     1.1 如果多个异步程序都是成功状态, p的状态就是成功, 多个异步程序的成功结果会打包成一个数组统一返回
     1.2 但凡发现一个失败,最快得到失败结果的直接返回
     
2. Promise.race([多个Promise对象])  ----- 类似于||
 特点:  谁快返回谁 */
	 

用promise 解决回调地狱

 
        // 如何解决回调地狱----将异步代码改成看起来像同步代码(方便维护)
        p1.then(data1=>{
            console.log(data1);
            return p2; //返回下一个 实例对象
        }).then(data2=>{
            console.log(data2);
            return p3
        }).then(data3=>{
            console.log(data3);
        }).catch(err=>{
            console.log(err.responseText);
        })

promise方法

Promise.all

返回结果由参数(Promise实例的结果)决定,分成两种情况。

(1)只有所有的实例fulfilled,返回才会变成 fulfilled

(2)只要实例有一个rejected返回的状态就变成 rejected`

Promise.race

返回结果跟随最快返回的那个实例的结果

Promise.any

接受一个数组包括多个Promise实例作为参数,返回新的Promise实例,只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态。如果所有参数实例都会变成rejected状态,包装实例就会变成rejected状态。

Promise.allSettled

接受一个数组包括多个Promise实例作为参数,返回传入的Promise的状态。相比于Promise的all方法,可以获取成功或失败的所有状态,因为Promise的all方法遇到一个rejected就会立即停止。

Set 和Map数据结构

new Set ()

  • Set 本身是一个构造函数,用来生成Set数据结构

  • Set 类似于数组,成员的值时唯一的

//Set 数组去重、遍历数组

let arr = new Set([1,2]);
arr.size; //2  得到数组成员数量 

操作方法(操作数据)

add (value)   //添加某个值到数组中
delete (value)  //删除某个值,返回布尔值
has (value)     //判断是否为Set的成员
clear()  //清除所有成员

遍历方法(遍历成员)

keys() //返回所有键名
values() //返回键值的遍历器
entries() //返回键值对
forEach() //使用回调函数遍历每个成员

new Map()

  • Map本身也是一个构造函数,用来生成Map数据结构。

  • Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。

方法和Set 类似

day 03

自定义构造函数:

  1. 使用大驼峰命名(必须首字母大写(可以小写开头(几乎没人这样)));
  2. 不需要手动创建对象
  3. 通过 this(实例对象) 进行添加成员
  4. 不需要手动返回, 会自动返回
  5. 必须搭配 new 关键字进行实例化

自定义构造函数是如何创建对象的?(也叫new关键字做了什么

1.构造函数内部自动,默认创建了一个空对象 var obj = {};

2.把这个空对象赋值给了this    this=obj;

3.p. __proto__=Person.prototype; 
将构造函数的 prototype 赋值给 实例对象的__proto__;

4.给this身上添加成员  this.xxx = xxxx;
5.自动返回了this 

对 对象进行分类

  		// 人类
        function Person(name, age) {
            this.name = name; 
        }
        // 狗类
        function Dog(name, age) {
            this.name = name;
        }

        var p = new Person("申五");
        var d = new Dog("旺财");

        console.log(p, d);


        // 如何分类: 
        // 1. constructor 属性  获取 构造函数(又叫构造器)
        console.log(p.constructor === Person);//true

        // 2.instanceof 关键字  判断类型
        // a instanceof b   判断a(对象)的类型是不是b(构造函数) 返回布尔值
        console.log(p instanceof Person);// true
        console.log(d instanceof Person);// false
      

获取原型对象的 方式

1.实例对象.__proto__
2.构造函数.prototype
3.Object.getPrototypeOf(实例对象)

原型对象相关概念

  // 对象的成员有属性和方法
        // 1. 构造函数----构造器(类)----创建对象用---------母亲
        function Person(name, age) {
            // 5. 实例成员-----name age
            this.name = name;
            this.age = age;
        }

        // 2. 原型对象----构造函数与生俱来的对象(夫妻)-----父亲
        // Person.prototype    函数对象身上的属性prototype
        // console.dir(Person);

        // 6. 原型成员-----eat
        Person.prototype.eat = function () {
            console.log(this.name + "爱吃木桶饭");
        }

        // 3. 实例对象: 构造函数创建出来的新对象p
        // 4. 实例化: new的过程 构造函数创建实例对象的过程
        var p = new Person("张三", 20);


        // 7. 静态成员-------- 给构造函数身上添加的成员
        Person.showInfo = "这是一个人类";
        // console.log(p.showInfo);// 实例不能使用静态成员
        console.log(Person.showInfo);// *** 静态成员只能给构造函数使用

        // 之前接触过吗????
        // Object.assign()-----Object构造函数的静态成员方法

day 04

原型链访问规则:

原型链访问规则: 顺着__proto__往上去查找,父亲身上找不到,去爷爷身上去找.....

	1. 整个原型链都找不到  得到 undefined

	2. 就近原则(爸爸身上有,就不去爷爷身上找了;自己身上有,哪都不找)

完整的原型链结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1ms8c9E-1649943311958)(C:\Users\Administrator\Desktop\A截图\Snipaste_2022-03-21_14-42-33.png)]

day 06

异常捕获结构

 // js的代码错误: 
        // 1. 语法问题,浏览器报错
        // console.log(a);// 报错
        // 2. 逻辑错误, 浏览器不报错
        // console.log(2==2==1);

        // 异常处理1----即使报错,也不影响代码运行

        /* try{
            // 可能会出错的代码
            console.log(a);
        }catch(e){
            // 异常的捕获
            //e 是错误信息 error
            console.log(e);
        }finally{
            console.log("不管怎么,都要运行");
        } */

        // 异常处理2------业务逻辑的问题

        // 需求: 判断 函数的参数是不是数字,不是则报错(抛出异常)

        function fn(num){
            if(typeof num !== "number"){
                // 主动抛出异常 throw
                throw "数据类型错误";
            }else{
                console.log(num);
            }
        }

        // fn("1");

        try{
            fn("1");
        }catch(e){
            // console.log(e);
            if(e=="数据类型错误"){
                alert("隔壁的老弟啥也不是!!!")
            }
        }

严格模式

 "use strict";
 /*必须写在第一行
 1.严格模式下,不能未声明就赋值
 2.有作用域  严格模式写在全局,全局生效,写在局部作用域,局部作用域生效
 3.严格模式下,this禁止指向window  ---undefined
 */
 
 //a=10; //报错
  function fn1() {
            // "use strict";
            x = 1;
            console.log(x);
        }
        fn1();
        
         function fn(){
            console.log(this); //undefined
        }
        // console.log(this);

        fn();

立即执行函数

//立即执行函数,本质上将函数变为函数表达式直接调用
 // 优点: 1. 初始化变量(防止全局变量的污染)  
 //2.全局变量私有化(创建独立作用域)
 // 需求: 点击不同的按钮,显示对应的索引
  
 
 /*  var btns = document.getElementsByTagName("button");
        for (var i = 0; i < btns.length; i++) {
            btns[i].myIndex = i; //添加属性 = i  ------ 这一步相当于 存索引
            btns[i].οnclick=function(){
                // console.log(i);
                console.log(this.myIndex);
            }
        } */


        // 使用立即执行函数解决
        var btns = document.getElementsByTagName("button");
        for (var i = 0; i < btns.length; i++) {
            // 每一次循环,都会创建一个独立的作用域
            // 功能: 全局变量私有化
            (function (ii) {
                btns[ii].onclick = function () {
                    console.log(ii);
                }
            })(i)// 实参
        }

闭包

//闭包:函数中返回一个函数的结构
/* 特点
 1. 防止全局变量的污染
 2. 保护了私有变量的安全,不会被修改
 3. 让函数外部访问局部变量成为可能,打破了作用域的限制,延迟了变量的生命周期
 4. 会造成内层泄露的问题(有一块内存永远被占用不会释放) */
 function fn(){
            var a = 10;
            return function(){
                return a
            }
        }
    var x =  fn();
     console.log(x());
    // console.log(fn()()); //第一个调用外面函数  第二个调用里面的函数
            

定时器和闭包

  // 每隔一秒打印1~10
        for(var i = 1;i<11;i++){
            // 定时器 参数设置---- 第三个及以后的参数都是传给第一个函数的参数
            // 定时器允许传参接受第三个及以上的参数
            // 第三个及以上的参数都是传给第一个函数的参数
            // setTimeout(fn,time,a,b....)
            setTimeout(fn(),1000*i,i)
        }
        // 闭包---函数内部返回一个函数的结构
        function fn(ii){
            return function(ii){
                console.log(ii);
            }
        }

DOM操作和闭包

 // 需求: 点击不同的按钮,显示对应的索引
        var btns = document.getElementsByTagName("button");
        for (var i = 0; i < btns.length; i++) {
            //for  同步
            // 点击事件是异步的
            btns[i].onclick=fn(i);
        }
        // 闭包: 打破了作用域的限制
        function fn(ii){
            return function(){
                // 异步
                console.log(ii);
            }
        }

递归

//递归: 函数中调用函数自己的结构
 var i =0;
        function fn (){
            i++
            if (i<6){//入口
                console.log('天气真好');
                fn();
            }//出口
        }
        fn();
        

递归阶乘

//阶乘的递归
// 阶乘 : 3!  3*2*1
// 求n 的阶乘(函数封装)
        function fn(n) {
            // 需要一个出口
            if (n <= 1) { 
                return 1;
            }
            return n*fn(n-1)//入口
            //3*fn(3-1)---3*2*fn(2-1)---3*2*1*fn(1-1)//n=1 return  1
        }

        console.log(fn(3));

关于深拷贝和浅拷贝

1)浅拷贝

    • Object.assign() 该方法用于对象复制时,也是浅拷贝
    • 数组的slice方法、concat方法、Array.from方法以及扩展运算符都算是浅拷贝

2)深拷贝

    • 递归方案 经典的方案 (其实就是通过循环一层一层的进行拷贝)
    • JSON.parse()方法 这个方案简单易懂,不过也有缺点,对于undefined、function、symbol 会在转换过程中被忽略

深拷贝

    var obj = {
            name:'张三',
            age:23,
            faves:['打球','听音乐','跑步'],
            wife:{
                name:'李四',
                age:20,
                faves:['爱马仕','古驰','香奈儿']
            }
        }
        var obj2 ={};
  // 浅拷贝
        /*    for(var k in obj){
               obj2[k]=obj[k];
           }

           obj2.wife.age = 30; //一改全改
           console.log(obj);
           console.log(obj2); */


        function deepCopy(cur,tar){
            for(var k in cur){//1.遍历对象cur ----obj
                if(cur.hasOwnProperty(k)){//2.获取 构造函数里面的实例成员
                    // console.log(k); name age faves wife
                    if(typeof cur[k]==='object'){ //3.判断基本数据类型 和复杂(引用)数据类型
                        // console.log(k); //faves wife
                        tar[k]= Array.isArray(cur[k])?[]:{}; 
                        deepCopy(cur[k],tar[k]); //调用函数 判断 faves wife里面的实例成员
                       
                    }else{
                       tar[k]=cur[k]; //name,age
                      
                    }
                }
            }
        }
        deepCopy(obj,obj2)
        obj2.wife.age =30;
        console.log(obj,obj2);

冒泡排序算法

var  arr = [1,7,3,267,9];
for(var i=0;i<arr.length-1;i++){
	for(var j=i+1;j<arr.length;j++){
		if(arr[i]<arr[j]){
			[arr[i].arr[j]]=[arr[j].arr[i]];
		}
	}
}
console.log(arr);

sort 方法排序

    // js封装好的一种排序方法
    
        console.dir(Array);
        // sort Array的原型方法------可以给数组的所有实例使用
    
        // 真 sort 排序--------工作要用
        var arr = [2, 5, 1, 4547, 3];
        var newArr = arr.sort((a,b)=>{
            // 升序  a-b
            // return a-b;
            // 降序
            return b-a;
        })
        console.log(newArr);

day 07

正则

 // 正则: 编程语言的常识-----数组,对象
        // 正则表达式本质上是对象
        // 用来创建规则校验字符串

        // 创建一: 内置构造函数创建
         let reg = new RegExp("a");
        // console.log(typeof reg);// 实例对象

        // 创建二: 字面量创建   /正则表达式/
        let reg = /a/i;
        /*
            修饰符(很少用): 
            i 忽略大小写
            m 多行匹配
            g 全局匹配

            \d  取数字
            \D  取不是数字的
            \w  取数字、字母
            \W  取不是数字字母的
            \s  取空格
            \S  取不是空格
*/

		// 手机号码校验 以1开头 第2个数3-9  第3~11位 0-9	
        var reg = /^1[3-9][0-9]{9}$/;
        console.log(reg.test('13523343455')); //true
        console.log(reg.test('12455656777')); //false
        console.log(reg.test('1331235346'));   //false

        // 十六进制 颜色 校验
        // 一共7个字符 以#开头    后面六个字符是 十六进制 0-9a-fA-F
        var reg1 = /^#[ 0-9a-fA-F]{6}$/;
        console.log(reg1.test('#cececf'));//true
        console.log(reg1.test('ccececf'));//false
        console.log(reg1.test('#cecech'));//false

执行栈

 // 执行栈的调用规则: 先入后出  (包括栈内存也是先入后出,堆内存是列队----先入先出)
        // 也叫执行环境的   入栈(压栈) 和 出栈(弹栈)

任务列队

   // 任务列队-------先入先出

        setTimeout(() => {
            console.log("定时器1");
            // 定时器3 再500ms之后进入列队,此时 定时器2只剩500ms
            // 如果定时器时间相同----先入先出
            setTimeout(() => {
                console.log("定时器3");
            }, 400)
        }, 500)
        // 
        setTimeout(() => {
            console.log("定时器2");
        }, 1000)

        // 先执行同步再执行异步---------js的单线程
        // for (var i = 0; i < 10000; i++) {
        //     console.log("同步");
        // }

node

day01

node环境安装

方法一: 直接安装

Node官网 或者 民间翻译更好的网站 下载安装

方法二: nvm方式安装 (比较推荐)

NVM(Node version Manager) 一个用于管理Node多版本的工具。

实现快速切换node版本的需求

  1. 下载nvm安装包

然后直接安装(如果自己之前安装过node,需要先卸载之前安装的node)

双击安装包,选择接受accept ,第一个目录必须是中文(可以自己选择目录),然后电脑 win + R 建打开,输入nvm version 得到版本号就说明安装成功。

  1. 设置nvm的镜像地址

    打开nvm的安装目录,打开里面的settings.txt,可以对里面的镜像地址进行设置,可以把下面的两行复制到最后

    node_mirror: https://npm.taobao.org/mirrors/node/
    npm_mirror: https://npm.taobao.org/mirrors/npm/
    

    因为默认情况下,nvm帮我们下载node环境的时候会到国外的地址下载,我们可以手动改为国内的。不过有时候国内的镜像有时候会崩,如果下载过慢,也可以尝试把这两行删除,再重新下载。

    不行让别人发一份放在nvm的安装目录 也可以使用

    1. 使用nvm 安装node

      win + R 输入cmd (命令行工具)

      nvm install node版本号

    nvm install 14.18.2
    

    依然在cmd 输入 nvm list查看已经安装的版本

    切换使用需要的版本 nvm use 指定版本号

    nvm use 14.18.2
    

    此时在cmd里面输入 node -v 就可以查看当前的node版本

    总结:

    1. nvm是一个版本管理工具,安装的时候不能安装在中文目录下
    2. nvm主要命令
      1. nvm version 查看nvm版本
      2. nvm list 查看当前安装的所有node版本
      3. nvm install node版本 安装指定版本的node环境
      4. nvm use node版本 切换指定版本的node环境
    3. 如果下载过慢可以自己更改镜像地址,也可以向同桌要一份已经下载好的

day 02

模块化:以功能为界限,将代码切割为多个js 文件。

作用:提高代码的复用性、扩展性、可维护性。

模块化 在js的发展中 出现过4个标准:AMD 、CMD 、CommonJS、ES Module(ES6)

CommonJS模块化

导出:
module.exports = { 导出的数据 }
或者
module.exports.键 = 导出的数据
或者
exports.键 = 导出的数据

导入:
const 模块名 = require('模块'

ES Module(ES6模块化)

导出:
export default 要导出的对象 // 默认导出  只能写一次
export  { 数据 }    // 按需导出

导入:
import 模块名 from '模块或者路径'   //默认导入
import {数据 , 数据 ...} from '模块或者路径'   // 按需导入
import  默认,{按需} from  '模块或路径'     // 混合导入

例如

导出

// 默认导出
export default add

// 按需导出
export { add , reduce }

function add(a,b) { return a + b }
function reduce(a,b) { return a - b }

导入

// 默认导入
import fn from './a.js'
// 按需导入
import {add} from 'a.js'
// 混合导入
import fn,{add,reduce} from './a.js'

npm (包管理工具)

node中自带的包管理工具叫 NPM(Node Package Manager),其实说白了无非也是一个软件,只是我们在安装Node的时候就已经"捆绑"安装了。只需要在cmd中输入 npm -v 就能看到当前的npm的版本号。

作用

  1. 下载并管理项目中使用到的第三方式模块(包)
  2. 发布自己的模块到npmjs平台

使用

步骤1:初始化项目

在一个项目中初次使用npm,需要先交项目初始化。在自己项目的根目录,打开终端,输入

npm init -y

会得到一个package.json文件,文件描述了我们整个node项目的基本信息。

步骤2:下载需要使用的第三方模块

npm install 模块名称
例如:
npm install colors

下载完成我们会发现在根目录下多了一个node_modules文件,里面就是我们下载下来的模块。

步骤3:在https://npmjs.com 查找对应的文档学习如何使用下载下来的模块。

npm安装模式

npm安装第三方模块有三种方式:

1.全局依赖方式 - npm install -g   一次安装,在任何项目都能用,一般是方便项目构建的工具

2.生产依赖方式 - npm install -S   上线需要依赖的模块 比如jquey

3.开发依赖方式 - npm install -D   只是在开发的时候使用的模块,上线不需要使用 比如color,less

nodemon 工具 : 可以在我们保存代码的时候就自动重启代码

安装nodemon

npm install -g nodemon

如果报错显示:nodemon 无法加载文件XXX,因为此系统上禁止运行脚本:

1.以管理员身份打开Windows PowerShell

  1. 输入 set-ExecutionPolicy RemoteSigned 命令

3.选择 A 或者 Y

4.重新运行nodemon,就会发现已经运行成功了。

全局安装了nodemon后,只需要把node命令换成nodemon即可

yarn (包管理工具)

Yarn 是于 2016 年 10 月 由 Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具,旨在取代 npm 这种包管理工具。

官网:
https://yarnpkg.com/en/docs

中文参考链接:
https://yarn.bootcss.com/

特点

  • 速度超快

yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。

  • 超级安全

在执行代码之前,yarn 会通过算法校验每个安装包的完整性。

  • 超级可靠

使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的工作。

安装:

管理员模式运行cmd :npm install -g yarn

常用命令

npmyarn
npm init -yyarn init -y
npm install react --saveyarn add react
npm uninstall react --saveyarn remove react
npm install react --save-devyarn add react --dev
npm update --saveyarn upgrade
npm install -g nodemonyarn global add nodemon

yarn 全局安装后,命令不生效

背景:

  1. 执行 yarn global add nodemon 后,重启 bash…`, vue 命令依然不生效
  2. 而 npm 全局安装(npm install -g nodemon)后,命令生效

解决办法:

1.执行如下命令,得出 yarn 全局安装的命令所处的安装目录

yarn global bin 

2.复制安装目录至电脑的环境变量中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z4z6pOvO-1649943311960)(F:/叩丁狼/06-nodejs/211224Node第二天/笔记/assets/2018110718150477.png)]

3.重新启动终端,发现全局命令行可以生效了

yarn和npm的对比

  • 速度

      npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。
    
      而 Yarn 是同步执行所有任务,提高了性能。
    
  • 安装版本统一

     Yarn 默认会生成这样的锁定文件
    
     npm 要通过 shrinkwrap 命令生成 npm-shrinkwrap.json 文件,只有当这个文件存在的时候,packages 版本信息才会被记录和更新。
    
     npm5.0之后新增了类似yarn.lock的 package-lock.json。如果软件包的根目录中同时存在package-lock.json和npm-shrinkwrap.json,package-lock.json将被完全忽略。
    
  • 更简洁的输出

    npm 的输出信息比较冗长。在执行 npm install <package> 的时候,命令行里会不断地打印出所有被安装上的依赖。
    
    Yarn 简洁太多:默认情况下,结合了 emoji直观且直接地打印出必要的信息,也提供了一些命令供开发者查询额外的安装信息。
    

package.json 文件

我们发现使用yarn和npm,都要先把项目初始化,而初始化的结果就是生成一个package.json文件。这个文件到底有什么用?

  1. 记录了你这个项目的主要信息
  2. 可以明确项目的依赖,将来即使把node_modules删除了,也可以通过这个文件找回
  3. 声明简短 的命令,来代替复杂的命令

小结:

  1. 包管理工具是我们在后面的学习,以后的工具中一定会用到的,所以一定要会使用
  2. 每个项目一定要检查有没有 package.json ,如果没有,一定要先 创建一个 package.json npm init -y
  3. node_modules文件夹里面就是我们下载的第三方模块,在传输代码的时候要记得排除这部分
  4. 将来在工作中,yarn或者npm都可能会使用,要熟悉对应的命令
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值