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. 数字 + 数字 = 数字
会把其他类型 转换为 数字 ,再相加
-
操作符的作用就是数字相减
-
都是优先把非数字的转换为数字,再运算
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. 第九优先级: = += -= *= /= %= 赋值
上面是具体的优先级,但是平时我们不会把很多的操作符放在一起运算,所以我们大致记住
- 括号先算
- 其次算算术
- 再次算比较
- 然后算逻辑
- 最后算赋值
二、流程控制
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");
}
练习:
-
任意输入两个数,求两个数最大值,在弹窗中显示最大值(练习if-else结构)
-
判断分数区间,分数在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;
}
细节:
-
小阔号里面的变量 全等于 case 后面的值得时候,这个case后面的代码就会被执行
-
default不是必须的,如果小阔号里面的变量都不等于所有的case后面的值,才会执行default 后面的代码
-
break的作用是结束判断,如果后面没有写break,则代码会继续往下执行
-
.变量和固定值的比较是 === 严格等于
三元表达式(补充)
三元(三目)表达式的使用是简写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~10之间的所有整数和
- 在控制台输出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
自定义构造函数:
- 使用大驼峰命名(必须首字母大写(可以小写开头(几乎没人这样)));
- 不需要手动创建对象
- 通过 this(实例对象) 进行添加成员
- 不需要手动返回, 会自动返回
- 必须搭配 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环境安装
方法一: 直接安装
方法二: nvm方式安装 (比较推荐)
NVM(Node version Manager) 一个用于管理Node多版本的工具。
实现快速切换node版本的需求
- 下载nvm安装包
然后直接安装(如果自己之前安装过node,需要先卸载之前安装的node)
双击安装包,选择接受accept ,第一个目录必须是中文(可以自己选择目录),然后电脑 win + R 建打开,输入nvm version 得到版本号就说明安装成功。
-
设置nvm的镜像地址
打开nvm的安装目录,打开里面的
settings.txt
,可以对里面的镜像地址进行设置,可以把下面的两行复制到最后node_mirror: https://npm.taobao.org/mirrors/node/ npm_mirror: https://npm.taobao.org/mirrors/npm/
因为默认情况下,nvm帮我们下载node环境的时候会到国外的地址下载,我们可以手动改为国内的。不过有时候国内的镜像有时候会崩,如果下载过慢,也可以尝试把这两行删除,再重新下载。
不行让别人发一份放在nvm的安装目录 也可以使用
-
使用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版本
总结:
- nvm是一个版本管理工具,安装的时候不能安装在中文目录下
- nvm主要命令
- nvm version 查看nvm版本
- nvm list 查看当前安装的所有node版本
- nvm install node版本 安装指定版本的node环境
- nvm use node版本 切换指定版本的node环境
- 如果下载过慢可以自己更改镜像地址,也可以向同桌要一份已经下载好的
-
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的版本号。
作用
- 下载并管理项目中使用到的第三方式模块(包)
- 发布自己的模块到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
- 输入 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
常用命令:
npm | yarn |
---|---|
npm init -y | yarn init -y |
npm install react --save | yarn add react |
npm uninstall react --save | yarn remove react |
npm install react --save-dev | yarn add react --dev |
npm update --save | yarn upgrade |
npm install -g nodemon | yarn global add nodemon |
yarn 全局安装后,命令不生效
背景:
- 执行
yarn global add nodemon 后,重启
bash…`, vue 命令依然不生效 - 而 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文件。这个文件到底有什么用?
- 记录了你这个项目的主要信息
- 可以明确项目的依赖,将来即使把node_modules删除了,也可以通过这个文件找回
- 声明简短 的命令,来代替复杂的命令
- …
小结:
- 包管理工具是我们在后面的学习,以后的工具中一定会用到的,所以一定要会使用
- 每个项目一定要检查有没有 package.json ,如果没有,一定要先 创建一个 package.json npm init -y
- node_modules文件夹里面就是我们下载的第三方模块,在传输代码的时候要记得排除这部分
- 将来在工作中,yarn或者npm都可能会使用,要熟悉对应的命令