前端自学之路( JS 上 )

103 阅读13分钟

初识JS

前端三层

结构层 :html,搭建结构,放置部件,描述语义

样式层:css ,美化页面,实现布局

行为层:javaScript,, 实现交互效果,数据收发,表单验证等

javaScript体系:语言核心(ECMASCript5,6,7,8,9); 页面文档对象模型 dom ;

浏览器对象模型 bom

js注释

单行注释 ctrl+/

多行注释 默认 shift+alt +a

认识输出语句

  • 1 ; alert( '慕课网')

alert() 是内置函数,函数就是功能的封装,调用函数需要使用圆括号

慕课网是函数的参数,因为是字符串,所以用引号

  • 2 ; console.log('慕课网')

console是js的内置对象,通过’打点‘ 可以调用他内置的 log ‘方法’

所谓方法就是对象能够调用的函数

学会处理报错,控制台

变量

第一步声明他,并且赋值

变量相当于一个容器

var a=5

注意:

  • var为关键字定义变量 (定义变量 要写var) 等号表示赋值(不是相等) 把5 赋予a

  • 变量使用时不能使用引号

  • console.log(a);

  • 变量的合法命名:只能由字母,数字,下划线,美元符号$组成,不能以数字开头;

  • 不能是关键字和保留字;小写a与A是两个不同的变量

  • 优秀的变量命名法:驼峰命名法, c风格(下划线)

变量声明提升:你可以提前使用一个稍后才声明的变量,而不引发异常

注意 变量声明提升只提升定义,不提升值,,所以输出undefined,

是javascript的特性

基本数据类型

number , string ,boolean ,undefined和 null

1,使用typeof 运算符可以 检测 值或者 变量的类型

用法:console.log(typeof 变量)

number()

数字类型:所有数字不分大小,不分整浮,不分正负,都是数字类型

一个特殊的数字类型值NaN: 在数学运算中,若结果不能得到数字,其结果往往都是NaN,它有一个

奇怪的性质;

任何涉及NaN操作,都会返回NaN,NaN与任何值都不相等,包括自身

isNaN( n)

功能:检测n是否为 非数值

返回的值:boolean 不是真就是假

参数n 可以是任何类型

说明:isNaN() 对接收的参数,先尝试转换为数值,再检测是否为非数值

数值转换; 有三个函数可以把 非数值 转为 数值

Number() parseInt() parseFloat()

说明:

  • Number()可以用于 任何数据类型 强制转换

  • 而parseInt() parsefloat()则专门用于把字符串转换为 数值

  • parseInt() 提取内容,必须以数字开头,若不是,打印结果为NaN,取整数

  • parsefloat 取浮点数 ,提取第一个小数点的值

undefined类型

定义:只有一个值,即特殊的undefined ,声明了一个变量,没有赋值,那么他的类型就是undefined

null 类型

  • 1,null值表示一个空对象指针
  • 2,如果定义的变量准备在将来用于保存对象,那么最好将变量初始化设为null而不是其他值
  • 说明:undefined值派生自null值,所以 undefined==null的返回结果为 true

String类型

转换为字符串方法:

toString()

语法:str.toString()

返回值:str的一个副本

参数:str是要转换的内容,可以是数值,布尔值,对象,和字符串

说明:在不知道要转换的值是不是 null或undefined的情况下,还可以用

Striing()函数,能够将 任何类型的值 强制转换为字符串

字符串必须放在引号内


Boolean类型

用于表示真假的类型,只有两个值,即true表示真,false表示假

强制转换;Boolean()

  • 1,除0之外的所有数字,转换为布尔型都为 true
  • 2, 所有 字符串中,除 “” 空字符串 转为布尔型都为true , “ ” 空格字符串转布尔型也为true
  • 3,null和undefined这些类型转为布尔型为false

算数操作符

什么是表达式:

将同类型的数据(如常量,变量,函数等),用运算符号按一定的规则连接起来的,有意义的式子称为表达式

算数操作符 中的 递增和递减

1,递增

++a与a++都是对a进行递增操作

区别:++a先返回递增之后的 a 的值

a++先返回a的原值,再返回递增之后的值

例子 var num1=10,num2=20,

num3=++num1+num2

console.log(num1); // 11

console.log(num3); // 31

2,递减同理

var num1=10,num2=20,

num3= --num1+num2--

console.log(num1); // 9

console.log(num3); // 29

赋值操作符:var a=10 , b=20, str='hello'

a+=5 ; // 等价于 a=a+5

b%=4; //等价于 b=b%4

str=str+'world' //hello world

操作数是数字,加号则是 相加

操作数是字符串,加号则是 连接作用

其他的操作符

三元操作符

语法:条件?执行代码1:执行代码2

说明:可代替简单的 if 语句

如果条件成立,执行代码1,否则执行代码2

例子;var a=3,

b=(a<5)? alert('yes'):alert('none')

逻辑操作符: &&(与); ||(或); !(非)

&&(与)

(只要有一个条件不成立,返回 false)可理解为 并且

说明:在有一个操作数不是布尔值的情况,逻辑与 操作就不一定返回值

(可以操作任何类型的数据 ,操作布尔值则返回布尔值)

此时遵循的规律:

1,如果第一个操作数 隐式类型 转换布尔型 后为 true ,则返回第二个操作数

例如 console.log( "abc" && 50 )则返回 50

2如果第一个操作数 隐式类型 转换布尔型 后为 false,则返回第一个操作数;

例如 console.log( 0 && 50 ) 返回0

3,如果有一个操作数是 null 则返回 null

4,如果有一个操作数是 undefined,则返回 undefined

5,如果有一个操作数是 NaN,则返回 NaN

逻辑或

||(或) 只要有一个条件成立,返回 true

例子 console.log(55>60 || 33<60); // true

console.log( 55!="55" || 88 =="88") // true

说明:在有一个操作数不是布尔值的情况,逻辑与 操作就不一定返回值,

此时遵循的规则:

console.log( "hello" || 0) // 返回 hello

1,如果第一个操作数 隐式转换布尔值 为true,则返回第一操作数,不会再继续向下转换

