数组的基础
创建数组
- 直接量:var arr=[值1,...];用的比较多
- 构造函数:var arr=new Array(值1,...);
特殊
按值传递:
- 如果传递的是原始类型其实是复制了一个副本给对方,两者互不影响的;
- 如果传递的是引用类型:js中不是原始类型,就是引用类型(函数、数组........都是引用类型)- 浅拷贝
- 因为引用类型很大,比原始类型要大得多,不可能保存在变量本地,只是保存了一个【地址值】而已
- 其实是把自己的地址值赋值给了对方,而两者使用的是同一个地址值,一个人修改,另一个也会跟着变化
- 引用类型,在比较时,其实看的不是值,而是看的地址值在做比较
索引数组:下标都是数字组成的数组
hash(关联)数组:下标是可以自定义的
为什么使用:索引数组的下标无具体的意义,不便于查找
如何使用:
1. 创建:2步
先创建一个空数组:var arr=[];
为数组添加自定义下标并且赋值:arr["自定义下标"]=新值;
2、访问:arr["自定义下标"];
3、强调:hash数组的length会失效,永远为0!
遍历hash数组,不能再使用for循环了,必须使用for in循环 - 其实for in袍哥并不爱称呼他是一个循环,因为它不需要设置从哪里开始,到哪里结束,纯自动化的,专门为了遍历hash数组而存在的
语法:
for(var i in arr){
i->下标
arr[i]->当前次元素
}
特殊
不止hash数组可以遍历,索引数组也可以遍历
索引数组依然使用for循环,hash数组再使用for in
hash数组的原理
hash算法:
将字符串,计算出一个尽量不重复的数字(地址值)
字符串内容相同,则计算出来的数字也一定相同
添加元素:js解释器会将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到此地址之中保存
获取元素:js解释器会将指定的下标再次交给hash算法,得到了一个和当初保存时完全一样的数字(地址值),通过此地址值就可以找到你当初保存的数据了,取出来使用了
JS里面一切东西都是对象,万物皆对象,除了undefined和null,!!!!一切对象的底层都是hash数组!!!!
数组的API
前辈们预定义了很多方法,等待我们学习,我们程序员只需要学会如何使用,就可以直接用上 - 这些方法只有数组可以使用
1.自定义连接符:
不修改原数组的,只会返回一个新数组
arr to str:
var str=arr.join("自定义连接符");
固定套路:2个
将数组里面的内容拼接为一句话/单词 - 无缝拼接,其实就是拼接了一个空字符串
var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
console.log(arr.join(""));
将数组拼接为DOM页面元素 - 第一次遇到数据渲染页面,这仅仅只是数据渲染的基础 - 一个好的数据结构能极大的提升程序员的开发效率
var arr=["-请选择-","北京","南京","西京","东京","重庆"];
var str="<option>"+arr.join("</option><option>")+"</option>";
sel1.innerHTML=str;
2.拼接数组:添加元素的新方式
不修改原数组的,只会返回一个新数组
将你传入的实参全部拼接到数组的末尾
语法:var newArr=arr.concat(新值1,arr1,...);
特殊:
1、不修改原数组,只会返回一个新数组
2、concat支持传入数组参数,悄悄将的你传入的数组打散为单个元素再拼接
3.截取子数组:只想要取出数组的某一部分使用
不修改原数组的,只会返回一个新数组
根据你传入的开始下标一直截取到结束下标
语法:var subArr=arr.slice(starti,endi+1)
特殊:
1、不修改原数组,只会返回一个新数组
2、含头不含尾
3、endi可以省略不写,如果不写,则从starti截取到末尾
4、starti和endi可以省略不写,那么从头到尾完整的赋值一份,此操作叫做深拷贝!复制了一个副本给对方,两者不会相互影响
5、支持负数参数,-1代表倒数第一个
4.删插替:
【删除】:var dels=arr.splice(starti,n);//n代表你要删除几个
特殊:虽然他直接修改原数组,但是也有返回值,返回的是被删除的数组组成的一个新数组,因为前辈们考虑到有可能删掉的就是你刚需要的,哪怕没有删除也会返回一个空数组
【插入】:var dels=arr.splice(starti,0,新值1,...);
特殊:
1、原starti位置的元素以及后续元素都会被向后移动
2、尽量不要插入一个数组,会导致我们的数组一些是一维,一些是二维,导致我们遍历的时候极不方便
【替换】:var dels=arr.splice(starti,n,新值1,...);
特殊:1、插入的元素和删除的元素,个数不必相等
5.翻转数组:arr.reverse(); 垃圾
6.数组的排序
1、冒泡排序:前一个元素和后一个元素进行比较,如果前一个>后一个,两者就交换位置,发现就算做完一
轮也只是将最大的数字放到了最后,所以还要再次开启循环,才能把每一个都排好.
公式:
for(var j=1;j<arr.length;j++){
for(var i=0;i<arr.length-j;i++){
if(arr[i]>arr[i+1]){
var m=arr[i+1];
arr[i+1]=arr[i];
arr[i]=m;
}
}
}
2、正式开发中:数组的API:arr.sort();
默认:将数组中的元素转为字符串,然后再按位PK每个字符的unicode号(ASCII码)
问题1:希望按照数字升序排序:
arr.sort(function(a,b){此函数叫做匿名回调函数,回调函数不需要我们程序员调用,由前辈们创建好,我们学习如何使用即可,其实前辈们的sort方法,底层里面有一个形参,会接住我们传入的这个回调函数,前辈们悄悄的帮我们调用了,所以不需要程序员自己调用
console.log(a);//后一个
console.log(b);//前一个
return a-b;//如果a-b返回的是一个正数,说明后一个>前一个
如果a-b返回的是一个负数,说明后一个<前一个
如果a-b返回的是一个0,说明后一个==前一个
而sort方法会根据你返回的正数、负数、0,自动考虑要不要交换位置
问题2:希望按照数字降序排序:
arr.sort(function(a,b){
return b-a;
})
特殊:
1、以后只要在网页上发现有排序功能,说明他的底层一定是一个数组,因为JS里面只有数组可以排序
2、以后只要在网页上发现有随机功能,说明他的底层一定用到了随机数公式
7.栈和队列:添加元素和删除元素的新方式:
栈: 其实就是数组,只不过是一端封闭,只能从另一端进
如何使用:
开头进:arr.unshift(新值1,...);//添加元素的新方式,向前添加,缺点:导致其他元素的下标都会发生变化
开头出:var first=arr.shift();//删除元素的新方式,向前删除,一次只能删除一个,也有返回值,返回的是删除的那个元素,缺点:导致其他元素的下标都会发生变化
结尾进:arr.push(新值1,...);//添加元素的新方式,向后添加
结尾出:var last=arr.pop();//删除元素的新方式,向后删除,一次只能删除一个,也有返回值,返回的是删除的那个元素
队列:其实就是数组,只不过只能从一端进入,从另一端出去
何时:按照先来后到的顺序拿取数据
如何使用:
开头进:arr.unshift(新值1,...);//添加元素的新方式,向前添加,缺点:导致其他元素的下标都会发生变化
结尾出:var last=arr.pop();//删除元素的新方式,向后删除,一次只能删除一个,也有返回值,返回的是删除的那个元素
结尾进:arr.push(新值1,...);//添加元素的新方式,向后添加
开头出:var first=arr.shift();//删除元素的新方式,向前删除,一次只能删除一个,也有返回值,返回的是删除的那个元素,缺点:导致其他元素的下标都会发生变化
8.ES5(2014年)为数组提供了3组6个API:
1、判断:2个,判断的结果一定是一个布尔值
every:每一个,要求所有的元素都满足条件,结果才为true,只要有一个不满足则为false,非常类似于我们以前学的&&
var bool=arr.every(function(val,i,arr){
val - 当前的值
i - 当前的值的下标
arr - 数组本身
return 判断条件;
})
some:有一些,要求只要有一个元素满足,则为true,全部不满足才为false,非常类似于我们以前学的||
var bool=arr.some(function(val,i,arr){
return 判断条件;
})
2、遍历:拿到数组中的每个元素做相同 或 相似的操作
forEach - 直接修改原数组:
arr.forEach(function(val,i,arr){
操作
})
map - 不修改原数组,返回一个新数组
var newArr=arr.map(function(val,i,arr){
return 操作;
})
3、过滤和汇总:
过滤:筛选出你需要的部分,但是和现实不太一样,原数组是不会变化的!
var subArr=arr.filter(function(val,i,arr){
return 判断条件;
})
汇总:
var sum=arr.reduce(function(prev,val,i,arr){
return prev+val;
})
这6个API都是为了简化一个人,for循环!!!!!!!!!!!!!!!!
二维数组:数组的元素,又引用着另一个数组
何时使用:在一个数组内,再次细分每个分组 创建: var arr=[[],[],[]];
访问: arr[行下标][列下标];
遍历二维数组:
必然两层循环,外层循环控制行,内层循环控制列
for(var r=0;r<arr.length;r++){
for(var c=0;c<arr[r].length;c++){
console.log(arr[r][c]);
}
}
String的概念:
字符串和数组有相同点:
- 字符串中的个数:str.length;
- 获取字符串中的某个字符:str[i];
- 遍历字符串
- 所有数组不修改原数组的API,字符串也可以使用(concat、slice)
和数组也有很多不同的地方:所有数组的直接修改原数组的API,字符串都不可以使用,比如排序只有数组可以使用
引用/对象类型:11个
String/ Number/ Boolean -> 这三个人具有包装类型
Array Function Date(日期) Math(数学) RegExp(正则:验证)
Error(错误)
Object(面向对象)
Global(全局对象)
StringAPI/字符串的API:
*1、转义字符:*
作用:
1、将字符串中和程序冲突的字符转为原文
"\"" '\''
2、包含特殊功能的符号
换行:\n
制表符:\t 大空格,跟你敲tab效果是一样的
3、输出unicode编码的字符
汉字的第一个字:\u4e00 -> ascii码:19968
汉字的最后一个字:\u9fa5 -> ascii码:40869
2、大小写转换:
将字符串中每个英文字符统一的转为大写 或 小写
何时:只要程序不区分大小写,就要【先统一】的转为大写 或 小写,再比较(做验证码)
如何:
var 大写=str.toUpperCase();
var 小写=str.toLowerCase();
3、获取字符串中的指定位置的字符:
str.charAt(i)===str[i]
4、获取字符串中的指定位置的字符的ASCII码:
var ascii=str.charCodeAt(i);
通过ASCII码转回原文
var 原文=String.fromCharCode(ascii);
5、检索字符串:
检查索引 - 检查下标,获取关键字的下标
var i=str/arr.indexOf("关键字",starti);
从starti位置开始,查找右侧第一个关键字的第一个字符的下标
starti可以省略,默认从0位置开始查找
返回值:
找到了,返回的第一个关键字的第一个字符的下标
没找到,返回-1,其实我们根本不关心下标为多少,我们只管下标为不为-1
作用:判断有没有,只要你不希望有重复的就用它
强调:数组也能使用此方法,数组这个方法其实是后期才添加上的,原本此方法只有字符串可用,比如老IE(8以前)的数组就没有此方法
6、拼接字符串:
var newStr=str.concat(新字符串,...) === 还不如+运算
7、截取字符串:3个
var newStr=str/arr.slice(starti,endi+1);//和数组的用法一模一样
str.substring(starti,endi+1);//几乎和slice一样,但是不支持负数参数
str.substr(starti,n);//n代表截取的个数,不必考虑含头不含尾
8、替换字符串:
var newStr=str.replace("固定关键字"/RegExp,"新内容")
9、去掉开头结尾的空白字符:
str.trim();
str.trimStart();
str.trimEnd();
10、切割/分割字符串:
作用:将字符串切割为数组:str<=>arr
var arr=str.split("自定义切割符");
特殊:
1、切割后,切割符就不存在了
2、如果你的切割符写的就是一个空字符串"",切散每一个字符
Math对象:专门提供了数学计算的API
强调:Math不需要创建,直接使用,由浏览器的JS解释器自动创建
属性:Math有一些属性,涉及到科学计数法,但是几乎用不到,只有Math.PI可能会用到 === 3.1415926.... 这一串数字不需要你自己创建
API:
1、取整:
1、上取整:超过一点点,就会取下一个整数
Math.ceil(num);//小数点位数不能超过15位,否则会失效
2、下取整:无论超过多少,都会省略小数点部分
Math.floor(num);
3、四舍五入取整:
Math.round(num);//只看第一位小数
以上三个方法:都是在取整,而且只能取整
目前我们学过的取整方式:以上三个;*parseInt(str);*num.toFixed(d);num.toFixed(d);
优点:
1、d代表保留的小数位数,而且也带有四舍五入的功能
2、解决浏览器带来的舍入误差,计算机很笨,但是他的记忆力很强,而且速度很快,笨在何处?比如:2-1.6=== 0.3999999999999
缺点:返回的结果是一个字符串,建议搭配parseFloat使用
2、乘方和开方
乘方:Math.pow(底数,幂) === ES9提供了简化:底数**幂
开方:Math.sqrt(num);//只能开平方
3、最大值和最小值:
var max/min=Math.max/min(a,b,d,c,e,f,g...........);//自动在你传入的数字中找到最大值或最小值
问题:默认不支持数组参数
解决:固定用法:Math.max/min.apply(Math,arr);//apply具有打散数组的功能
4、绝对值:把负数变成整数
Math.abs(num)
5、随机数:
Math.random(); -
在0~1之间取一个随机小数
搭配上parseInt,只能取到0,不可能取到1,意味着可以取到最小值,而取不到最大值
公式:parseInt(Math.random()*(max-min+1)+min);
强调:只要网页中某一块带有随机功能,那么他的底层一定用到了随机数
Date对象:日期对象
1.创建
1、创建当前时间:
var now=new Date();
2、*创建一个自定义时间:
var birth=new Date("yyyy/MM/dd hh:mm:ss");
3、创建一个自定义时间:
var birth=new Date(yyyy,MM-1,dd,hh,mm,ss);//修正月份,从0~11月,0代表1月
4、*复制一个日期:
为什么:var end=new Date(start);
日期的所有的API都是直接修改原日期的,无法获得修改之前的日期所以,在执行API之前都要先进行一次复制,然后再操作复制后的日期
2、操作:
-
两个日期对象之间可以相减,得到一个毫秒差(大-小),换算出自己想要的任何一部分 - 日期的本质其实就是保存了一个毫秒数(做出倒计时的关键)
-
API
分量:时间的单位 年月日星期:FullYear Month Date Day 时分秒毫秒:Hours Minutes Seconds Miiliseconds 每一个分类都有一对儿getXXX/setXXX 其中getXXX负责获取一个分量的值 其中setXXX负责设置一个分量的值
特殊:
-
取值范围:日期还会自动进制
FullYear - 当前年份的数字 Month - 0~11 Date - 1~31 Hours - 0~23 Minutes、Seconds:0~59 Day:0~6,0代表星期天,外国人的眼里星期天是一周的第一天 -
任何人都可以set,唯独Day没有set操作
-
如果希望对某个分类进行加减操作的话
date.setXXX(date.getXXX()+/-n) -
格式化日期为本地字符串:
date.toLocaleString(); - 垃圾,具有兼容性问题,我们一般会选择自己封装一个format函数来进行格式化用了此方法会失去一些东西:日期的自动进制,以及日期所有的API但是你也会得到一些东西:字符串所有的API,你可以解锁更多的操作(替换、截取、切割...)
定时器:
1、周期性定时器:
每过一段时间就会执行一次,先等再做,会反复执行,需要自己写停止才能停止
开启:timer=setInterval(callback,间隔毫秒数);
停止:clearInterval(timer);
2、一次性定时器:
开启:timer=setTimeout(callback,间隔毫秒数);
停止:clearTimeout(timer);
BOM:
1、获取浏览器的完整大小:
outerWidth/outerHeight;
2、获取浏览器的文档显示区域(用户能看到的部分)的大小:
innerWidth/innerHeight;
3、获取屏幕的完整大小:
screen.width/height;
打开链接的新方式:
1、当前窗口打开,可以后退
HTML:<a href="">内容</a>
JS:open("url","_self");
2、当前窗口打开,禁止后退
location.replace("新url");
3、新窗口打开,可以打开多个
HTML:<a href="" target="_blank">内容</a>
JS:open("url","_blank");
4、新窗口打开,只能打开一个
HTML:<a href="" target="自定义name">内容</a>
JS:open("url","自定义name");
打开新窗口/新链接:
var newW=open("url","target","width=?,height=?,left=?,top=?");
关闭窗口:
window/newW.close();
改变新窗口的大小:
newW.resizeTo(新宽,新高);
改变新窗口的位置:
newW.moveTo(新x,新y);
window还提供了三个弹出框
警告框:alert("警告文字");
输入框:var user=prompt("提示文字");
确认框:var bool=comfirm("提示文字");
window的专属事件
window.onresize:
创建如果大小发生了变化,就会触发,搭配上上面的innerWidth,我就可以判断现在窗口的大小不同,做不同的操作,他就是css3媒体查询的底层原理
window.onscroll:滚动事件,一旦滚动就会触发
1、获取滚动条当前的位置:window.scrollY
2、获取元素距离页面顶部有多远:elem.offsetTop/offsetLeft
本地/客户端存储技术:
1、sessionStorage - 会话级,只要浏览器一旦关闭,数据就会死亡
2、localStorage - 本地级,只要你不清空他,他就永久存在
操作:
1、添加:xxxStorage.属性名="属性值";
2、读取:xxxStorage.属性名;
3、删除:xxxStorage.removeItem("属性名");
4、清空:xxxStorage.clear();