一、JavaScript基础
(一)概念
JavaScript简称js是一门运行在浏览器端的解释型弱类型面向对象的脚本语言
1. 浏览器端(运行环境):
自带JavaScript解释器(打开浏览器就可以自动运行)
2. 解释型:
执行前不进行编译,直接运行,遇到错误就停止运行
3.弱类型:
变量类型无需定义,根据数据类型决定
4.面向对象:
对象名.属性值; 对象名.方法名();
(二)使用方法
1.直接在HTML页面写
<script>
代码
</script>
2.创建js文件,引入HTML页面
<script src="文件路径">
** 不可以写代码 **
</script>
(三)输出方式
1.控制台输出
console.log(输出内容);//如果输出字符串,使用引号包裹
2.在页面上输出
document.Write(输出内容);//搭配hover事件会导致替换页面原本内容,不推荐
3.通过警告框输出
alert(输出内容);//会卡住整个页面,影响用户体验感,不推荐
(四)变量和常量
1.变量
var 变量名=值;//创建后值可以修改
*变量创建规则
1.变量名不以数字开头
2.使用驼峰命名法或下划线命名法
3.尽量做到见名之意
4.尽量不使用拼音
5.变量名不可为关键字
6.变量名为name时无论是什么类型都默认转为字符串
7.变量不赋值则默认为undefined,无意义
8.可以同时定义多个变量(var 变量名1=值1,变量名2=值2;)
2.常量
const 常量名=值;//创建后不能修改
(五)数据类型
1.原始类型
| 数据类型名 | 意思 | 数量 | 颜色 | 意义、用法 |
|---|---|---|---|---|
| number | 数字 | 无数个 | 蓝色 | 直接写 |
| string | 字符串 | 无数个 | 黑色 | 需要加引号,单双均可 |
| boolean | 布尔变量 | 两个 | 蓝色 | 只能取true或false,用于条件判断 |
| null | 空 | 一个就是null | 灰色 | 用于释放变量或内存,提升性能 |
| undefined | 未被定义 | 一个 | 灰色 | 没有意义 |
2.引用/对象类型:共11个
3.强制数据类型转换
在隐式转换无法满足需求时使用,页面上一切数据js获取之后都转为字符串类型
undefined和null不能用于做任何操作,因为它们不是对象
1.转为字符串:
(1)var str=x.toString();
x的类型不能是undefined和null,会报错
(2)var str=String(x);完全等效于隐式转换,还不如+"",不能自己手动使用
2.转为数字
(1)parseInt(string/num) parse:解析 Int:整型
专门用于将字符串转换为整数,也可以转换其他类型的数字
执行原理:从左向右依次转换,遇到非数字就停止,不能识别小数点
(2)parseFloat(string) Float:浮点型小数
专门用于将字符串转换为小数
执行原理:与parseaInt类似,但是能识别第一个小数点
(3)Number(x);完全等效于隐式转换,还不如-0 *1 /1,不能自己手动使用
3.转为布尔
只有 0,"",undefined,NaN,null,false会被转换为false,其他的都是true
Boolean(x);完全等效于隐式转换,还不如!!x,不能自己手动使用
在分支或者循环条件中,自带此方法
只要不是以上六个值就是true
(六)运算符
| 运算符类型 | 运算符 | 特殊点 |
|---|---|---|
| 算数运算符 | + - * / % | 1.%取余,取除不尽的余数 [1、一般用于判断奇偶(任意数%2)] [2、取任何数的后n位(1024%10可以取到4,1024%100可以取到24)] 2.带有隐式转换,将左右转为数字再进行计算(+除外) [null==0] [true==1] [false==0] [undefined==NaN] ["10px"==NaN] 3.NaN:Not A Number 是数字类型但不是一个有效数字 [参与任何算术运算结果都为NaN] [参与任何比较运算结果都为false] 4.如果+两边有字符串,则默认将两边都变成字符串,进行拼接 |
| 比较/关系运算符 | > < >= <= == != === !== | 1.带隐式转换,默认转为数字再比较 2.结果一定是一个布尔值(true或false) 3.如果参与比较的都是字符串,则按位比较每个字符的十六进制unicode号或十进制ACSII码 [unicode/ASCII的大小:0-9<A-Z<a-z<汉字] [汉字第一个字:一,unicode:4e00,ASCII:19968] [汉字最后一个字:龥,unicode:9fa5,ASCII:40869] 4.NaN参与任何比较结果都是false,即使是两个NaN进行比较 5.===表示全等,数据类型和值都相等才是全等 6.!==不带隐式转换的不等比较 [undefined==null,undefined!==null(值相等但类型不同)] |
| 赋值运算符 | = += -= *= /= %= | 1.=表示赋值,将右边的值保存到左边的变量名中 2.剩下的表示运算后再将值保存到变量名下 [i+=1 <==> i=i+1] |
| 逻辑运算符 | 与或非 | 1.是一种综合比较,结果一定是一个布尔值 2.与,全部条件满足则为true,一个条件不满足就false 3.或,一个满足就为true,全都不满足则为false 4.非,改变其布尔值,!true表示false |
| 自增自减运算符 | ++ -- | 1.自增,++,固定每次+1 2.自减,--,固定每次-1 3.++i和i++的区别 [单独使用没有区别] [参与其他运算时,变量本身+1,但返回结果不同] [++i返回加后的新值] [i++返回加之前的旧值] |
二、程序的流程控制语句
(一)顺序结构
默认从上向下执行
(二)分支结构
做判断时使用
1.if...else
语法:
(1)一个条件,一种操作
if(条件){
操作;
}
(2)一个条件,两种操作
if(条件){
操作1:;
}else{
操作2;
}
(三)多个条件,多种操作
if(条件1){
操作1; //分支选择一种执行,条件应该从严格向宽松写
}else(条件2){
操作2;
}else{
操作三
}
2.switch
语法:
switch(变量/表达式){
case 值1: //中间多个case值操作相同时可以省略中间部分
操作1; //如:
break; //case 值1:
case 值2: //case 值2:
操作2; //case 值3:
break; //case 值4:
case 值3: //操作;
操作3; //break;
break;
default: //default后边可以省略break
默认操作;
}
3.三目运算:可以简化分支
语法:
条件?操作:默认操作 等价于 if...else...
条件1?操作1:条件2?操作2:默认操作 等价于 if...else if... else...
ps: 默认操作省略了会报错,操作语句大于一句就不能使用三目运算
面试题1:if...else和switch...case的区别是什么?
答: if...else:
优点:可以进行范围判断
缺点:执行效率低,速度慢
switch...case:
优点:执行效率高,速度快,进行比较时,case做的是等值比较
缺点:使用之前必须知道结果
(三)循环结构
反复执行相同或者相似操作时使用
执行原理:创造循环变量,判断条件,满足则执行循环体,不满足退出循环
1.while
语法:
var 循环变量= ; //如: var i=1
while(循环条件){ // while(i<4){
循环体; // console.log(i);
循环变量的变化; // i+1;
} // }
特殊:死循环:while(true/1){循环体}
1.不确定循环次数时使用
2.搭配break,退出整个循环
3.搭配continue,退出本循环,但会执行下一次循环
2.for
语法:
for(循环变量;循环条件;循环变量的变化){ //如: for(var i=1;i<4;i++){
循环体; // console.log(i);
} // }
特殊:死循环:for(;;){循环体}
3.do...while
语法:
var 循环变量= ;
do{
循环体;
循环变量的变化;
}while(循环条件)
面试题2:while和for的区别是什么?
答:原理上几乎没有区别
在不确定循环次数时常使用while-----死循环
确定循环次数时则更倾向于使用for---更常用
面试题3:while和do...while的区别是什么?
答:第一次执行时如果条件都满足则无差别
条件不满足时,while不执行,但do...while至少执行一次
(四)fanction---函数
概念:function是函数,又叫方法,指的是预定义之后可以反复使用的代码段,函数名其实就是一个变量名
1.函数的使用方法
1.创建/声明/定义函数
(1)使用声明方式创建
function 函数名(形参列表){
操作;
return 返回值/结果;
}
(2)使用直接量方式创建
var 函数名=function (形参列表){
操作;
return 返回值/结果;
}
2.调用函数
(1)在js内部:函数名(实参列表);
(2)在HTML页面绑定事件:<标签名 on事件名="函数名(实参列表)">
(3)通过var 变量名=函数名(实参列表);来保存函数返回值/结果
3.特殊点:
(1)return的本意是退出函数,在return后边加上数据就可以将该数据返回到函数作用域外,
但由于return并不会保存数据,所以需要定义一个变量用于保存函数的返回值
(2)函数中省略return时,默认return一个undefined
2.作用域
1.全局作用域:
可以定义全局变量、全局函数,它们可以在页面上任意位置使用
2.函数作用域:
可以定义局部变量、局部函数,在函数被调用时,在函数内部使用
3.变量使用规则:
函数执行时优先使用局部变量,没有则使用全局变量,都没有就报错
4.特殊:
(1)在函数中向未声明的变量赋值就会导致全局污染
也就是全局作用没有声明的变量,被函数作用域添加上了
(2)局部作用域可以直接使用全局变量、函数,全局作用域则必须通过保存return的值才
能使用局部变量,局部函数只在定义它的函数被调用的时候执行
5.声明提前:
规则:在程序正式执行之前,将var声明的变量/函数名提前到当前作用域顶部,赋值/函数值
则不动,function声明的函数整个提前
3.重载
1.概念:相同的函数名,根据传入实参的不同,执行不完全相同的操作
2.使用方法:
在函数内部使用对象argument(类数组对象),无需定义,不写形参也可以接收实参,
默认argument.length=0
3.固定搭配:
(1)通过下标获取实参:argument[i],i从0开始
(2)通过length获取实参的数量
4.原理:
通过判断传入实参的数量,执行不同操作,变相实现重载
5.数组基础
1.创建方式:2种
(1)直接量方式
var arr=[];//空数组
var arr=[数据1, 数据2..., 数据n];
(2)构造函数方式
如果使用此方法,在括号里写一个数字,会默认创建一个长度为该数字的空数组
,数据是undefined
var arr=new Array();//空数组
var arr=new Array(数据1, 数据2..., 数据n);
2.使用方式:
(1)获取数组中的元素:
数组名[i]//获取数组中编号为i的元素
(2)后续添加/替换元素:
数组名[i]="新数据";
3.数组特点:
(1)不限制元素类型
(2)不限制元素长度
(3)不限制下标越界
4.下标越界的坏处:
(1)获取时下标越界会返回undefined
(2)添加时越界,得到稀疏数组,在遍历时会得到很多undefined
5.避免下标越界的方法:使用arr.length
6.固定用法:
(1)向末尾添加:arr[arr.length]="新数据";
(2)获取倒数第n个元素:arr[arr.length-n];
(3)缩容---删除倒数第n个元素:arr.length-=n;
(4)遍历数组:for(var i=0;i<arr.length;i++){arr[i];}
(五)DOM(Document Object Model)
意为文档对象类型 专门用于操作HTML对象
原本DOM是可以操作一切结构化文档的,但是再某一次升级后,为了方便各类程序员将DOM分为了3方面:
1、核心DOM:即可以操作HTML又可以操作XML,但是语法相对比较繁琐
2、HTML DOM:只可以操作HTML,不能访问一切自定义的东西,但语法简单
3、XML DOM:只可以操作XML已经被JSON数据格式代替了
1.DOM树的概念:DOM将HTML视作倒挂的树状结构,但是树根是document而非html
document对象:无需创建,js解释器自动创建,一个页面只有一个
作用:可以通过树根找到想要的任何一个DOM元素/节点/对象(属性和方法)
2.查找元素
(1)通过id查找
var elem = document.getElementById("id值");
特殊:
返回值:找到就返回DOM元素,没找到就返回null
出现多个相同的id,只会找到第一个
前端开发不使用id查找
(2)通过标签名查找
var elem = document/已经找到的父元素.getElementByTagName("标签名");
特殊:
返回值:找到返回一个类数组DOM集合,没找到就返回空集合
js只能操作DOM元素,不能直接操作DOM集合
使用已经找到的父元素对标签名的查找会更准确
(3)通过class名查找
var elem = document/已经找到的父元素.getElementByClassName("class名");
特殊:
返回值:找到返回一个类数组DOM集合,没找到就返回空集合
js只能操作DOM元素,不能直接操作DOM集合
使用已经找到的父元素对标签名的查找会更准确
(4) querySelector: 查询css选择器 query(查询)
1.var elem = document.querySelector("任意css选择器");
缺陷:只能找到单个元素,如果匹配到了多个,也只会返回第一个,没找到null
2.var elem = document.querySelectorAll("任意css选择器");
优点:
1、找到了是一个集合,没找到是一个空集
2、进行复杂查找时,简化了操作
3、返回的是一个静态集合NodeList
面试题:
1.document.getXXX 和 document.queryXX
答:后者更适合复杂查找
2、动态集合和静态集合的区别?
答:
1、动态集合:每一次DOM发生变化时都会再次查找,让页面和数据保持一致,
因此效率更低 - 不支持forEach
2、静态集合:每一次DOM发生变化时不会再次查找,没有让页面和数据保持一致,
因此效率更高 - 支持使用forEach
3.通过关系查找元素,前提:找到一个元素后才可使用关系
会返回一个动态集合HTMLCollection
| 关系 | 语句 | 范围 |
|---|---|---|
| 父元素 | elem.parentNode | 单个元素 |
| 子元素 | elem.children | 集合 |
| 第一个子元素 | elem.firstElementChild | 单个元素 |
| 最后一个子元素 | elem.lastElementChild | 单个元素 |
| 前一个兄弟 | elem.previousElementSibling | 单个元素 |
| 后一个兄弟 | elem.nextElementSibling | 单个元素 |
4.操作元素,前提:找到元素
1.内容
elem.innerHTML(会显示子元素标签)
获取和设置开始标签到结束标签之间的内容,有标签的话就会显示标签
获取:elem.innerHTML;
设置:elem.innerHTML="新内容";
elem.innerText(不显示子元素标签)
获取和设置开始标签到结束标签之间的纯文本
获取:elem.innerText;
设置:elem.innerText="新内容";
input.value: 专门获取/设置input里的内容
获取:input.value;
设置:input.value="新内容";
2.属性:
*****设置属性为空字符串,对于某些属性可以算是删除,但只删除了属性值,属性名还在,
有的属性只有一个属性名,也会有作用(如: href属性值为空会刷新界面,
disabled,readonly,checked这类属性,原本就可以省略属性值)
(1)核心DOM:
获取属性值:elem.getAttribute("属性名");
设置属性值:elem.getAttribute("属性名","属性值");
删除属性值: elem.removeAttribute("属性名");
(2)简化版(HTML DOM):
获取属性值:elem.属性名;
设置属性值:elem.属性名="属性值";
删除属性值: elem.属性名=""; - 属性节点删不干净
特殊点:
class必须写作className----ES6(2015年)class变成了关键字
不能操作自定义属性
3.样式:
a.内联样式
(1)优点:不牵一发而动全身,优先级最高
(2)获取样式:elem.style.css属性名;
(3)设置样式:elem.style.css属性名="css属性值";
本方法只能获取和设置内联样式
(4)特殊:css属性名之前使用横杠链接的地方,变为小驼峰
如:border-radius----borderRadius
b.样式表样式
var sheet=document.styleSheets[i]; //获取想要操作的样式表
var rules=sheet.cssRules;//获取此样式表中所有的样式规则
var rule=rules[i];//数出想操作的规则的下标
console.log(rule.style.css属性名);
rule.style.css属性名="css属性值";//操作
4.判断是否有某属性,只能判断有没有,不能判断是什么,推荐用elem.getAttribute("属性名");
获取到值后自己再写比较运算(返回true/false)
核心DOM:elem.hasAttribute("属性名");
HTML DOM:elem.属性名!="";
******优先使用HTML DOM,实现不了的再用核心DOM补充
6.绑定事件的三种方式:
1、在HTML上书写事件属性
<elem on事件名="函数名(实参)"></elem>
缺点:
1、不符合内容与样式与行为的分离原则
2、无法动态绑定,一次只能绑定一个元素
3、不支持绑定多个函数对象
2、*在js中使用事件处理函数属性
elem.on事件名=function(){
操作;
}
优点:
1、符合内容与样式与行为的分离原则
2、动态绑定,一次能绑定多个元素
缺点:
不支持绑定多个函数对象
3、*在js中使用事件API:如果不用考虑IE,那也不错
主流:elem.addEventListener("事件名",callback);
IE:elem.attachEvent("on事件名",callback);
优点:
1、符合内容与样式与行为的分离原则
2、动态绑定
3、支持绑定多个函数对象
缺点:有兼容性问题
兼容的写法:
if(elem.addEventListener){
elem.addEventListener("事件名",callback);
}else{
elem.attachEvent("on事件名",callback);
}
7.创建元素及上树的步骤:
1、创建空标签:
var elem=document.createElement("标签名");
2、为其设置必要的属性和事件
elem.属性名="属性值";
elem.on事件名=function(){}
3、上树:3种
*父元素.appendChild(elem);//在父元素末尾处追加一个子元素elem
父元素.insertBefore(elem,已有子元素);
//在父元素追加一个子元素elem,但是放在已有子元素的前面
父元素.replaceChild(elem,已有子元素);
//在父元素追加一个子元素elem,但是会替换掉已有子元素
*** 4.1、select&option专用创建元素&上树语句:
select.add(new Option("innerHTML","value"));
8.删除元素:elem.remove();
9.拓展:
1、创建变量:新增的一个let关键字:
let 变量名=值;
作用:
1、解决了声明提前
2、带来了块级作用域,一个{}就是一个块,此变量只能在那个{}里面使用
3、如果用let去当作下标绑定事件,直接记录着当前元素的下标,不再需要自定义
下标,forEach的那个形参i就是let创建的
2、类数组转为普通数组:接住=Array.from(类数组对象);