JavaScript介绍
JavaScript是一个运行在 浏览器端 的 解释型、弱类型、面向对象 脚本语言。
由三部分构成:ECMAScript(核心语法3/5/6/7/8/9/10/11/12) + DOM和网页关联) + BOM(和浏览器关联)
一、概念
1.1 浏览器端:
环境,自带JavaScript解释器——打开浏览器就可以自动运行
在学习Node.js的时候,会安装一个独立的js解释器
1.2 解释型:
在程序执行之前,不需要先检查语法是否正确,直接运行,碰到错误就停止,比如:js、php...
编译型:
在程序执行之前,需要先检查语法是否正确,如果语法错误,则不运行。相对于解释型比较严格,比如:Java、C#...
1.3 弱类型:
变量保存的数据是可以随意的,数据类型由数据来决定,比如:JavaScript
强类型:
变量保存的数据,是由数据的类型决定的,比如:Java
1.4 面向对象:
很难。面向对象式的写法:对象名.属性名;对象名.方法名();
1.5 特点:
- 可以用一切编辑工具编写JS代码,编辑器的不同并不代表实力的大小
- 解释型
- 弱类型
- 面向对象
- 可以做一切css完成不了的效果,比如:轮播、选项卡、购物车、验证...
二、如何使用js
2.1 使用方式:(2种)
- 在HTML页面上书写一个script标签,然后在里面书写代码 —— 一般不使用此方法
<script>js代码</script> - 创建一个xx.js的文件,然后在HTML里面引入 —— 正式开发
<script src='js路径'>此时不能在这里写代码</script>
2.2 输出方式/打桩输出:(3种)
作用:辅助我们检查代码错误
- 在控制台输出日志:
console.log(想要输出的内容);//console - 控制台,log - 日志
推荐:不会影响到页面的内容 - 在页面上输出日志:
document.write(想要输出的内容);//document - 文档,write - 写。
支持识别标签,但不推荐:如果搭配点击事件,会把页面上原有的东西全部替换 - 在弹出框输出日志:
alert(想要输出的内容);//警告框
一般般:有时候会卡住整个页面,导致用户只能看到一个白板
2.3 变量:创建后,可以再次修改
- 何时使用:反复用到的数据,提前保存到一个变量中,后续使用变量名就相当于在使用变量的值
- 语法:var 变量名=值;
- 特殊:
- 变量名是不可以随意的: a.不能以数字开头 b.建议驼峰命名法 c.命名尽量见文知意:
- 如果你的变量名是name,不管你保存的数据类型是什么,都会默认转为一个字符串
- 变量名不能是关键字
- 变量可以只创建,不赋值,默认值为undefined,undefined不能拿来做任何操作
- 如果多个变量连续创建,中间用,隔开;
2.4 常量:创建后,不能修改
- 语法:const 常量名=值;
- 特殊:见上文变量的特殊
2.5 数据的类型:(两大类)
- 原始/基本/值类型:(5个)
(1)number - 数字:取值有无数个,数字直接写,不需要加任何东西,颜色是蓝色
(2)string - 字符串:取值有无数个,写的时候需要加英文状态下的单双引号(" "或' '),颜色是黑色
(3)boolean - 布尔:取值只有2个,true/false - 一般用于当做条件判断,颜色是蓝色
(4)null - 空,取值只有1个,null,作用是释放变量释放内存,节约空间,提升网页的性能,颜色是灰色
(5)undefined - 取值只有1个,undefined做任何操作都不行,颜色是灰色
- 查看数据类型:typeof(变量);
- 引用对象类型:(11个)
可以理解为有11个对象(属性和方法)
2.6 运算符:(6种)
-
算术运算符:+ - * / %
(1)%:取余,俗称模,两数相除,取余数
作用:a.判断奇偶,任意数%2;
b.取出某个数字的后n位:1234%10 ==> 4, 1234%100 ==> 34
(2)带有隐式转换:会默认将数据类型转化为数字再进行运算:
true => 1,false => 2,undefined => NaN,null => 0
"10" => 10,"1000px" => NaN,带单位的要用强制转换
(3)NaN:Not a Number,不是一个数字,但它属于数字类型,不是有效数字
缺点:a.参与任何算术运算结果为NaN
b.参与任何比较运算结果都是false
解决:!isNaN()判断是否是数字,true是数字,false不是数字 -
比较运算符:> < >= <= == != === !==
结果:是布尔值
带有隐式转换:默认两边转为数字再比较
undefined==null为true
=== 全等,不带隐式转换的
!== 不等,不带隐式转换的 -
赋值运算符:= += -= *= /= %=
例如:i+=1 --> i=i+1 -
逻辑运算符:|| && !
或=>|| 与=>&&
非=>! 颠倒布尔值 -
自增自减运算符: ++ --
i++ ==> i=i+1 ==> i+=1
前++ 和 后++的区别:
单独使用没有任何区别
如果是等式运算,则返回的结果不同:
前++返回的是加了之后的值
后++返回的是未加的值 -
位运算:
左移:m<<n,读作m左移了n位,m*2的n次方
左移:m>>n,读作m右移了n位,m/2的n次方
缺点:底数只能是2
2.7 用户输入框:var 变量=prompt('提示文字');
三、分支结构
通过条件判断,选择部分代码执行
3.1 if...else...
三种写法:
1.一个条件,一件事,满足就做,不满足就不做
if(条件){
操作;
}
2.一个条件,两件事,满足就做第一件,不满足就做第二件
if(条件){
操作;
}else{
操作;
}
3.一个条件,多件事,满足哪个条件就做对应的操作
if(条件){
操作;
}else if{
操作;
}else if{
操作;
}else{
操作;
}
- else if想写多少就写多少,由程序员决定
- else默认操作可以不写,但不建议,如果条件都不满足则什么都没有发生
- 分枝走了一条路就不会走其他的路
3.2 switch...case...
switch(变量/表达式){
case 值:
case 值:
case 值:
操作;
break;
case 值:
操作;
break;
default:
操作;
}
-
默认只要一个case满足后,会将后续所有的操作全部做完。
解决:在每一个操作后面添加break; default后面不用跟。 -
default可以不写,但是不推荐不写,如果条件都不满足的时候,则什么都不会发生,什么都不发生就感觉这段代码还不如不写
-
case在做比较的时候是不带隐式转换的
3.3 if和switch的区别(面试题)
-
switch...case:
优点:执行效率高,速度快(case做比较时,case做的不是范围查找,而是等值比较)
缺点:必须要知道最后的结果是什么才可以使用 -
if...else...:
优点:可以做范围判断,也可以做等值比较
缺点:执行效率较慢,速度慢(因为是范围查找)
- 建议:代码开发结束后,做代码优化,尽量少用if...else...,多用switch...case和三目运算
3.4 三目运算(简化分支)
语法: 条件?操作:默认操作; ==>if...else
-
条件和操作可以有多个,默认操作只有一个,且默认操作必须写
比如:条件?操作1:条件?操作2:条件?操作3:默认操作; ==> if...else if...else if...else -
如果条件和操作太多,不建议使用三目运算,还是推荐 if 或 switch
-
注意:默认操作不能省略,省略了会报错的
四、强制转换数据的类型
解决隐式转换解决不了的,例如:"100px"*2=NaN
页面上一切数据,js获取到都是字符串类型
4.1 转数字
-
parseInt(str/num); 主要用于字符串转整数
识别规则:从左往右依次识别数字字符,碰到第一个不是数字的字符串就停止,如果第一个不是数字字符串,则为NaN,不认识小数点 -
parseFloat(str); float浮点数,主要用于字符串转小数
识别规则:只认识第一个小数点,其余与整数相同 -
Number(x); 万能公式,任何东西都可转换为数字类型,绝对不要手动转换,等同于隐式转换 -0 *1 /1,减0,乘1,除1
4.2 转字符串
-
var str=x.toString(); x不能是undefined和null,会报错,他们不是对象,不能使用.做任何操作
-
var str=String(x); 万能的,绝对不要手动转换,等同于隐式转换 +,加
4.3 转布尔:
-
Boolean(x); 万能的,任何东西都可以转布尔,绝对不要手动转换,完全等同于隐式转换,不如 !!x
-
只有6个为false:false 0 undefined NaN null 空引号""
-
除了这6个,剩下的都是true
五、循环结构
循环结构:反复执行相同或相似的操作
循环三要素:
1、循环条件:开始-结束,循环的次数
2、循环体:做的操作是什么
3、循环变量:记录着当前循环到哪一次了,会不断地变化
循环都是一次一次执行的
5.1 for循环
语法:
for(i=0;i<5;i++){
console.log(i);
}
执行原理:与while循环的原理相同
for循环的语法比while循环的语法看上去更简洁,更舒服
5.2 while循环
语法:
var i=0;
while(i<5){
console.log(i);
i++;
}
- 执行原理:首先创建出循环变量,判断循环条件,如果条件满足,则做一次循环体操作,并不会退出循环,而会回过头再次判断循环条件满不满足,如果满足,则做一次循环体操作,...直到条件不满足,才会退出循环
- while 和 for的区别(面试题):
while和for在原理上几乎没有区别
一般来说不确定循环次数的时候,会使用while循环- 死循环
一般来说确定循环次数的时候,会使用for循环 - 大部分情况
5.3 do...while循环(不常用)
语法:
var i=0;
do{
console.log(i);
i++;
}while(i<5)
- while和do...while的区别(面试题)
区别只在第一次,如果第一次条件满足,则没有任何区别,但是如果第一次条件不满足,while循环一次都不会做,do...while至少执行一次。根据代码从上到下的运行规则,可以看出,do...while循环是先执行里面的循环体,再判断,而while循环是先判断,再执行。
5.4 死循环
while(true){}for(;;){}
-
死循环:默认永远不会停下来的循环
何时使用:不确定循环次数的时候:while(true){死循环} -
让死循环停下来:
break; - 退出整个循环,大多是用来搭配死循环的
continue; - 退出本次循环,下一次依然会执行
六、Function函数
Function 称为函数,又称为方法,先预定义好,以后可以反复使用的代码段
6.1、Function基础
6.1.1 如何使用函数:(2步)
- 定义/创建/声明:
function 函数名(){函数体/代码段;}
注意:函数创建后,不会立即执行,需要调用函数才能执行 - 调用函数:(2种)
(1)在js内部写:函数名(); ——程序员写几次就调用几次
(2)在HTML上绑定事件:<elem onclick='函数名'></elem>————什么元素都可以绑定事件
6.1.2 何时使用:
- 不希望打开页面立刻执行
- 希望用户来触发提升用户的体验感
- 以后每一个独立的功能都要封装为一个函数
- 函数在js里的地位极高,函数是js的第一等公民
6.1.3 创建出带有形参的函数:
形参:其实就是一个变量,只不过不需要加var、不需要赋值,所以称之为形式参数 - 简称形参
- 语法:
function 函数名(形参,...){函数体/代码段;} - 使用带有形参的函数时,必须传入实参 - 实际参数
调用函数:函数名(实参,...)
注意:传参时顺序不能乱,必须和形参的顺序一一对应,数量不多不少 - 总结:
a、不带参数的函数:用于执行一些固定操作
b、带参数的函数:可以根据我们传入的实参的不同,做的略微不同
6.1.4 函数和循环的区别:
- 循环:几乎是一瞬间就完毕了
- 函数:需要调用后才会执行
6.2 自定义函数Function
函数:需要先定义好,以后可以反复使用的一个代码段
何时使用:不希望打开页面立刻执行,以后可以反复使用,希望用户来触发...
6.2.1 函数的创建:(2种)
- 声明方式 创建函数:
function 函数名(形参列表){代码段;return 返回值/结果;} - 直接量方式 创建函数:--不推荐
var 函数名=function(形参列表){代码段;return 返回值/结果;}
6.2.2 函数的调用:
var 变量名=函数名(实参列表)
-
return的本意是退出函数,但是如果return后面跟着一个数据,顺便将数据返回到函数作用域的外部,但是return只负责返回,不负责保存,所以调用函数时要自己拿个变量来接住他
-
就算省略return,默认也有,会return一个undefined
-
具体需不需要得到函数的结果,看你自己:如果有一天你在全局希望拿着函数的结果去做别的操作,那么记得加return
-
前辈们提供的方法,大部分基本上都加了return
6.2.3 作用域:(2种)
-
全局作用域:
全局变量 和 全局函数,在页面的任何一个位置都可以使用 -
函数作用域:
局部变量 和 局部函数,在当前函数调用时,内部可用 -
带来了变量的使用规则:
优先使用局部的,局部没有找全局要,全局也没有那就会报错
特殊点/缺点:
1、千万不要在函数中对着未声明的变量直接赋值 - 全局污染:全局本身没有这个东西,但是被函数作用域给添加上了
2、局部可以使用全局的,但是全局不能使用局部的 - 解决:return
6.2.4 声明提前:(鄙视题)
规则:在程序正式执行之前,将var声明的变量(轻)和function声明的函数(重),都会悄悄的集中定义在当前作用域的顶部,但是赋值留在原地
-
强调:声明方式创建的函数会完整的提前,直接量方式创建的函数不会完整提前,只有变量名部分会提前,赋值留在原地
-
何时使用:永远不会自己使用,会干扰我们判断 - 只会在笔试中遇到
-
为什么平时开发不会遇到? 只要你遵守以下规则: 1、变量名和函数名尽量不要重复 2、先创建后使用
6.2.5 重载:
-
概念:相同的函数名,根据传入的实参的不同,自动选择对应的函数去执行,但是JS不支持,函数名如果重复了,后面的肯定会覆盖掉前面的
-
目的:减轻我们程序员的压力,记住一个方法就可以执行很多的操作
-
解决:在【函数内部】自带一个arguments的对象(类似数组对象):不需要我们去创建 - 哪怕没有写任何形参,他也可以接受住所有实参,所以他默认length长度为0
固定套路: 1、通过下标去获取传入的某一个实参:arguments[i] —— i从0开始。 2、通过length去获取到底传入了几个实参:arguments.length -
通过判断传入的实参的不同,在内部去写判断,从而变相的实现重载
七、DOM
Document Object Model:文档对象模型,专门用于操作HTML文档的,提供了一些方法。
7.1 DOM树概念:
-
DOM将HTML看作是一个倒挂的树状结构,但是树根不是html标签,而是document的对象
-
document对象:不需要我们程序员创建,由浏览器的js解释器自动创建,一个页面只有一个document树根
作用:可以通过树根找到我们想要的任何一个DOM元素/节点/对象(属性和方法) -
DOM会将页面上的每个元素、属性、文本、注释等等都会被视为一个DOM元素/节点/对象
7.2 查找元素:(两大方面)
7.2.1 直接通过HTML的特点去查找元素
-
通过 ID 查找元素:
var elem=document.getElementById("id值");
特殊:
1、返回值,找到了返回当前找到DOM元素,没找到返回的一个null
2、如果出现多个相同id,只会找到第一个
3、记住控制台输出的样子,这个样子才叫做一个DOM元素/节点/对象,才可以下午去做操作
4、忘记此方法,不允许使用,id不好用,一次只能找一个元素。id留给后端用
5、其实根本不用查找,id直接可用 -
通过 标签名 查找元素:
var elems=document/已经找到的父元素.getElementsByTagName("标签名");
特殊:
1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素 -
通过 class 查找元素:
var elems=document/已经找到的父元素.getElementsByClassName("class名");
特殊:与标签名相同
7.2.2 通过关系去获取元素:
- 前提条件:必须先找到一个元素才可以使用关系`
- 父元素:elem.parentNode; - 单个元素
- 子元素:elem.children; - 集合
- 第一个子元素:elem.firstElementChild; - 单个元素
- 最后一个子元素:elem.lastElementChild; - 单个元素
- 前一个兄弟:elem.previousElementSibling; - 单个元素
- 后一个兄弟:elem.nextElementSibling; - 单个元素
- 为什么要通过关系去找元素呢?
不希望影响到别人,只希望影响到自己的关系网
7.3 操作元素:(3方面)
前提:先找到元素,才能操作元素
7.3.1 操作元素的内容:
-
elem.innerHTML - 获取和设置开始标签到结束标签之间的内容,支持识别标签的
获取:elem.innerHTML;
设置:elem.innerHTML="新内容"; -
elem.innerText - 获取和设置开始标签到结束标签之间的纯文本,不识别标签的
获取:elem.innerText;
设置:elem.innerText="新内容";
- 以上两个属性都是专门为双标签准备,而有一个单标签也是可以写内容,叫做,我们如何获取?
- input.value - 专门获取/设置input里的内容
获取:input.value;
设置:input.value="新内容";
7.3.2 操作元素的属性:
获取属性值:elem.getAttribute("属性名");
设置属性值:elem.setAttribute("属性名","属性值");
简化版:
获取属性值:elem.属性名;
设置属性值:elem.属性名="属性值";
简化版的缺点:
1、class必须写为className - ES6(2015年)class变成了一个关键字
2、不能操作自定义属性
7.3.3 操作元素的样式:
使用样式的方式:(3种)
1、内联样式
2、内部样式表
3、外部样式表 - 一阶段做开发用的都是外部样式表
二阶段用js来操作【内联样式】
1、不会牵一发动全身
2、优先级最高
获取样式:elem.style.css属性名;
设置样式:elem.style.css属性名="css属性值";
特殊点:
1、css属性名,有横线的地方,去掉横线,变为小驼峰命名法:
border-radius -----> borderRadius
2、小缺陷:获取时,我们只能获取到内联样式,因为我们目前学的就是内联样式的操作
7.3.4 绑定事件:
elem.on事件名=function(){
操作;
关键字this - 这个
如果单个元素绑定事件,this->这个元素
如果多个元素绑定事件,this->当前触发事件元素
}
- 一切的获取,往往都是为了判断
- 一切的设置,可以说是添加也可以说是修改
八、数组
问题:保存1000个同学的名字?
var name1="钟清翰1";
...
var name1000="钟清翰1000";
不推荐,变量其实就是我们所谓的内存,变量创建的越多,那么我们的内存空间消耗越大,那么网站性能就会越差
解决:数组:创建一个变量可以保存【多个数据】
数组都是线性排列,除了第一个元素,每个元素都有唯一的前驱元素除了最后一个元素,每个元素都有唯一的后继元素
每个元素都有一个自己的位置,称之为叫做下标,下标都是从0开始的,到最大长度-1结束
8.1 创建数组:(2种)
1、直接量方式:
var arr=[];//空数组
var arr=[数据1,...];
2、构造函数方式:
var arr=new Array();//空数组
var arr=new Array(数据1,...);
8.2 获取数组之中的元素:
数组名[i];
8.3 后续添加/替换元素:
数组名[i]=新数据;
如果下标处没人则为添加,如果下标处有人则为替换
8.4 数组具有三大不限制
- 不限制元素的类型
- 不限制元素的长度
- 不限制下标越界 - 不是一个好东西
如果获取元素时,下标越界,返回的是一个undefined
如果添加元素时,下标越界,会得到一个稀疏数组,如果我们搭配上我们学过循环去遍历获取每个元素,那么你会得到很多很多undefined
问题:自己数下标,难免会数错,导致我们下标越界
8.5 下标越界的解决:数组中有一个唯一的属性--length
语法:数组名.length
作用:获取到数组的长度,长度是从1开始的
三个固定套路:
- 向末尾添加元素:
arr[arr.length]=新数据; - 获取数组的倒数第n个元素:
arr[arr.length-n]; - 缩容:删除倒数n个元素:
arr.length-=n;
8.6 遍历数组:
往往很多情况,我们不会拿出某个元素来使用,而是拿出每个元素来进行 相同 或 相似的操作 - 搭配上循环
固定公式:
for(var i=0;i<arr.length;i++){
arr[i];//当前次元素
}