初识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()方法可以合并连接多个数组
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最大的特点就是将文档表示为 节点树。
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()
方法的功能是通过选择器 得到元素 数组
节点的关系
子节点:childNodes; 父节点:parentNode;
第一个子节点:firstChild
最后一个子节点:lastChild
前一个兄弟节点; previousSibling
后一个兄弟节点: nextSibling
注意; DOM中,文本节点也属于节点 在使用节点的关系一定要注意
//子节点 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
<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就是这次事件 的‘’事件对象‘’ }
//e.charCode属性通常用于onkeypress事件中,表示用户输入的字符 的‘字符码’
//e.keyCode通常用于onkeydown事件和 onkeyup中,表示用户按下的 按键 ’键码‘
<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);
}