数据类型转换
显式转换
1.转字符串
xx.toString(); undefined / null 不可使用
String() 万能转换法 等效隐式转换的+
2.转数字
parseInt()
parseFloat()
Number() 万能转换法 等效隐式转换-0 *1 /1 %1
3.转布尔
Boolean() 万能转换法 等效!!()
只有6个值转换结果为false:0,"",undefine,null,NaN,false
常用于循环/分支的判断条件
隐式转换
运算符和表达式
1.算术运算符 +-*/%
- 具有隐式转换,默认转为数字再运算
- 特殊使用
- +运算 只要碰上一个字符串,两边都会默认转换字符串,进行拼接
- -*/%运算 只要是纯数字组成的字符串,都会转为数字在运算
2.比较运算符 < > <= >= == != === !==
- 运算的结果: true / false
- 具有隐式转换,默认转为数字再进行比较
- 注意:
-
若参与比较的两个都是字符串,按位比较每个字符的十六进制Unicode号或十进制ASCII码
- 0-9 < A-Z < a-z < 汉字
- 汉字第一个:一 4e00(19968)
- 汉字最后一个:9fa5(40869)
-
NaN:参与任何比较运算,结果都为false
- 解决:!isNaN() (数字-结果为false;NaN-结果为false)
-
undefined==null
- 结果:true
- 解决:使用===,数据类型和值都相同时,结果才为true
//String(); 执行原理:任何东西都可以转换为字符串
function String(x){
if(x===null){
console.log(null)
}else if(x===undefined){
console.log(undefined}
}else{
console.log(x.toString())
}
}
3.逻辑运算符 && || !
短路逻辑
只要前一个条件已经可以得出结论,则后续条件不执行
- &&:简化if(){}
if(total>=500){total*=0.8;}
total>=500&&(total*=0.8);
- ||:两个值二选一,可用于兼容
4.位运算
左移:m<<n 读作:m左移了n位,实际是m*2的n次方
8*2*2*2*2 == 8<<4
右移:m>>n 读作:m右移了n位,实际是m/2的n次方
8/2/2/2/2 == 8>>4
5.赋值运算 += -= *= /+ %= ++ --
-
递增和累加
- 递增:i++ 每次只能+1
- 累加:i+=n 每次加的数字可以自定义
-
++i 和 i++ 的区别
- ++i 返回的是加了1之后的新值
- i++ 返回的是加了1之后的旧值
6.三目运算
-
简化if...else
条件?操作1:默认操作; -
简化if...else if...else
条件1?操作1:条件2?操作2:条件3?操作3:默认操作; -
注意
- 只能完成【简单】的分支:操作只能有一句话
- 默认操作不能省略
自定义函数/方法
使用
创建/定义/声明函数&返回结果(2种方法)
- 声明方式:用function关键字进行声明 只有变量/常量/函数具有声明方式
function 函数名(形参,...){ 函数体 return 返回值; }
- 直接量方式(函数名也是一个变量)
var 函数名=function(形参,...){ 函数体 return 返回值; }
调用函数&接住结果
var result=函数名(实参,...);
return
本意是退出函数,但若后面跟着一个数据,则可将数据返回到全局作用域,但返回值不会自动保存,所以需要创建一个变量保存结果
- return 一个函数只能使用一次,最好写在函数体后面
- 何时使用:并不是任何时候都需要使用return
- 全局想要使用局部时
- 调用完函数还想拿到函数结果进行后续操作时
- 若无return,会有默认返回值undefined
作用域
全局作用域
【全局变量】和【全局函数】,在任何位置都可以访问/使用
局部作用域
【局部变量】和【局部函数】,只能在当前【函数调用时内部可用】
- 变量的使用规则:优先使用自己的,自己没有找全局,全局都没有报错
- 不要对未声明的变量直接赋值,会导致全局污染:所有的变量在使用之前都一定要先var,不能对着没有var变量直接赋值
- 局部变量:
- 直接在函数作用域中创建的变量
- 形参
声明提前
程序执行前,将var声明的变量和function声明的函数,集中提前到当前作用域的顶部,但:1.赋值留在原地;2.变量比函数轻,变量在前
//1
var a=10;
function f1(a,b,c){
console.log(a);//undefined
var a=20;
console.log(a);//20
}
f1();
console.log(a);//10
//2
function fn(){
console.log(2);
}
fn();//2
var fn=100;
fn();//报错:fn不是一个方法
//3
var fn=function(){
console.log(1)
};
fn();//1
var fn=100;
fn();//报错
var fn=function(){
console.log(2)
};
function fn(){
console.log(3)
};
fn();//不执行
//4
function fn(){
console.log(1)
}
fn();//1
var fn=100;
var fn=function(){
console.log(2)
}
fn();//2
//5
function fn(){
console.log(1);
}
fn();
var fn=100;
var fn=function(){
console.log(2);
}
fn();
function fn(){
console.log(3);
}
fn();
按值传递
两个变量之间进行赋值
- 传递原始类型的值:两个变量之间赋值、做操作互不影响
- 传递引用类型的值:(Array、Function) 两个变量之间赋值、做操作会互相影响,因为引用类型传递的是地址值,共用地址值
预定义的全局函数
编码和解码
前端将用户输入的网址的中文编码为单字节字符,后端再将前端传递的内容解码为原文
- 编码
var code=encodeURIComponent("str"); - 解码
var 原文=decodeURIComponent(code);
isFinite(num)
判断num是否再有效范围内
- 三种情况会为false:分母为0,NaN,Infinity
重要的:parseInt/Float()、eval()、isNaN()
分支结构
if...else结构
switch...case结构
switch(变量/表达式){ case 值1: 操作1; break; case 值2: 操作2; break; default: 默认操作; }
注意:
- 默认只要满足一条路,会把后面的所有操作做完 -->break:通常放在操作后面
- 最后的default默认操作不用加break
- 连续多个操作相同,可省略中间部分
- 不具有隐式转换
- default可以省略
if 和 switch的比较
switch
优点:效率相对较高,因为不需要做任何范围判断
缺点:不能实现范围判断,必须要知道用户有可能输入的结果是什么才能使用
if
优点:实现范围判断
缺点:效率相对较低
循环结构
while循环
var 循环变量=几; while(循环条件){ 循环体; 变量变化; }
do...while循环
var 循环变量=几; do{ 循环体; 变量变化; }while(循环条件)
while 和 do...while的区别?只看第一次
-
如果第一次大家都满足条件,两者没有区别,无非do...while更麻烦
-
如果第一次大家都不满足条件,while一次都不会执行,而do...while至少会执行一次
for循环
for(var 循环变量=几;循环条件;变量变化{循环体}
循环终止语句:
- break 退出整个循环
- continue 退出本次循环
数组
1.创建:2种
-
直接量:
var arr=[值1,....]; -
构造函数:
var arr=new Array(值1,....);//缺陷:
new Array(3);//设置一个长度为3的空数组
2.访问
获取:arr[i]; 下标越界:得到undefined
添加/替换:arr[i]=新值; 下标越界:得到稀疏数组
3.三大不限制:不限制长度、类型、下标越界
4.length
获取倒数第n个元素:arr[arr.length-n];
向末尾添加元素:arr[arr.length]=新值
缩容:arr.length-=n;
5.遍历
for(var i=0;i<arr.length;i++){ arr[i];//当前次元素 }
6.如何释放一个引用类型
找到这个引用类型对象有几个变量名引用着,每个变量都要释放才能真的释放干净
7.数组分类
索引数组:下标都是数字组成的数组
关联(hash)数组:下标是可以自定义的数组
-
创建:2步
- 创建一个空数组:var arr=[];
- 添加自定义下标并且赋值:arr["自定义"]=值
-
访问:
arr["自定义下标"]; -
遍历:把所有的元素都取出来执行 相同 或者 相似的操作
问题:不能使用for循环,因为length失效了,关联数组永远为0,而且下标也在是一个数字
解决:for in循环
for(var i in 数组名){ 数组名[i] }不光可以遍历关联数组,也可以遍历索引数组
-
JS中除了undefined和null不是一个对象,万物皆对象,而且一切对象的【底层都是hash数组】
-
hash数组的原理:
-
hash算法:将字符串交给hash算法,会得到一个尽量不重复的数字,但是字符串内容相同的,那么得到的数字一定也是相同的
-
添加元素:将自定义的下标交给hash算法,得到一个数字(地址值),把要保存的数据放到那个地址之中
-
获取元素:将指定的下标交给hash算法,得到一个和添加时完全相同的数字(地址值),得到这个地址值之中保存的数据
-
数组的API
1. 数组转字符串
var str=arr.join("自定义连接符");
注意:
-
如果没有传入实参,则和toString/String,完全一样,默认由,分割
-
固定使用
- 提供一个数组给你,无缝拼接数组里面的内容变为一个字符串
var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
var str=arr.join("")
console.log(str);//"hello world";
- 将数组中的数据拼接为页面上的元素:初级版数据渲染
var cities=["北京","南京","西京","东京","重庆"];
var str="<option>"+cities.join("</option><option>")+"</option>";
sel.innerHTML=str;//innerHTML可以识别标签
//二级联动
//1.必须使用二维数组,而且二维数组的数据顺序一定要和一级的对应上
//2.select专属事件:select.onchange:状态改变事件:选中项发生改变才会触发
//3.select具有一个属性:this.selectedIndex;获取选中项的下标 - 只有select不需要自定义下标
//4.其实绑定事件的部分就是函数名,也可以拿来调用
<!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>
</head>
<body>
<select name="" id=""></select>
<select name="" id=""></select>
<script>
var sel1=document.getElementsByTagName("select")[0],
sel2=document.getElementsByTagName("select")[1];
var cities=["-请选择-","北京","南京","东京","西京","重庆"],
counts=[
["-请选择-"],
["-请选择-","东城区","海淀区","通州"],
["-请选择-","玄武区","秦淮区","鼓楼区","雨花台区"],
["-请选择-","开封","汴京","龙亭区","杞县","兰考县"],
["-请选择-","西安","碑林区","未央区","长安区","临潼区"],
["-请选择-","渝中区","江北区","南岸区","渝北区","巴南区"]
]
sel1.innerHTML="<option>"+cities.join("</option><option>")+"</option>";
sel1.onchange=function(){
var i=this.selectedIndex;
sel2.innerHTML="<option>"+counts[i].join("</option><option>")+"</option>"
}
sel1.onchange();
</script>
</body>
</html>
2.拼接数组
var newArr=arr.concat(值1,arr1...);
注意:
- 此方法不修改原数组,只会返回一个新数组
- 此方法传参支持数组参数,并且会悄悄的打散这个数组,单独传入
3.截取子数组
var subArr=arr.slice(starti,endi+1)
从starti位置截取到endi+1位置的元素,组成一个新数组
注意:
-
此方法不修改原数组,只会返回一个新数组
-
含头不含尾,从strati 到 endi,不含endi-1
-
第二实参可以省略:从starti截到末尾
第一实参也可以省略:从头截到尾 - 昨天按值传递(浅拷贝)
深拷贝:复制了一个副本给对方
-
支持负数参数,-1代表倒数第一个
4.删除、插入、替换
删除:var dels=arr.splice(starti,n);//从starti开始删除n个
特殊:此方法其实有返回值,所有删除的元素组成的一个新数组
插入:arr.splice(starti,0,值1,...);//从starti开始删除0个,插入了新元素
特殊:原来starti位置的元素以及后续元素都会被向后移动
替换:var dels=arr.splice(starti,n,值1,...);
特殊:插入的个数和删除的个数可以随意
5.翻转数组
arr.reverse();
6.排序
arr.sort();
注意:
- 默认按照字符串按位PK每个字符的unicode号排序
- 按照数字排序
//正序:从小到大
arr.sort(function(a,b){
return a-b;
})
//降序:从大到小
arr.sort(function(a,b){
return b-a;
})
-
function(){}回调函数:不需要程序员调用的函数:悄悄的带有循环,提供了两个形参:a是后一个数,b是前一个数
-
return a-b
- 如果a>b,返回是一个正数
- 如果a<b,返回是一个负数
- 如果a==b,返回是一个0,sort根据你反复的结果,来判断两者要不要交换位置
//冒泡排序:把数组中的每一个数字取出来,前一个和后一个进行比较,如果前一个>后一个,两者就要交换位置:
var arr=[13,25,4,3675,12,23,3,215,2,1,42,4,65,473,2431,123];
for(var j=0;j<arr.length-1;j++){
for(var i=0;i<arr.length-(j+1);i++){
if(arr[i]>arr[i+1]){
var m=arr[i];
arr[i]=arr[i+1];
arr[i+1]=m;
}
}
}
console.log(arr);
7.栈和队列
栈
一端封闭,只能从另一端进出的操作
开头进:arr.unshift(值1,...);
开头出:var first=arr.shift();//一次只能删掉一个,并且会返回删除的元素
结尾进:arr.push(值1,...);
结尾出:var last=arr.pop();//一次只能删掉一个,并且会返回删除的元素
队列
只能从一端进入,另一端出
//轮播
<!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>
*{
margin: 0;
padding: 0;
}
.banner{
position: relative;
}
img{
width: 100%;
}
.banner>div{
height:20px;
width: 30px;
background: rgb(255, 255, 255,0.5);
line-height: 20px;
text-align: center;
color:#333;
font-size:18px;
position:absolute;
top:50%;
margin-top: -10px;
}
.banner>div:nth-of-type(1){
border-radius:0 10px 10px 0;
left: 0;
}
.banner>div:nth-of-type(2){
border-radius:10px 0 0 10px;
right: 0;
}
</style>
</head>
<body>
<div class="banner">
<img src="./img/1.jpg" alt="">
<div class="button"><</div>
<div class="button">></div>
</div>
<script>
var images=["./img/1.jpg","./img/2.jpg","./img/3.jpg"],
btns=document.getElementsByClassName("button"),
img=document.getElementsByTagName("img")[0];
var div=document.getElementsByClassName("banner")[0];
for(var i=0;i<btns.length;i++){
btns[i].onclick=function(){
if(this.innerText==">"){
var first=images.shift();
images.push(first);
img.src=images[0]
}else{
var last=images.pop();
images.unshift(last);
img.src=images[0];
}
}
}
timer=setInterval(function(){
var first=images.shift();
images.push(first);
img.src=images[0]
},1000);
div.onmouseover=function(){
clearInterval(timer);
}
div.onmouseout=function(){
timer=setInterval(function(){
var first=images.shift();
images.push(first);
img.src=images[0]
},1000);
}
</script>
</body>
</html>
二维数组
创建
var arr=[["张三丰",128,3500],["张翠山",30,4500],["张无忌",18,5500]];
访问
arr[r][c];
- 列下标越界:返回undefined
- 行下标越界:报错:undefined不能使用[]
遍历二维数组
必然需要两个循环嵌套:外层循环控制行,内层循环控制列
for(var r=0;r<arr.length;r++){
for(var c=0;c<arr[r].length;c++){
console.log(arr[r][c]);
}
}
- 定时器
开启定时器:
timer=setInterval(function(){操作},间隔毫秒数)
关闭定时器:clearInterval(timer);
2、鼠标移入:onmouseover
3、鼠标移除:onmouseout
//淡入淡出轮播
<!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>
* {
margin: 0;
padding: 0;
list-style: none;
}
img {
width: 100%;
vertical-align: top;
opacity: 0;
}
.banner {
position: relative;
}
.banner>.banner_img>img {
position: absolute;
left: 0;
top: 0;
transition: all 1s linear;
}
.banner>button {
height: 30px;
width: 40px;
background: rgba(0, 0, 0, 0.3);
border: none;
font-size: 20px;
text-align: center;
line-height: 30px;
cursor: pointer;
position: absolute;
top: 50%;
margin-top: -15px;
}
.banner>button:active {
background: rgba(0, 0, 0, 0.5);
}
.banner>button:nth-of-type(1) {
left: 0;
border-radius: 0 15px 15px 0;
}
.banner>button:nth-of-type(2) {
right: 0;
border-radius: 15px 0 0 15px;
}
.banner>ul {
width: 60px;
text-align: center;
display: flex;
justify-content: space-around;
position: absolute;
left: 50%;
margin-left: -30px;
bottom: 15px;
}
.banner>ul>li {
width: 10px;
height: 10px;
border-radius: 50%;
background: #999;
cursor: pointer;
}
img.active {
opacity: 1;
}
.banner>ul>li.active {
background: #eee;
}
</style>
</head>
<body>
<div class="banner">
<div class="banner_img">
<img src="./img/1.jpg" alt="" class="active">
<img src="./img/2.jpg" alt="">
<img src="./img/3.jpg" alt="">
</div>
<img src="./img/2.jpg" alt="">
<button><</button>
<button>></button>
<ul>
<li cli="0" class="active"></li>
<li cli="1"></li>
<li cli="2"></li>
</ul>
</div>
<script>
var btns=document.getElementsByTagName("button"),
lis=document.getElementsByTagName("li"),
imgs=document.getElementsByTagName("img"),
j=0,
div=document.getElementsByClassName("banner")[0];
for(var i=0;i<btns.length;i++){
btns[i].onclick=function(){
if(this.innerText==">"){
j++;
j==lis.length&&(j=0);
for(i=0;i<lis.length;i++){
lis[i].className="";
imgs[i].className="";
}
lis[j].className="active";
imgs[j].className="active";
}else{
j--;
j==-1&&(j=lis.length-1);
for(i=0;i<lis.length;i++){
lis[i].className="";
imgs[i].className="";
}
lis[j].className="active";
imgs[j].className="active";
}
}
}
for(var i=0;i<lis.length;i++){
lis[i].onclick=function(){
j=this.getAttribute("cli");
for(i=0;i<lis.length;i++){
lis[i].className="";
imgs[i].className="";
}
lis[j].className="active";
imgs[j].className="active";
}
}
timer=setInterval(function(){
j++;
j==lis.length&&(j=0);
for(i=0;i<lis.length;i++){
lis[i].className="";
imgs[i].className="";
}
lis[j].className="active";
imgs[j].className="active";
},2000)
div.onmouseover=function(){
clearInterval(timer);
}
div.onmouseout=function(){
timer=setInterval(function(){
j++;
j==lis.length&&(j=0);
for(i=0;i<lis.length;i++){
lis[i].className="";
imgs[i].className="";
}
lis[j].className="active";
imgs[j].className="active";
},2000)
}
</script>
</body>
</html>
String
概念
多个字符组成的【只读】字符【数组】
- 字符串也可以叫数组
-
和数组有共同点:
- 支持下标 - 获取某个字符
- 支持length - 字符的长度
- 遍历
- 数组不修改原数组的API,字符串也可以使用(concat、slice)
-
不同点:数组修改原数组的API,字符串都不可以使用,但是字符串也有很多属于自己的API
- 只读:字符串中的所有的API都不会修改原字符串,只会返回新字符串
引用类型的对象: 11个
String(字符串) Number(数字) Boolean(布尔) - 具有包装类型
Array(数组) Function(函数) Math(数学) Date(日期) RegExp(正则) Error(错误) Object(面向对象)
Global - 全局对象:在浏览器端被window对象给代替了:window对象可以省略不写出来
包装类型
将原始类型的值变为一个引用类型的对象
- 为什么:前辈们发现字符串/数字/布尔经常都会被拿来使用,所以提前提供了包装类型封装为一个引用类型的对象,提供我们一些属性和方法(便于程序员操作)
- 何时使用:只要在你试图用原始类型的值去调用属性或者方法时,会自动套上包装类型
- 何时释放:属性或方法调用完毕后,包装类型自动释放
- 为什么undefined和null不能使用.:不具有包装类型,没有任何的属性和方法
String的API
\ 转义
- 字符串中如果出现了和字符串冲突的符号,可用\将其转义为原文"
- 特殊功能
- 换行:\n
- 制表符:\t
- 可以书写unicode号 表示一个字\uXXXX
- 汉字的第一个字4e00 汉字的最后一个字9fa5
1.转换大小写
【统一的】转为大写或小写,再比较,忽略大小写:- 验证码
大写:var newStr=str.toUpperCase();
小写:var newStr=str.toLowerCase();
2.ascii码
获取字符串中指定位置的字符的ascii码var ascii=str.charCodeAt(i);
通过ascii码转回原文var 原文=String.fromCharCode(ascii);
3.检索字符串
var i=str/arr.indexOf("关键字",starti);
检查索引/下标:从starti位置开始找右侧的第一个关键字的下标
注意:
- starti可以省略,若省略则从0开始
- 返回值:找到则返回第一个字符的下标;没找到则返回-1
- 数组也可以使用该方法
- 找到所有关键字的位置
var str="no zuo no die no can no bibi";
var i=-1;
while((i=str.indexOf("no",i+1))!=-1){
console.log("找到了:"+i);
}
4.拼接字符串
var newStr=str.concat(str1,str2...)
5.截取字符串(3种)
var subStr=str/arr.slice(starti,endi+1);
var subStr=str.substring(starti,endi+1);不支持负数参数
*var subStr=str.substr(starti,n);截取的个数,不必考虑含头不含尾
6.替换字符串-配合正则使用
var newStr=str.replace("关键字"/正则表达式,"新内容");
7.切割/分割字符串
作用:str <=> arr
var arr=str.split("自定义切割符");
注意:
- 切割符可以自定义,切割过后返回一个数组,数组中不再包含切割符
- 如果传入的切割符是一个"",每一个字符都会被切开
创建元素并且渲染页面
-
创建空标签
var elem=document.createElement("标签名"); -
设置必要的属性或事件
elem.属性名="属性值";
elem.on事件名=function(){函数体} -事件都可以在创建时提前绑定上
- 创建好的元素渲染到DOM树上
父元素.appendChild(elem);
//将数据渲染到页面上,形成表格
<!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>
*{
margin: 0;
padding: 0;
}
table{
width: 900px;
margin:50px auto;
text-align: center;
border:1px solid #000;
border-collapse: collapse;
}
td{
border:1px solid #000;
}
</style>
</head>
<body>
<script>
var body=document.getElementsByTagName("body")[0];
var str="Tom@补给兵@60%#Mary@医护兵@80%#John@特种兵@30%";
var table=document.createElement("table");
var arr=str.split("#");
for(var i=0;i<arr.length;i++){
var tr=document.createElement("tr");
var people=arr[i].split("@");
for(var j=0;j<people.length;j++){
var td=document.createElement("td");
td.innerHTML=people[j];
tr.appendChild(td);
}
table.appendChild(tr);
}
body.appendChild(table);
</script>
</body>
</html>