console.log( "" || 88 || true) // 返回 88

2,如果第一个转换后 值 为false,则返回 第二个操作数

3,如果两个操作数是 null 则返回 null

4,如果两个操作数是 undefined,则返回 undefined

5,如果;两个操作数是 NaN,则返回 NaN

跟与 不一样,,

逻辑 非

!非 :相当于否定的意思,只有两种结果, !false=true ; !true=false

说明:1,无论操作数是什么数据类型,逻辑非都会返回一个 布尔值

字符串对象 String

            // 加号可以拼接多个 字符串;也可以与变量拼接

        var mukecom = 'mu' + 'ke';

        console.log(mukecom);

        var a = 10;

        var str = '我买了' + a + '个苹果';

        console.log(str);

        // 字符串的length属性表示 他的长度

        console.log(str.length);

String常用方法
str.substring()

        // str.substring(a,b)得到从 下标a开始到b(不包含b) 的子字符串

        // 如果省略第二个参数b则 从a开始截取到最后,参数a可以大于b,他会自动调整位置

        // 参数a不能为负数

str.substr()

        //    str.substr(a,b) 得到从 下标a开始 的长度为b 的子串(提取指定数目的子串)

        // a可以为负数 -1则为最后一个;-2则为倒数第二个;

str.slice()

        // str.slice(a,b) 得到从 下标a开始到b(不包含b) 的子字符串

        // a可以为负数

        // str.slice(-4,-1)则表示截取倒数第四位到 倒数第一位(不包含倒数第一)的子串

        // 参数a必须大于参数b

str.toUpperCase()

    // str.toUpperCase()  转为大写

str.toLowerCase()

    // str.toLowerCase()  转为小写

str.charAt()

charAt() 方法可返回指定位置的字符

第一个字符位置为 0, 第二个字符位置为 1,以此类推

str.indexOf()

indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置

如果没有找到匹配的字符串则返回 -1

str.split()

split() 方法将字符串分割为字符串数组,并返回此数组。

使用指定符号分割字符串,代码如下:

  • var mystr = "www.imooc.com";
  • document.write(mystr.split("."));
  • document.write(mystr.split(".", 2));

运行结果:

www,imooc,com www,imooc

将字符串分割为字符,代码如下:

  • document.write(mystr.split(""));
  • document.write(mystr.split("", 5));

运行结果:

  • w,w,w,.,i,m,o,o,c,.,c,o,m
  • w,w,w,.,i

JS的分支语句

if (选择)语句

if 语句

最简单的条件语句,通常和else结合使用,如果。。。就。。。否则。。。

语法一:

if ( condition){ satement ; }

参数 condition: 如果条件成立,

statement: 执行什么 操作

例子: var age=15

if (age<18){ alert ( '你没有成年!') }

语法二:

if ( condition ) { satement1;} else{ staement2; }

如果条件成立则执行 staement1,否则执行 代码2 staement2

prompt()

语法 : prompt()

功能:弹出输入框(让用户自己输入)

返回值:

1,点击确认,返回输入内容

2,点击取消,返回 null

例子

var age =prompt('请输入您的年龄');

if (age <18) { alert('你还没有成年') } else{ alert ('你已经成年') }

语法三:

if (condition){

statement1;}

else if (condition){ staement2;}

...else{ staement 3; }

说明:省略号那里还可以有 else if(){}

if语句的嵌套

if(){

if(){}else{}

}else{

if(){}else{}

}

if语句算法 例子

