数据类型转换
强制类型转换:
1、转字符串
1.xx.toString();//undefined和null不能使用,不能使用,去调用任何的属性和方法,因为他们俩不是对象。
2.String(xx);//万能的,但是没什么用:千万不要手动适应,完全等效于隐式转换,还不如+"";
2、转数字
1.parseInt(str/num)-专门用于字符串转为整数的
执行原理:从左向右依次读取每个字符,碰到非数字字符就停止,不认识小数点,一开始就碰到不认识的,则为NaN。
2.parseFloat(str)-专门欧阳姑娘与字符串转为浮点数的
执行原理:几乎个parseInt一致,但是认识第一个小数点
3.Number(xx);万能的,但是没什么用,完全等效于隐式转换,还不如*1 /1 -0。
3、转布尔
Boolean(xx);//万能的,任何人都可以转为一个布尔值,简化版写法:!!xx-简化版也不会用。
哪些会为false? 6个:0,"",undefined,null,NaN,false。其他都为ture
注意:一定要记得那些人会为false,在循环或分支的条件判断种都会带有此隐式转换,隐式转换为布尔值
if(Boolean(条件)){}
运算符和表达式
算术运算
+ - * / %
隐式转换:默认,转为数字再运算
特殊:
1、+运算,只要碰上一个字符串,则变为拼接
2、- * / %,纯数字组成的字符串,也可以转为数字,但是非纯数字的字符串转为NaN
NaN参与任何算术运算结果仍为NaN
比较运算
> < >= <= == != === !==
结果:布尔值
隐式转换:默认,左右两边都会悄悄的转为数字,再比较。
特殊:
1、如果左右【两边】参与比较的都是字符串,则是按位PK每个字符的十六进制的unicode号(十进制ascii码)不需要记忆:但是知道常识
0-9<A-Z<a-z<汉字
汉字:记不了,太多了,20000+个以上,汉字一定比数字和字母的都大
百度搜索:中文字符集 Unicode 编码范围
汉字的第一个字:一(unicode:4E00)-(ascii:19968)
汉字的最后一个字:龥(unicode:9fa5)-(ascii:40869)
了解着玩的常识:汉字的ascii或者unicode号为什么这么大?
2、NaN参与任何比较运算结果都为false,带了一个问题,没有办法使用普通的比较运算判断一个xx是不是NaN
解决:!isNaN(xx); true->有效数字 false->NaN
3、undefined==0,
问题:==区分不开undefined和null,怎么才能区分开?
undefined===null
全等:===,要求值和数据类型都要相同,换句话说,就是不再带有隐式转换
!==,不带隐式转换的不等比较
写一个String()方法的底层原理
function String(x){
if(x===null){
return "null";
}else if(x===undefined){
return "undefined";
}else{
return x.toString();//return 返回
}
}
逻辑运算符
隐式转换:悄悄的都变为布尔,然后综合比较得出结论
&&:全部的条件都为true,结果才为true
只要有一个为false,结果才为false
||:全部的条件都为false,结果才为false
只要有一个为true,结果九尾true
!:颠倒布尔值
特殊:用法
短路逻辑:只要前一个条件已经可以得出最后结论,则后续条件不再执行。
&&短路:如果前一个条件为true,后一个操纵不执行
如果前一个条件为false,后一个操作不执行
简化了简单的分支:if(条件){操作}
语法:条件&&(操作);
||短路:如果前一个条件为true,不需要执行后一个
如果前一个条件为false,需要执行后一个
使用场景:两个值二选一 - 后期做浏览器兼容性(老IE)
e=e||window.event; - 见小案例
位运算
左移:m<<n,读作m左移了n位,相当于m*2的n次方
右移:m>>n,读作m右移了n位,相当于m/2的n次方
缺点:底数永远只能是2
赋值运算
一句话执行了两个操作,先运算,再赋值
+= -= *= /= %= ++ --
何时使用:只要取出变量中的值,在做计算,之后还要在保存回去时,就要试用赋值运算
i+=1 或者 i++
递增:i++; 每次只能+1
累加:i+=n; 每次想加几,随便你
笔试题:++ 分为前++和后++
1、单独使用时,没有参加别的表达式,放前放后都一样
2、如果参与了别的表达式:
变量中的值都会+1
++i,返回的是递增后的新值
i++,返回的是递增前的旧值
三目运算
简化分支:if(){}else{} if(){}else if()else{}
语法:
1、条件?操作1:默认操作;
2、条件1?操作1:条件2?操作2:默认操作;
舍入误差
num.toFixed(n);//带有四舍五入的功能,并能按你传入的n保留n位小数
获取第一个字符的ascii码
var ascii=str.charCodeAt(0);
自定义Function
什么是函数:需要定义好的,可以反复执行的代码段
何时使用:1、不希望打开页面立即执行 2、以后可以反复调用 3、希望绑定在页面元素之上
创建并调用
创建
1、声明方式创建:
function 函数名(形参,...){
函数体;
return 返回值/结果;
}
2、直接量方式:
var 函数名 = function(形参,...){
函数体;
return 返回值/结果;
}
调用
var 接住返回的结果 = 函数名(实参);
//其实return的本意是退出函数,但是如果return后跟着一个数据
//顺便将数据返回到函数作用域的外部,但return只负责返回,不负责保存
//具体需不需要得到函数的结果,看你自己
声明提前
在程序正式执行之前,var声明的变量(轻)和function声明的函数(重),都会悄悄的集中定义在当前作用域的顶部,但是赋值留在原地。
声明创建的函数会完整的提前
直接量方式创建的函数不会完整提前,只有变量部分会提前
按值传递
如果传递的是原始类型的值:
修改一个变量,另一个变量是不会受影响的,其实是复制了一个副本给对方
如果传递的是引用类型的对象:
修改一个变量,另一个变量是会受到影响的,因为大家操作的其实是同一个地址值
预定义的全局函数
前辈们提前创建好的函数,我们可以直接使用,在任何位置都可以使用
编码和解码
编码:var code = encodeURIComponent("xx")
解码: var 原文 = decodeURIComponent(code)
浏览器自带此功能
isFinite(num)
判断num是不是无穷大,ture->有效数字 false->无穷大
哪些会为false:NaN,Infinity,分母为0
eval
eval(str):计算字符串,简单来说就是脱字符串的衣服
分支结构
switch
语法: switch(变量/表达式){
case 值1:
操作1;
case 值2:
操作2;
default:
默认操作
}
特殊:
1、case的比较不带隐式转换
2、问题:默认只要一个case满足后,会将后面的操作全部做完0.
解决:break;
. 00..建议:每一个case的操作后都跟上一个break
3、default可以省略,如果条件都不满足的情况,什么事都不会做
面试题:if vs switch
1、switch...case..缺点:必须要知道准备的结果才能使用,不能做范围判断
2、if...else..缺点:执行效率相对较低,优点:可以范围判断
循环结构
while
while(循环条件){循环体}
do while
do{循环体}while{循环条件}
面试题
while 和 do...while的区别
只看第一次:如果第一次大家都满足,两者没有区别
如果第一次都不满足,while一次都不执行,dowhile至少会执行一次
for
for(循环变量;循环条件;变量的变化){
循环体
}
流程控制语句
退出循环: break;//退出整个循环
continue;//退出本次循环
数组
基础概念:
什么是数组:在一个内存(变量)中保存了多个数据的一个集合结构
何时:只要存储的多个相关的数据,都要用数组集中保存
为什么:一个好的数据结构,可以极大的提升我们程序员的开发效率
创建
1、直接量方式: var arr = [值1,...]
2、构造函数方式: var arr = new Array(值1,...)
访问
数组名[下标];--当前元素
添加/修改:数组名[下标]=新值;
特殊:读取元素,下标越界--返回undefined
添加元素,下标越界--下标不再连续,导致变成一个稀疏数组
三大不限制
1、不限制长度
2、不限制类型
3、不限制下标越界
唯一属性
数组名.length//获取当前数组的长度
三个固定套路:
1、末尾添加:arr[arr.length]=新值
2、获取倒数第n个:arr[arr.length-n]
3、删除倒数n个:arr.length-=n
遍历
对数组中每个元素执行相同或相似的操作
for(var i = 0;i<arr.length;i++){
arr[i]//当前次元素
}
关联(hash)数组
什么是:下标是可以自定义的
为什么:索引数组的下标无具体意义,不便于查找
hash数组的length永远失效,永远为0
创建
1、创建空数组:var arr = [];
2、为数组添加下标并且添加元素:arr["自定义下标"]=新值
访问
arr["自定义下标"]
遍历
for(var i in arr){
i;
}
for in 虽然不能定义从哪里开始,到哪里结束,专门用于遍历数组的,既可以遍历索引数组也可以遍历hash数组
原理
hash算法:将字符串,计算出一个尽量不重复的数字(地址值)
字符串内容相同,则计算出来的数字也一定是相同的
添加元素:将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到这个地址之中
获取元素:将指定的自定义下标交给hash算法,得到一个和当初保存时一样的数字(地址值),通过地址就找到当前保存的数据
js里面的一切东西都是对象,除了undefined和null,一切对象的底层都是hash数组
数组的API
连接数组
var str = arr.join("自定义连接符");
固定套路:
1、笔试题:将数组里面的内容拼接为一句话/单词;
无缝拼接: var str = arr.join("");
2、将数组拼接为DOM页面元素
//数据
var arr = ["北京","南京","西京"]
//转为字符串,并且拼接好标签
var str = "<开始标签>"+arr.join("</结束标签><开始标签>")+"</结束标签>"
//渲染到DOM树上
elem.innerHTML = str;
数组的拼接
添加元素的新方式
将你传入的实参全部拼接到arr的末尾
var newArr = arr.concat(新值)
特殊:1、不会修改原数组,只会返回一个新子数组
2、concat支持传入数组参数,悄悄将你传入的数组打散为单个元素后再拼接
截取子数组
根据你传入的开始下标截取到结尾下标
var subArr = arr.slice(stari,endi+1)
特殊:1、不修改原数组,只会返回一个新子数组
2、含头不含尾
3、endi可以省略不写,会从starti位置一直截取到末尾
4、其实两个是实参都可以省略-从头截到尾,深拷贝,和以前的按值传递(浅拷贝不同),一个修改不会影响到另一个
5、支持负数参数,-1代表倒数第一个
以上API都是不会修改原数组的
以下API都是会修改原数组的
删除、插入、替换
删除:var dels = arr.splice(starti,n);//n代表删除的个数
特殊:其实splice也有返回值,返回的是你删除的元素组成的一个新数组
插入:arr.splice(starti,0,值1,...)
注意:1、原starti位置的元素以及后续元素都会向后移动
2、千万不要插入一个数组,会导致我们的数组一些是一维,一些是二维
替换:var dels = arr.splice(starti,n,值1,...)
注意:删除的元素不必和插入的元素个数相同
翻转数组
arr.reverse();-以后不会使用
排序
两种方式:
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 middle = arr[i];
arr[i]=arr[i+1];
arr[i+1]=middle;
}
}
}
2、正式开发中:
arr.sort();
问题1:默认会将元素们转为字符串,按位PK ascii码,如果希望按数字排序?
解决:
arr.sort(function(a,b){//回调函数
console.log(a);//拿到后一个
console.log(b);//拿到前一个
return a - b;//如果return返回是一个正数,说明后一个数>前一个数
//如果return返回的是一个负数,说明后一个数<前一个数
//如果return返回的是一个0,说明后一个数==前一个数
//而我们的sort方法正好可以根据你返回的正数/负数/0来排序
})
问题2:只能升序排列,如何降序
arr.sort(function(a,b){
return b-a;
})
强调:排序其实非常重要,切记,只要以后页面中有排序功能,他的底层一定是一个数组,因为只有数组具有排序方法
栈和队列
添加元素和删除元素的新方法
栈:其实就是一个数组。只不过是一端封闭,只能从另一端进出的数组
何时:优先使用最新的数据,现实生活中,情况不多
如何:
开头进:arr.unshift(新值,...);//添加元素的新方式,向前添加,缺陷:导致其余元素的下标发生改变
开头出:var first = arr.shift();//删除元素的新方式,向前添加,缺陷:导致其余元素的下标发生改变
结尾进:arr.push(新值,...);//添加元素的新方式,向后添加,完全等效于arr[arr.length]或者arr.concat
结尾出:var last = arr.pop();//删除元素的新方式,向后删除
队列:其实就是数组,只不过一端进,另一端出
何时:根据先来后到的顺序,现实中多
如何:
开头进:arr.unshift(新值,...);
结尾出:var last = arr.pop;
结尾进:arr.push(新值,...);
开头出:var first = arr.shift();
拓展
周期定时器:
开启:timer = setInterval(function(){
操作;
},间隔毫秒数)
停止:clearInterval(timer)
鼠标移入:onmouseenter
鼠标移出:onmouseleava
二维数组
数组的元素,又引用着另一个数组
何时:在一个数组内,希望再次细分每个分类
创建:var arr = [[arr1],[arr2],[arr3]];
访问:arr[行下标][列下标];
特殊:列下标越界,返回undfined
行下标越界,报错
遍历二维数组:必然两层循环:外层循环控制行,内层循环控制列
for(var r = 0;r<arr.length;r++){
for(var c = 0;c<arr[r].length;c++){
console.log(arr[r][c])
}
}
String的概念
什么是字符串:多个字符组成的只读字符数组
和数组有相同的地方:
1、字符串中的个数:str.length
2、获取字符串中某个字符:str[i]
3、遍历字符串
4、所有数组不修改原数组的API,字符串也可以使用(concat,slice)
和数组也有不同的地方:
所有的数组直接修改原数组的API,字符串都不可以,比如排序只有数组可以使用,但是字符串也有很多很多属于自己的API
引用对象类型
String Number Boolean ->包装类型
Array Function Date(日期) Math(数字) RegExp(正则:验证)
Error(错误)
Object(面向对象开发方式)
Global(全局对象)
包装类型
专门将原始类型的值封装为一个引用类型的对象
为什么:原始类型的值原本是没有任何属性和方法,意味着原始类型本身是不支持操作
何时使用:只要试图用原始类型的变量调用属性或者方法时,自动包装
何时释放:方法调用完毕后,自动释放包装类型,并且返回数据
String的API
1、转义字符:\
作用:1、将字符串中和程序冲突的字符转为原文
"\"\""
'\'\''
2、包含特殊功能的符号
换行:\n
制表符:\t
3、输出unicode编码的字符
第一个汉字:\u4e00
最后一个汉字:\u9fa5
大小写转换
何时:只要程序不区分大小写,就要先统一转为大写或者小写
如何: 大写:var upper = str.toUpperCase();
小写: var lower = str.toLowerCase();
获取字符串中指定位置的字符
var newStr = str.charAt(i) === str[i]
获取字符串中指定位置的ASCII码
var ascii = str.charCode(i)
根据ascii码转回原文
var 原文 = String.fromCharCode(ascii);
检索字符串
检查索引,获取关键字的下标
var i = str.indexOf("关键字",starti);
从starti位置开始,查找右侧第一个关键字的位置
starti可以省略,默认从0位置开始查找
返回值:找到,返回的是第一个关键字的第一个字符的下标
没找到,返回-1,
作用:判断有没有
强调:数组也能用此方法
截取字符串
var subStr = str/arr.slice(starti,endi+1);//和数组用法一样 ,支持负数参数,-n代表倒数第n个
str.substring(starti,endi+1);//用法几乎和slice相同,不支持负数参数
str.substr(starti,n);//支持负数参数,n代表截取的个数,不必考虑含头不含尾
拼接字符串
var newStr = str.concat(str1,...)//还不如+运算
替换字符串
var newStr = str.replace("关键字"/正则,"新内容");
切割字符串
作用:将字符串转为数组
var arr = str.split("自定义切割符");
特殊:1、切割后,切割符就不存在
2、切割符"",切散每个字符
拓展
创建空元素
var elem = document.createElement("标签名");
为此空标签添加必要的属性或者事件
elem.innerHTML = "内容";
elem.属性名 = "属性值";
elem.on时间名 = function(){};
渲染到DOM树上
父元素.appendChild(新元素)
小案例
获取四位随机数
var arr = [],
code = "";
function f1(a, b) {
for (var i = a; i <= b; i++) {
arr.push(String.fromCharCode(i));
}
}
f1(48, 57);
f1(65, 90);
f1(97, 122);
console.log(arr);
while (code.length < 4) {
var a= parseInt(Math.random() * arr.length);
if(code.indexOf(a)==-1){
code+=arr[a];
}
}
var user= prompt("请输入验证码"+ code);
(user.toUpperCase()==code.toUpperCase())?alert("验证成功"):alert("验证失败");
根据数据渲染表格
var str = "tom@补给兵@60%#mary@医疗包@80%#john@特种兵@100%";
var table = document.createElement("table");
var newstr = str.split("#");
var arr = ["姓名", "兵种", "血量"];
var tr = document.createElement("tr");
for (var i = 0; i < arr.length; i++) {
var td = document.createElement("td");
td.innerHTML = arr[i];
tr.appendChild(td);
}
table.appendChild(tr);
for (var i = 0; i < newstr.length; i++) {
var tr = document.createElement("tr");
var newstr1 = newstr[i].split("@");
for (var j = 0; j < newstr1.length; j++) {
var td = document.createElement("td");
td.innerHTML = newstr1[j];
tr.appendChild(td);
}
table.appendChild(tr);
}
bd.appendChild(table);
淡入淡出轮播图-未封装版
var btn = document.getElementsByTagName("button"),
img = document.getElementsByTagName("img"),
li = document.getElementsByTagName("li"),
j = 0,
cal = document.getElementsByClassName("carousel")[0];
console.log(cal)
for (i in btn) {
btn[i].onclick = function () {
if (this.innerText == ">") {
j++;
j == li.length && (j = 0);
for (var i = 0; i < li.length; i++) {
img[i].className = " ";
li[i].className = " ";
}
img[j].className = "active";
li[j].className = "active";
} else {
j--;
j == -1 && (j = li.length - 1);
for (var i = 0; i < li.length; i++) {
img[i].className = " ";
li[i].className = " ";
}
img[j].className = "active";
li[j].className = "active";
}
};
}
time = setInterval(function () {
j++;
j == li.length && (j = 0);
for (var i = 0; i < li.length; i++) {
img[i].className = " ";
li[i].className = " ";
}
img[j].className = "active";
li[j].className = "active";
}, 2000);
淡入淡出轮播图-封装版
<body>
<div class="carousel">
<div class="carousel_img">
<img class="active" src="../images/1.jpg" />
<img src="../images/2.jpg" />
<img src="../images/3.jpg" />
</div>
<img src="../images/3.jpg" />
<button><</button>
<button>></button>
<ul>
<li dy="0" class="active"></li>
<li dy="1"></li>
<li dy="2"></li>
</ul>
</div>
<script type="text/javascript">
var btns = document.getElementsByTagName("button"),
imgs = document.getElementsByTagName("img"), //[img,img,img,img]
lis = document.getElementsByTagName("li"), //[li,li,li]
car = document.getElementsByClassName("carousel")[0], //[li,li,li]
j = 0; //计数器
for(var i in btns) {
btns[i].onclick = function() {
if(this.innerText == ">") {
animate(1);
} else {
animate(-1);
}
}
}
for(var i in lis) {
lis[i].onclick = function() {
animate(0,this);
}
}
timer = setInterval(function() {
animate(1);
}, 1000)
car.onmouseenter = function() {
clearInterval(timer);
}
car.onmouseleave = function() {
timer = setInterval(function() {
animate(1);
}, 1000)
}
function animate(num,li) {//num==0 li==this
if(num){
j+=num;
if(j==lis.length){j=0}else if(j==-1){j=lis.length-1}
}else{
j=parseInt(li.getAttribute("dy"));
}
for(var i = 0; i < lis.length; i++) {
lis[i].className = "";
imgs[i].className = "";
}
imgs[j].className = "active";
lis[j].className = "active";
}
</script>
</body>
二级联动
var arr = ["-请选择-", "北京", "南京", "西京", "东京", "重庆"];
var arr1 = [
["-请选择-"],
["天安门", "玄武门", "朝阳"],
["南京1", "南京2", "南京3"],
["西京1", "西京2", "西京3"],
["东京1", "东京2", "东京3"],
["重庆1", "重庆2", "重庆3"],
];
sel.innerHTML = "<option>" + arr.join("</option><option>") + "</option>";
sel.onchange = function () {
var i = this.selectedIndex;
var newarr1 = arr1[i];
sel1.innerHTML =
"<option>" + newarr1.join("</option><option>") + "</option>";
};
sel.onchange();
购物车-封装版
<!DOCTYPE html>
<html>
<head>
<title>new document</title>
<meta charset="utf-8" />
</head>
<body>
<table id="tbl">
<thead></thead>
<tbody>
<tr>
<td>iphone6</td>
<td>4488</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>4488</td>
</tr>
<tr>
<td>iphone7</td>
<td>5488</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>5488</td>
</tr>
<tr>
<td>iphone8</td>
<td>6488</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>6488</td>
</tr>
<tr>
<td>RTX 3090</td>
<td>20000</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>20000</td>
</tr>
<tr>
<td>RTX 3080</td>
<td>16000</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>16000</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">总计:</td>
<td id="total">0</td>
</tr>
</tfoot>
</table>
<script type="text/javascript">
var btn = document.getElementsByTagName("button");
var total = document.getElementById("total");
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
if (this.innerText == "+") {
cacl(1,this)
} else {
cacl(-1, this);
}
moneytotal();
};
}
moneytotal();
function moneytotal() {
var tbody = document.getElementsByTagName("tbody")[0];
var trs = tbody.children;
for (var i = 0, sum = 0; i < trs.length; i++) {
sum += parseInt(trs[i].lastElementChild.innerText);
}
total.innerHTML = sum;
}
function cacl(num, btn) {
if (num == 1) {
var span = btn.previousElementSibling;
} else {
var span = btn.nextElementSibling;
}
var jia = parseInt(span.innerText) + num;
span.innerHTML = jia;
var price = btn.parentNode.previousElementSibling;
var up = parseInt(price.innerHTML);
var money = btn.parentNode.nextElementSibling;
var money1 = parseInt(money.innerText);
money.innerHTML = jia * up;
}
</script>
</body>
</html>