游乐场门票

 //  让用户输入星期几

    // var week=Number(prompt('请输入星期几'));

    // var age =Number(prompt('请输入年龄'));

    //让星期几作为大前提条件/*

    /*

if (week==0 || week==6){

    //周末

    if(age>=10){

   alert(500)

    }else{

        alert(210)

    }

}else{

    //平常

    if(age>=10){

 alert(300)

}else{

    alert(140)

}

}

switch (选择)语句

除了if 语句之外,js还提供了另一种选择语句:switch语句

switch语句的用途:当一个变量被分类讨论的情况

1,在 switch()的圆括号中一般是一个变量名,这个变量将被 分类讨论

2;case 表示情况,它后面没有圆括号,直接跟一个值,程序依次将 case后面的值 与 switch 圆括号 中的值进行 全等比对,如果比对相同,则执行这条 case 冒号后面的语句,default表示默认情况

多条case 可以共用同一个语句体

栗子

 var year =Number(prompt("请输入一个年份"))

    var month = Number(prompt("请输入一个月份"));

    //分类讨论

    switch (month) {

      case 1:

      case 3:

      case 5:

      case 7:

      case 8:

      case 10:

      case 12:

        alert("这个月有31天");

        break; // 非常重要,程序员必须主动调用 break来跳出整个

// switch 语句,如果没有书写 break,则后面的所有case都将视为匹配,直至遇见 break

      case 4:

      case 6:

      case 9:

      case 11:

        alert("这个月有30天");

        break;

      case 2:

          if (year % 4==0 && year % 100 != 0 || year % 100 == 0 &&

          year  % 400 ==0){

              alert('这个月有29天')

          }else{

            alert("这个月有28天");

          }

       

        break;

      default:

        alert("您输入的月份有误");

    }

栗子2

//获取星期几

var week = new Date().getDay();

//优化代码

var weekstr ="";

swich(week){

case 0 :

weekstr = "日";

break;

case 1 :

weekstr = "一";

break;

case 2 :

weekstr ="二" ;

break;

case 3 :

weekstr = ''三'' ;

break ;

case 4:

weekstr="四";

break;

case 5 :

weekstr ="五";

break;

default:

weekstr ="六"

break;

}

document.write ('今天是星期" + weekstr);

for 循环语句

for 循环语句的语法:(范围明显时使用for)

for (var i=1 ; i<=10 ; i++){ console.log(i) ;}

for 的圆括号中有三个表达式;

表达i式 var i=1;表示定义一个“循环变量” i,并赋值为1;

表达式 i<=10 ; 表示继续执行循环的条件,只要这个条件为真,则会一直执行;

表达式 i ++用来更新循环变量,使循环变量的值越来越趋向终点

执行机理(顺序):先执行 i=1,,然后 判断 i<=10是否成立,若成立则进入 循环体 { console.log(i) },,否则退出循环体 ,,

执行完{ },则执行 i++,,之后进入 判断 i<=10.。。。。

for 循环算法题一:1到100的和

for (var sum =0,i=1;i <=100 ; i++){

sum+=i };

console.log(sum)

for循环算二:1到100中符合以下条件的数字,除3余1,除4余2,除5余3

for (var i =1; i<=100 ; i++ ){ if ( i % 3==1 && i % 4==2 && i%5 == 3){

console.log(i); } }

while 循环语句

while 循环语句,是一种 不定范围 循环,和for循环各有不同的用武之地

while语句事先不指定 循环开始和结束范围,,只要测试条件满足。就一直执行循环体

语法: while(测试条件){ }

while循环注意事项

1,while循环没有显示定义循环变量,必须自己在while循环外定义好循环变量,

有时甚至可以没有循环变量

2,循环体内的语句,必须使循环 测试条件 趋向不成立,否则 会死循环

栗子:

1,

var i=1;

while(i<=100){

console.log(i);

i++ ; }

2,

var i=1 ,sum=0

while( i<=100) {

sum+=1 ;

i++ ; }

console.log( sum) ;

更适合while循环的场景

1,寻找最小的满足 n平方大于 456789的整数n

var n=1;

while(n*n <=456789){

n++; }

console.log(n);

2,小兔子拔萝卜,第一天扒一个,第二天拔两个,第三天拔三个。。。问几天拔完 500 个萝卜

// 天的序号也是,这一天拔的 萝卜数

var n = 1

// 累加器

var sum = 0;

while( sum<500) {

sum += n;

// 注意最后一下,因为运行条件 (终止条件)和 序号 的变量不一样

n++;

}

// "出一错误" , 手动减去

console.log( n - 1);

while语句算法题

//随机一个数字,2~99之间

    var answer = parseInt(Math.random() * 98) + 2;

//此时的最大值,最小值,这个数值是用来提醒用户的

    var min = 1,

      max = 100;

//为了能够不断重复的执行询问,此时就必须使用 死循环

    while (true) {

//询问用户猜测的数字

      var n = Number(prompt("请猜测数字" + min + "~" + max));

      if (n <= min || n >= max) {

        alert("你输入的数字不在范围内");

        continue;

      }

// 判断用户输入的数字与answer 的关系

      if (n > answer) {

        alert("你输入的数字太大了");

//因为用户输入的数字较大,所以可以让此时的最大范围 数字变为用户输入的值

        max = n;

      } else if (n < answer) {

        alert("你输入的数字太小了");

//因为用户输入的数字较小,所以可以让此时的最小范围 数字变为用户输入的值

        min = n;

      } else {

        alert("恭喜你猜对啦");

//结束循环

        break;

      }

    }

循环搭配之 break 与 continue

break表示立即终止循环,它只能用在循环语句中,在for循环和while循环中使用

for(var i=0; i< 10 ;i++) {

console.log(i) ;

if ( i == 4) {

break;

} }

break 用在while语句中,通常和 while(true) { } 死循环搭配使用

var n = 1;

while(true){

if (n*n >456789 ) { console.log (n) ; break; }

n ++ ; }

栗子2,兔子第一天拔一根,第二天拔两根,几天拔完500萝卜的问题

 var n=1,

     sum=0;

    while(true){

     if(Number(sum=sum+n) >=500){

     console.log(n);

      break;

     } n++;

        } 

continue用 于跳过循环中的一个 迭代,并继续执行 循环的下一个 迭代

栗子

for (var i = 0; i < 5 ; i++) {

if( i == 3 ) {

continue ;

}

console.log(i) ; } //会输出 0 1 2 4

do while 循环

do-while 循环 将循环执行条件写到了 循环体后面,这样一来,循环体一定会·至少执行一次

然后 再检测 循环执行条件 是否 为true,决定是否 继续 执行循环体

do {

循环体 }

while(循环执行条件)

var n = 1;

do { console.log(n);

n++; }

while(n< 101)

随机数函数

Math.random ( ) //得到0 到 1之间的小数

可放大倍数 乘以10 再parseInt 取整 得到1~10之间的随机数

得到 [a,b] 区间的(随机)整数,公式:

parseInt (Math.random() * (b - a +1))+a

栗子

   do{

       var dx=parseInt(Math.random()*9)-4

       var dy=parseInt(Math.random()*9)-4

   }while(dx==0 && dy==0)

   console.log(dx,dy)

累加器与累乘器

什么是算法:算法就是把一个问题,拆解为计算机能够一步一步·执行的步骤

计算机的流程控制语句:顺序执行,选择语句,循环语句

累加器

栗子·

    //由用户输入数字n,计算 3/2 + 4/3 + 5/4 +....+ (n+1)/n  的结果

    //用户输入数字 n

    var n = Number(prompt('请输入数字'));

    // 累加器

    var sum = 0;

    // 遍历分母就可以,因为分子就是分母加1的关系

    for(var i = 2;i <= n;i++){

// sum = 0; 累加器不能放这里,每循环一次会清零

        sum += (i+1)/i

    }

    alert(sum.toFixed(2));

累乘器:

栗子

// 用户输入数字,计算它的阶乘

var n=Number(prompt(''请输入数字''));

//累乘器

var result=1;

for(var i=n; i>=1 ; i--){

result*=i

};

alert(result);

同时使用累加器,和累乘器

//用莱布尼茨及数估算圆周率

// π=2*(1+ 1/3 + (12)/(35) + (123)/(357) +.......(1234.....n)/(3579.....(2n+1))

//累加器就是最后的答案

var sum =0;

// 累乘器,用来制作每一项,制作出的这个项,要往累加器中 累加

var item =1;

//让用户输入数字

var n=Number(prompt("请输入数字"));

for(var i=1 ; i<=n ; i++) {

//要先制作出 每一项,这一项怎么制作?要使用累加器,item就是小车厢

itme*=i / (2*i+1);

// 把小车厢往累加器中累加

sum+=itme;

}

// 显示结果

alert((1+sum)*2)

穷举法

栗子1:

寻找1~100中能整除3,整除5的所有数

for(var i=1 ; i<=100 ; i++){

if(i%3 == 0 && i%5 ==0){

console.log(i) } }

栗子2:

用户输入一个数字,寻找它的约数

var n=Number(prompt("请输入数字"));

for(var i=1; i<=n ; i++) {

if(n%i ==0){

console.log(i) } }

栗子3:

寻找水仙花数

for(var i =100 ; i<1000; i++) {

//水仙花数要拆数位

//a,b,c分别代表百位,十位,个位

var i_str = i.toString();

var a=i_str.charAt(0);

  var b=i_str.charAt(1);

  var c=i_str.charAt(2);

if(Math.pow(a,3) +Math.pow(b,3) +Math.pow(c,3) ==i) {

console.log(i) }

综合算法题目

//1:循环的嵌套

for(var i = 0; i<3 ;i++) {

for(var j=0; j<3; j++) {

console.log(i,j) } }

  //2; 寻找100以内的质数

        // 穷举法

        outer: for (var i = 2; i <= 100; i++) {

            // 内层循环从2开始尝试除以i 如果能被整除 说明这个数不是质数

            // 可以下一个数字

            for (var j = 2; j < i; j++) {

                if (i % j == 0) {

                    // 给外层的 for 循环加上一个lable

                    continue outer; //这样表示立即开始迭代外层的for循环 结束当前的

                }

            }

            console.log(i);

        }

//3

 //鸡兔同笼的问题。35个头 ;94只脚

 //假设小鸡有a只,兔子有b只

 for(var a=0; a<=35; a++){

   for(var b=0; b<=35; b++){

     if(a+b==35 && 2a+4b==94){

       console.log('小鸡有'+a+"只,兔子有"+b+'只');

     }

   }

 }

JS数组

一:数组的简介与定义

1: 数组,顾名思义,用来存储一组相关的值,从而方便进行求和,计算平均数,逐项遍历等操作。

定义数组的方法

//数组的定义方法1

var arr1=[33,34,55,556];

//第二种方法

var arr2=new Array(33,44,55,77);

//定义第三种方法,表示这个数组存储了4组数据,长度为4

var arr3=new Array(4);

console.log(arr1);

console.log(arr2);

console.log(arr3);

访问数组的知识

var arr=['a','c','b','gt'];

console.log(arr[0]);

console.log(arr[1]);

console.log(arr[2]);

console.log(arr[3]);

下标越界(访问不存在的下标)会返回 undefined

数组的length属性表示它的长度

数组最后一项的下标是数组的长度减1

console.log(arr.length);

最后一项

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

2: 数组不是只读的,我们可以修改它其中任何项的值

var arr=['u','y','r','t'];

arr[2]=arr[2].toUpperCase();

arr[6]='1'

console.log(arr);

数组的最大优点就是方便遍历

var arr=[34,4,45,5,,,66656,6,76,,];

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

  console.log(arr[i]);

数组类型的检测

数组用 typeof 检测结果为 object

Array.isArray()方法可以用来检测数组,返回布尔值

数组的常用方法
数组的头尾操作方法

push()方法用来在数组末尾推入新项,参数就是要推入的项,如果要推入多项,可以用逗号隔开

调用push()方法后,数组会立即改变,不需要赋值

var arr=[1,24,,5,66]

//方法就是打点调用的函数,所以是数组打点调用它们

arr.push(566,78,6);

console.log(arr);

pop()删除数组最后一项

var arr=[23,4,5,56,6,]

//删除最后一项

var item=arr.pop();

console.log(arr);

//返回被删除的一项

console.log(item);

unshift()在数组的首项插入新项

shift() 删除数组的首项,返回被删除的一项

splice()

splice()方法用于替换 数组中的指定项

也可删除指定项

var arr=[1,2,3,4,5,6];

arr.splice(3,2,66,77,88,99,); //参数3表示数组下标为3的进行操作,2表示要删除的个数,

console.log(arr); //后面那些表示插入的项,删除个数为0则不删除原来的

//splice() 也可以指定位置插入新的项,也可指定删除(不添加新项)

//splice() 函数返回一个数组

slice()

slice()方法用于得到子数组,类似于字符串的 slice()方法

slice(a,b)截取的子数组从下标为a的项开始,到下标为b(不包括下标为b的项)结束

slice()如果不提供第二个参数,则截取到最后

参数允许为负数,表示数组的倒数第几项

不改变原数组

join()

数组的join()方法可以使数组转为字符串; 字符串的split()方法可以使字符串转为数组

逆运算

jion()的参数表示以什么字符作为连接符,如果留空则默认以逗号分隔,如同调用toString()方法

注意:字符串split()方法的参数表示以什么字符拆分字符串,一般不留空

在打印台栗子

"abcdefg".split()

["abcdefg"]

"abcdefg".split("")

["a","b","c","d","e","f","g"]

"a-b-c-d-e-f-g".split("-")

["a", "b", "c", "d", "e", "f", "g"]

concat()

concat()方法可以合并连接多个数组

image.png

reverse()

reverse()方法用于将一个数组的全部项顺序置反

indexOf()

indexOf()方法的功能是搜索数组中的元素,并返回它所在的位置,如果元素不存在,则返回-1

includes()

includes()方法的功能是 判断一个数组是否包含一个指定的值,返回布尔值

数组遍历相关算法
  • //1:求数组的和

            var arr=[2,4,5,6,];

            //累加器

            var sum =0;

            //遍历数组,每遍历一个数字,就要把这个数字累加到累加器中

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

                sum+=arr[i]

            }

            console.log(sum);

  •             //2:求数组最大值和最小值

            var arr=[12,5,46,76,87,5,99,55];

            //定义两个变量,max表示当前寻找到的最大值,默认为 arr[0]

            //min表示当前寻找到的最小值,默认为 arr[0]

            var max=arr[0];

            var min=arr[0];

            //遍历数组,从下标为1的项开始遍历

            for(var i=1; i<arr.length; i++){

                //如果你遍历的这项,比当前最大值 大,那么就让它就成为当前最大项

                if(arr[i]>max){

                  max=arr[i];

                }else if(arr[i]<min){

                 //否则如果你遍历的这项,比当前最小值 小,那么就让它成为当前最小项  

                 min=arr[i] ;

                }

            }

           console.log(max,min);

数组去重和随机取样本
  •      //去除数组中的重复项,思路 创建一个新数组

     var arr=[1,1,1,3,3,45,6,77,77,6,5]

     //结果数组

     var result=[];

     

    //  遍历原数组

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

         //判断遍历到的这一项是否在结果数组中,如果不在就推入新数组中

         //includes方法用来判断某项是否在数组中

         if(!result.includes(arr[i])){

             result.push(arr[i]);

            

         }

     }

     console.log(result);

  • 随机取3项:

    var arr=[3,5,6,65,4,31,3,];

    //准备结果数组

    var result=[]

    //遍历数组

     for(var i=0; i<3; i++){

         //随机选择一项的下标,数组的下标0~arr.length-1;

         //之前学习过的  random的公式,[a,b]区间的随机数是 parseInt(Math.random()*(b-a+1)+a)

         var n=parseInt(Math.random()*arr.length)

         //把这项推入结果数组

         result.push(arr[n]);

         //删除这项,防止重复被随机到

         arr.splice(n,1);

     }

    console.log(result);

数组浅克隆

浅克隆:只克隆数组的 第一层,如果是多维数组,或者数组中的项是其他引用类型值,则不克隆其它层

方法1准备一个空数组,concat方法把两个数组连接

方法2准备一个空数组,for 循环遍历原数组,

遍历到的每一项推入空数组中

        // 浅克隆

        var arr = [1, 2, 3, 4, 5];

        var result = [];

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

            result.push(arr[i])

        }

        console.log(result);

        console.log(result == arr);

数组排序sort()

sort()方法使数组中的元素按照一定的顺序排列。

语法:

arrayObject.sort(方法函数)

栗子

function sortNum(a,b) {

return b-a //降序

}

var myarr = new Array("80","16","50","6","100","1");

document.write(myarr.sort(sortNum));

JS函数

函数的基本使用

什么是函数:函数就是语句的封装(功能的封装),可以让这些代码方便地复用

函数具有“一次定义,多次调用”的优点,可以简化代码,让代码更具有可读性

函数的定义和调用:和变量相似,函数必须 先定义 后使用

使用 function关键字 定义函数,用function是“功能”的意思

    function fun(){

        //函数体

    }

      //定义的方法二(匿名函数)

      var fun =function(){

          //函数体

      }

执行函数体内的所有语句,就称为“调用函数”

调用函数非常简单,只需在函数名字后书写圆括号即可

fun() ; //调用函数

栗子:

     //定义函数,,定义函数是不会直接执行的

    function fun(){

     console.log("好好学习");

     console.log("好好赚钱");

    }

    //函数必须要等到调用的时候才能执行

    fun();

函数优先提升;;变量声明提升,无法覆盖提升的函数

函数的参数

参数是函数内的一些待定值,在调用函数时,必须传入这些参数的 具体值

函数的参数可多可少,函数可以没有参数,也可以有多个参数,多个参数之间需要用逗号隔开

    function add(a,b){ //a,b是形参

        var sum=a+b;

        console.log('两个数字之和是'+sum);

    }

    add(3,5); //实参

    add(2,4);

    add(23,4)

数量尽可能保持一致,否则会出现报错,或者结果是NaN

    //定义一个函数,这个函数的功能是计算a到b之间所以整数的和

    function calcSumFromAtoB(a,b){

        for(var i=a, sum=0; i<=b; i++){

            sum+=i;

            

        }

        console.log("从"+a+'到'+'b'+'的所有参数的和是'+sum);

       

    }

    calcSumFromAtoB(3,7);

函数内arguments表示它接收到的实参列表,它是一个类数组对象

所有属性均为从0开始的自然数序列,并且有 length属性,和数组类似可以用方括号书写下标访问对象的某个属性值,但是不能调用数组的方法

//不管用户传入几个实际参数,永远能够计算它们的和

     function fun(){

        //  console.log(arguments);

        //  console.log(arguments[0]);

        //  console.log(arguments[3]);

        //  console.log(arguments[4]);

        var sum=0;

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

            sum+=arguments[i]

        }

     console.log("所有参数的和是"+sum);

      

     }

     fun(33,4,4,567,87,)

函数的返回值

函数体内可以使用 return关键字表示 函数的返回值

     //函数返回值 return

     //函数功能是返回两个参数的和

     function sum(a,b){

         return a+b;

     }

     //有 return 必须有变量接收

      var result= sum(3,4);

      console.log(result);

调用函数时,一旦遇见 return语句则会立即退出函数,将执行权交还给调用者

结合if语句的时候,往往不需要 写else分支了

    //书写一个函数,函数的功能判断一个数字是否为偶数

    function checkEven(n) {

      if (n % 2 == 0) 

      return true;

      return false;

    }

    var result = checkEven(63);

    console.log(result);

函数算法题

寻找喇叭花数:三位数,其中每一位数字的阶乘之和 恰好等于他本身,即ABC=A!+B!+C!

其中ABC表示一个三位数,试着寻找所有喇叭花数。

思路,将计算某个数字的阶乘 封装成函数,这样可以让问题简化

    //计算一个数字的阶乘

    function fac(n) {

        //累乘器

        var result=1;

        for(var i=1; i<=n; i++){

            result *= i;

        }

        return result;

    }

    //穷举法,从100到999寻找喇叭花数

    for(var i=100;i<=999; i++){

        //把数字i变为字符串

        var i_str=i.toString();

        //abc分别表示百位 十位 个位

        var a=Number( i_str[0]) ;

        var b=Number( i_str[1]) ;

        var c=Number(i_str[2]);

        // console.log(a,b,c);

        if(fac(a)+fac(b)+fac(c)==i){

            console.log(i);

        }

    }

JS内置的 sort()方法

数组排序可以使用sort()方法,这个方法的参数又是一个 函数

    var arr=[33,44,22,11,4,8,88];

    arr.sort(function(a,b){

    })

这个函数中的a,b分别表示数组靠前和 靠后的项,如果需要将它们交换位置,

则返回任意 正数; 否则 就返回 负数

栗子

    var arr=[33,44,22,11,4,8,88];

    arr.sort(function(a,b){

       if(a>b){

           return 1;

       }else{

           return -1;

       }

    })

    console.log(arr);

或者这样写

     var arr=[33,44,22,11,4,8,88];

    arr.sort(function(a,b){

        return a-b; // 降序 b-a

    })

    console.log(arr);

什么是递归

递归:函数的内部语句 可以 调用这个函数自身,从而发起 对函数的 一次迭代。在新的迭代中, 又会执行调用函数自身的语句,从而 又产生下一次的迭代。当函数执行到某一次时,不再进行新的迭代,函数被一层一层返回,,函数被递归。

递归是一种较为高级的编程技巧,它把一个大型复杂的问题层层转化成一个与原问题相似的规模较小 的问题来求解。

用求 4 的阶乘 举例

    //4!=4*3!=4*3*2!=4*3*2*1!

递归的要素

边界条件:确定递归到何时 终止,,也称为 递归出口

递归模式:大问题是如何分解为小问题的,也称为 递归体

   //实现递归的小程序

   //书写一个函数,这个函数内部自己会调用自己,从而形成递归。

   function fac(n){

       //这个是递归的出口,如果计算1的阶乘,可以不用递归了,直接告诉你答案就是1

       if(n==1) return 1;

       //函数的功能是计算n的阶乘;n!就是 n*(n-1)!

       //如果询问的不是1的阶乘,就返回 n*(n-1)!

       return n*fac(n-1);

   }

   var result=fac(7);

   console.log(result);

递归常见算法题

  //斐波那契数列是这样的数列:1,1,2,3,5,8,13,21

  //规律:下标为0和1的项的值都是 1,从下标 为2的项 开始,每项等于前面两项的和

  

  //编写一个函数,这个函数功能是返回 斐波那契数列中下标为 n的那项的值

  function fib(n){

      //数列的下标为 0的项,和下标为1的项 值为1

      if(n==0||n==1) return 1;

      //斐波那契数列的本质特征就是 每一项都等于前面两项 的和

     return fib(n-1)+fib(n-2);

  }

  //书写一个循环语句,计算斐波那契数列的前 15项

  for(var i=0; i<15; i++){

      console.log(fib(i));

  }

实现深克隆

使用递归思想,整体思路和浅克隆类似,但稍微进行一些改动:如果遍历到的项是 基本类型值

则直接推入结果数组;如果遍历到的项又是数组,则重复执行浅克隆的操作。

//原数组

var arr1=[33,44,5,[6,66,[77,43]]];

//函数,这个函数会被递归

function deepClone(arr){

    //结果数组,每一层都有一个结果数组

    var result=[];

  //遍历数组的每一项

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

   //类型判断,如果遍历到的这项是数组

   if(Array.isArray(arr[i])){

       //递归

      result.push( deepClone(arr[i]));

   }else{

       //如果遍历到的这项不是数组,是基本类型值,就直接推入到结果数组中,

       //相当于递归的出口

    result.push(arr[i]);

   }

  } 

    

    //返回结果数组,每一层都有一个结果数组

    return result;

}

 //测试

 var arr2=deepClone(arr1);

 console.log(arr2);

全局变量与局部变量

//全局变量

var a=10;

function fun(){

    //局部变量,会把全局的变量a遮蔽

    var a=5;

    a++;

    console.log(a);    // 6

}

fun();

console.log(a);    //10

注意考虑变量声明提升的情况

栗子

var m=1;

function fun(){

    m++;     //变量提升,只提升定义,不提升值,

           //局部变量m被自增1,m此时是undefined,自增1结果是NaN

  var m=4;     

      //重新将m赋值为4   

  console.log(m)   //4

}

fun();

console.log(m);  //1

//形参也是局部变量

函数的嵌套 :定义在一个函数内部的 函数是 局部函数

立即执行函数 IIFE

() 包裹

作用1--为变量赋值

当给变量赋值需要一些较为复杂的计算时(如 if 语句),使用IIFE显得语法更紧凑。

  var age=12;

   var sex="男";

   var title=(function(){

     

   if(age<18){

      return '小朋友';

   }else{

       if(sex=="男"){

           return "先生";

       }else{

          return "女士";

       }

   }

   })();

   alert(title);

作用2--将全局变量 变为局部变量

IIFE可以在一些场合(如for循环中)将全局变量变为局部变量,语法显得紧凑

    var arr = [ ];

    for (var i = 0; i < 5; i++) {

      (function(i) {

        arr.push(function() {

          alert(i);

        });

      })(i);

    }

    arr2;

什么是闭包

javascrip中函数会产生 闭包。闭包是函数本身 和 该函数声明时所处的环境状态 的组合

其实闭包就是函数的一种性质,函数能够 记忆住 其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时的所处环境的变量

//创建一个函数

function fun(){

    //定义局部变量

    var name='慕课网'

    //返回一个局部函数

    return function(){

      console.log(name);

    };

}

//调用外部函数,就能得到内部函数,用变量inn接收

var inn =fun();

    //执行inn函数,就相当于在fun函数的外部,执行了内部函数

inn();

在javascript中,每次创建函数时都会创建闭包

但是,闭包特性往往 需要将函数 ‘换一个地方 执行,才能被观察出来。

闭包很有用,因为它允许我们 将数据与操作该数据的函数 关联起来。

当闭包产生时,函数所处环境的状态 会 始终保持在内存中,不会在外层函数调用后 被自动清除,这就是闭包的记忆性。

 function create(stan){

      function  cre(n){

  if(n<=stan){

      console.log('你的体温正常');

  }else{

      console.log('你的体温偏高');

  }

     }

     return cre;

 }

 //创建一个create函数,它以37.1为标准线

   var check_A=create(37.1);

//创建一个check函数,它以37.3为标准线

var check_B=create(37.3);

  

 check_A(37.4);

   check_A(37.0);

check_B(37.5);

check_B(37.2);

DOM

DOM基本概念

DOM(文档对象模型)是javscript 操作html 文档的 接口;使文档操作变得更加优雅,简便。

DOM最大的特点就是将文档表示为 节点树。

image.png

document对象

document对象是DOM最重要的东西,几乎所有DOM的功能都封装在了document对象中。

document对象也表示整个html文档,它是DOM节点树的根;

document对象的nodeType属性值是9;

访问元素节点的常用方法:

一,document.getElementById()

功能是 通过 id得到元素节点;

注意事项;

如果页面上有相同 id的 元素,则只能得到 第一个

延迟运行:在测试DOMD代码时,js代码一定要写到html节点的后面,否则js无法找到

相应的html节点

可以使用 window.onload=function(){ }事件,使页面 加载完毕后 再执行 指定的代码;

二;getElementsByTagName()

方法的功能是通过标签名 得到节点数组

注意事项;

数组方便遍历,从而可以 批量 操控元素节点;

即使页面上只有一个指定标签名的节点,也得到 长度为1的数组;

三;getElementByClassName()

方法的功能是通过 类名得到节点数组

IE9开始兼容,

四;querySelector()

方法的功能是通过选择器得到元素

注意事项;querySelector()方法只能得到页面上一个元素,如果有多个元素符合条件,则智能得到第一个元素

五;querySelectorAll()

方法的功能是通过选择器 得到元素 数组

image.png

节点的关系

子节点:childNodes; 父节点:parentNode;

第一个子节点:firstChild

最后一个子节点:lastChild

前一个兄弟节点; previousSibling

后一个兄弟节点: nextSibling

注意; DOM中,文本节点也属于节点 在使用节点的关系一定要注意

image.png

//子节点 childNodes

var box=document.getElementById('box');

var pre=document.getElementById('spec');

//所有子节点

console.log(box.childNodes);

//所有元素的子节点(ie9开始兼容)

console.log(box.children);

//第一个子节点

console.log(box.firstChild);

console.log(box.firstChild.nodeType);

//第一个元素子节点(IE9开始兼容)

console.log(box.firstElementChild);

//最后一个子节点·

console.log(box.lastChild);

console.log(box.lastChild.nodeType);

//最后一个元素子节点·

console.log(box.lastElementChild);

//父节点

console.log(pre.parentNode);

    //前一个兄弟节点

    console.log(pre.previousSibling);

    //前一个元素兄弟节点

    console.log(pre.previousElementSibling);

    

    //后一个兄弟节点

    console.log(pre.nextSibling);

    //后一个元素兄弟节点

    console.log(pre.nextElementSibling);

节点操作
一;改变元素节点中的内容可以使用两个相关属性;
  • 1,innerHTML 属性能以 html语法设置节点中的内容

  • 2,innerText 属性只能以 纯文本的形式 设置节点的内容

var oBox= document.getElementById('box');

//    oBox.innerHTML="  <ul> <li>牛奶</li>   <li> 咖啡 </li> </ul> " 

oBox.innerText="  <ul> <li>牛奶</li>   <li> 咖啡

二;改变元素节点的css样式

css属性要写成“驼峰”形式

 <div id="box" class="box">

         节点呀呀

     

 var oBox=document.getElementById("box");

    //   oBox.style.backgroundColor="red";

    // oBox.style.backgroundImage='url(www.imooc.com/static/img/…)';

    // oBox.style.backgroundSize='contain'

    oBox.style.fontSize="50px"

三;改变元素节点的html属性

标准 W3C属性,如 src , href等等,只需要直接 打点 进行更改即可

oImg.src = 'images/2.jpg'

四;不是W3C属性,民间自定义属性

要使用 setAttribute() 和 getAttribute() 来设置和读取

      var oBox=document.getElementById("box");

  oBox.setAttribute('data-n',10);

  var n=oBox.getAttribute('data-n');

  console.log(n);

节点的创建
document.createElement()

方法用于创建一个指定 tag name的 HTML元素

var 0Div = document.createElement("div") //创建了一个div

新创建出的节点是“孤儿节点”,这意味着 它没有被挂载到DOM树上;

必须继续使用 appendChild() 或 insertBefore()方法将 孤儿节点插入到DOM树上。

任何已经在DOM树上的节点,都可以调用appendChild()方法,它将孤儿节点挂载到它的 内部,成为它最后 一个子节点

父节点.appendChild(孤儿节点);

      var oBox=document.getElementById("box");

  //创建孤儿节点

  var oP=document.createElement('p');

  //设置内部文字

  oP.innerText='我是新来的';

  //上树

  oBox.appendChild(oP);

任何已经在DOM树上的节点,都可以调用 insertBefore()方法,它将孤儿节点挂载到它的 内部,

成为 它的 “标杆子节点” 之前的节点

父节点.insertBefore(孤儿节点,标杆节点);

      var oBox=document.getElementById("box");

var oPs=oBox.getElementsByTagName('p');

  //创建孤儿节点

  var oP=document.createElement('p');

  //设置内部文字

  oP.innerText='我是新来的';

oBox.insertbefore(oP, oPs[0])

例子:创建一个九九乘法表

td{

    width: 100px;

    height: 30px;

    border: 1px solid #000;

}

<table id='mytable'> </table>

//创建九九乘法表

var mytable=document.getElementById('mytable');

for(var i=1; i<=9; i++){

    //创建了tr标签

    var tr=document.createElement('tr');

    for(var j=1; j<=9; j++){

        //创建了td标签

        var td=document.createElement('td');

        //设置td内部的文字

        td.innerText=i+'乘'+j+'等于'+(i*j);

        //让tr追加td标签

        tr.appendChild(td);

    }

    //让mytable追加tr标签

    mytable.appendChild(tr)

}

节点的移动和克隆
移动节点:

如果将已经挂载在DOM树上的节点成为 appendChild()或者 insertBefore()的参数,

这个节点将会被移动

新父节点.appendChild(已经有父亲的节点);

新父节点.insertBefore(已经有父亲的节点,标杆子节点);

这意味着 一个节点不能 同时位于 DOM树的两个 位置

例子1:

   <div id="box1">

       <p id="para">我是段落</p>

   </div>

   <div id="box2">

    

   </div>

var box2=document.getElementById('box2');

var pare=document.getElementById('para');

box2.appendChild(para);

例子2:

   <div id="box1">

       <p id="para">我是段落</p>

   </div>

   <div id="box2">

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

   </div>

var box2=document.getElementById('box2');

var pare=document.getElementById('para');

var ps_inbox2=box2.getElementsByTagName('p');

// box2.appendChild(para);

box2.insertBefore(pare,ps_inbox2[0]);

删除节点:

removeChild()方法从DOM中删除一个子节点

父节点.removeChild(要删除子节点);

节点不能主动删除自己,必须由父节点删除它;

(批量删除就要使用到循环语句)

   <div id="box2">

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

    <p>我是box2的原有标签</p>

   </div>

var box2=document.getElementById('box2');

var ps_inbox2=box2.getElementsByTagName('p');

box2.removeChild(ps_inbox2[0]);

克隆节点

cloneNode()方法可以克隆节点,克隆出来的节点是 “孤儿节点‘,

var 孤儿节点=老节点.cloneNode();

或者是

var 孤儿节点=老节点.cloneNode(true)

参数是一个布尔值,表示是否采用深度克隆:如果为 true,则该节点的所有后代节点也都会被克隆,

如果为false,则只克隆该节点本身

   <div id="box1">

       <ul>

           <li>牛奶</li>

           <li>可乐</li>

           <li>咖啡</li>

       </ul>

   </div>

   <div id="box2"> </div>

var box1=document.getElementById('box1');

var box2=document.getElementById('box2');

var theul=document.getElementsByTagName('ul')[0];

//克隆

var new_ul=theul.cloneNode(true);

//上树

box2.appendChild(new_ul)

事件监听

监听:顾名思义,就是让计算机 随时能够 发现这个 事件发生了,从而执行 程序员预先编写 得一些程序

设置事件监听的方法主要有 onxxxx 和 addEventlistener

image.png

image.png

<form id="myform">

          <p>

              姓名:

              <input type="text" name="namefle">

          </p> 

          <p>

            年龄:

            <input type="text" name="agefle">

        </p>

      </form>

var myform=document.getElementById('myform');

var namefle=myform.namefle;

var agefle=myform.agefle;

namefle.onchange=function(){

    console.log('你已经修改完姓名');

};

namefle.oninput=function(){

    console.log('你正在修改姓名');

};

namefle.onfocus=function(){

    console.log('得到焦点');

}

事件对象

什么是事件监听:事件处理函数提供一个形式参数,它是一个对象,封装了本次事件的细节;

这个参数 通常用 单词event或字母e 来表示

obox.onmousemove=function(e) { //这个e就是这次事件 的‘’事件对象‘’ }

image.png

      //e.charCode属性通常用于onkeypress事件中,表示用户输入的字符 的‘字符码’

      //e.keyCode通常用于onkeydown事件和 onkeyup中,表示用户按下的 按键 ’键码‘

image.png

image.png

<input type="text" id="box" />

    <h1 id="info"></h1>

var obox = document.getElementById("box");

    var oinfo = document.getElementById("info");

    obox.onkeypress = function(e) {

      oinfo.innerText = "你输入的字符的字符码是" + e.charCode;

    };

e.preventDefault()

方法用来阻止事件产生的默认动作

e.stopPropagation()

方法用来阻止事件继续传播

在一些场合,非常必要切断事件继续传播,否则会造成页面特效 显示出 bug

定时器

定时器  setInterval()函数可以重复调用一个函数,每次调用 之间具有固定的时间间隔

  var a=0;

  setInterval(function(){ //第一个参数是函数

      console.log(++a);

  },2000) //第二个参数是 间隔时间

函数的参数

setInterval()函数可以接收第3,4....个参数,它们将按顺序 传入函数

setInterval(

      function(a, b) {

        //形参a的值是88,b的值是66

        console.log(a,b);

      },

      2000,

      88,

      66

    );

具名函数也可以传入setInterval

    var a=0;

    function  fun(){

        console.log(++a);

    }

    setInterval(fun,1000) //注意fun这里没有圆括号

使用定时器实现动画,利用的是‘ 视觉暂留’原理

清除定时器

clearInterval()函数可以清除一个定时器

    <h1 id="info">0

    <button id="btn">开始

    <button id="btn1">暂停

//设置一个定时器,并且用time变量接收这个定时器

    var oInfo = document.getElementById("info");

    var oBtn = document.getElementById("btn");

    var oBtn1 = document.getElementById("btn1");

    var a = 0;

    //全局变量

    var time;

    oBtn.onclick = function() {

        //为了防止定时器叠加,应该设置定时器之前先清除 定时器

        clearInterval(time);

        //更改全局变量time的值为一个定时器实体

      time = setInterval(function() {

        oInfo.innerText = ++a;

      }, 2000);

      oBtn1.onclick=function(){

          clearInterval(time);

      }

    };

延时器

setTimeout()函数可以设置一个延时器,当指定时间到了之后,会执行函一次,不再重复执行

    setTimeout(function() {

      //这个函数会在2秒后执行一次

    }, 2000);


//初识异步语句

setTimeout(function(){

    console.log('a');   //回调函数

},2000);

console.log('b');   //异步语句不会阻塞程序整常运行

//b

//a

函数节流

函数节流:一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次,

借助 setTimeout()延时器

    //函数节流公式

    var lock = true;

    function x() {

      //x代表需要节流的函数

      //如果锁是关闭状态,则不执行

      if (!lock) return;

      //函数核心语句

      //关锁

      lock = false;

      //指定毫秒数后 将锁打开

      setTimeout(function() {

        lock = true;

      }, 2000);

    }

微信图片_20220511222417.png