javascript介绍:
简称JS,是一个运行在【浏览器端】的【解释型】【弱类型】【面向对象】脚本语言。
三部分组成:
ECMAScript(核心语法3/5/6/7/8/9/10/11/12)+DOM(和网页挂钩的)+BOM(和浏览器挂钩)
浏览器环境:
1.自带JavaScript解释器——打开浏览器可以自动运
2.会安装一个独立的js解释器——学习node.js的时候
编译型:
在程序执行之前,需要先检查语法是否正确,如果不正确,直接不运行——严格:比如:js、php...
强类型:
变量保存的数据,是由数据的类型来决定的——比如:Java-严格
弱类型:
变量保存的数据是可以随意的,数据类型由数据来决定,- 比如:JavaScript - 自由
1 - number(数字)
"1" - string(字符串)
如何使用js:
1、使用方式:2种
1、在HTML页面上书写一个script标签,再在里面书写js代码
2、创建一个xx.js的文件,再在HTML进行引入 - 正式开发
2、输出的方式/打桩输出,帮助我们以后检查错误:
1、*在控制台输出日志:console.log(想要输出的东西);
//console - 控制台 log - 日志,推荐:不会影响到页面。
2、在页面上输出日志:document.write(想要输出的东西);
//document - 文档 write - 写,还支持标签的写法,但是是个垃圾,比如:如果搭配点击事件,会把页面上原有的东西全部替换掉。
3、在弹出框输出日志:alert(想要输出的东西);
//警告框,一般般:有时候会卡住整个页面,导致用户只能看到一个白板。
3、*变量:创建后,可以再次修改
何时使用:
以后反复使用到的数据,都要提前把他保存在一个变量之中,以后使用变量名,相当于就是在使用变量的值
语法:var 变量名=值;
特殊:
1、变量名其实不是随意的:
1、不能以数字开头
2、建议驼峰命名法或下划线命名法
3、命名要尽量的见名知意
2、如果你的变量名是name,不管你保存的数据类型是什么,都会悄悄的给你转为一个字符串
3、变量名不能是关键字
4、变量可以只创建,不赋值,默认值为undefined,但是从今天开始我们要牢记undefined是一个垃圾,拿来做什么都要不得
5、如果多个变量连续创建,简写: var 变量名=值,变量名=值,变量名=值,变量名=值,变量名=值;
4、常量:创建后,不允许修改了
生活中的常量:
PI
一个小时60分
一分钟60秒
一天24个小时
一年365/366天
语法:const 常量名=值;
其余特殊点和变量一模一样
5、了解 - 数据类型有哪些?分为两大类
1、*原始/基本/值类型:5个
1、*number - 数字:取值有无数个,而且数字就是直接写,不用加任何东西(颜色是蓝色)
2、*string - 字符串:取值有无数个,但是必须加上:"" 或 ''(颜色是黑色)
3、*boolean - 布尔:取值只有2个,分别叫true(真|对) 或 false(假|错)- 一般用于当作条件判断(颜色是蓝色)
4、null - 空,取值只有1个,就是null,唯一的作用就是用于释放变量释放内存的,节约内存空间,提升网页的性能,以后会有更好的方式(颜色是灰色)
5、undefined - 取值只有1个,就是undefined,从今天开始我们要牢记undefined是一个垃圾,拿来做什么都要不得,undefined是祖师爷犯的一个错,但是他自己不承认(颜色是灰色)
查看数据类型:typeof(变量);
2、引用/对象类型:有11个,可以暂时理解为有11个对象(属性和方法)等待我们学习
6、*运算符:
1、*算术运算符:+ - * / %
特殊:
1、%:取余,俗称模,两个数相除,不取商,而是取除不尽的余数
作用:
1、*任意数%2 - 判断奇偶数
2、取出某个数字的后n位
1234%10-> 4
1234%100 -> 34
2、带有隐式转换:悄悄地会将数据类型转换,发生变化,默认:都是左右两边转为数字再运算
true->1
false->0
undefined->NaN
null->0
"1000"->1000
"1000px"->NaN - 暂时解决不了,只有等待以后学习了强制(显示)类型转换才能解决
NaN::Not A Number:不是一个数字,但是他确实是数字类型,不是一个有效数字,没有优点,但是有两个缺点:
1、参与任何的算术运算结果仍为NaN
2、参与任何的比较运算结果都是false
3、+运算特殊:如果碰上一个字符串,左右两边都会悄悄的转为字符串,+运算不再是+运算,而是拼接操作
2、*比较/关系运算符:> < >= <= == != === !==
结果:一定是一个布尔值
带有隐式转换:默认左右两边都会悄悄转为数字再比较大小
特殊:
1、如果参与比较的左右两边都是一个字符串,则会按位PK每个字符的十六进制的unicode号(十进制ASCII码);
数字0-9<大写A-Z<小写a-z<汉字
常识:汉字的第一个字:是 一 unicode号是 4e00 ascii是19968
汉字的最后一个字:是 龥 unicode号是 9fa5 ascii是40869
2、NaN参与任何的比较运算结果都是false,带来了一个问题:如何判断x是不是NaN,我们不能使用普通的比较运算去判断
!isNaN(x)
结果是一个布尔值:true->说明是有效数字 false->说明是NaN
3、undefined==null//true
解决:全等:不带隐式转换的等值比较===,要求值相同并且数据类型也要相同
!==:不带隐式转换的不等比较
3、*赋值运算符:= += -= *= /= %=
1、=:赋值:将=右边的东西,保存到=左边的变量名之中
2、后面5个可以理解为是一种升级写法,运算后再保存回变量本身,举例:
i=i+1 ==> i+=1;
4、*逻辑运算符:综合比较 - 用于写条件
&&:与(并且)
全部条件都满足,结果才为true
只要一个不满足,结果就为false
||:或者
全部条件都不满足,结果才为false
只要一个满足,结果就为true
!:颠倒布尔值
5、*自增自减运算符:
++ --
i++ ===> i+=1 ===> i=i+1
自增:固定的每次只能+1
累加:+=每次加几由程序员自己决定
鄙视题:
前++ 和 后++的区别?
如果单独使用,前++和后++,没有任何区别。
但是如果参与了其他表达式,变量始终都会+1,但是前++和后++的【返回结果】不同
前++,返回的是加了过后的新值
后++,返回的是加了之前的旧值
6、位运算:
左移:m<<n,读作m左移了n位,翻译:m*2的n次方
右移:m>>n,读作m右移了n位,翻译:m/2的n次方
垃圾的原因:底数只能是2
扩展:用户输入框:var 变量=prompt("提示文字");
分支结构:
1、程序的流程控制语句:
1、顺序结构 - 默认:从上向下依次执行每一句话
2、分支结构 - 通过条件判断,选择部分代码执行
3、循环结构 - 通过条件判断,选择要不要重复执行某块代码
3种:
1、if...else...如何使用:3种情况
1、一个条件,一件事,满足就做,不满足就不做
if(条件) {
操作;
}
2、一个条件,两件事,满足就做第一件,不满足就做第二件
if(条件){
操作;
}else{
默认操作;
}
3、多个条件,多件事,满足谁,就做谁
if(条件1){
操作1;
}else if(条件2){
操作2;
}else{
默认操作;
}
注意:
1、else...if这句话想写多少,由程序员自己决定
2、else这句话可以省略不写,但是不推荐,如果不写,条件都不满足的情况,则什么事儿都不会发生
3、分支走了一条路,就不会再走别的路
2、switch...case 分支:
语法:
switch(变量/表达式){
case 值1:
操作1;
break;
case 值2:
操作2;
break;
default:
默认操作;
}
特殊:
1、问题:默认只要一个case满足后,会将后续所有的操作全部做完
解决:break;
建议:每一个case的操作后面都跟上一个break
有的地方也可以不加break:
1、最后一个操作default可以省略break
2、如果中间多个条件,做的操作是一样的,可以省略掉中间部分
2、case在做比较的时候是不带有隐式转换的
3、default可以省略不写的,但是不推荐,如果不写,条件都不满足的情况,则什么事儿都不会发生
面试题:if vs switch的区别?
1、switch...case:
优点:执行效率较高,速度快(他比较时,case做的不是范围查找,而是等值比较)
缺点:必须要知道最后的结果是什么才可以使用
2、if...else...:
优点:可以做范围判断
缺点:执行效率较慢,速度慢(他做的是范围查找)
建议:代码开发完过后,要做代码优化,要尽量的少用if...else...,多用switch...case和三目运算
3、三目运算:简化分支的
语法:
条件?操作1:默认操作; === if...else...
条件1?操作1:条件2?操作2:默认操作 === if...else if..else
注意:
1、默认操作不能省略,省略了会报错
2、如果操作复杂,不能使用三目运算:操作只能有一句话,如果操作有多句话还是推荐使用switch或if
隐式转换:多半都是再运算符中悄悄的变化的,但是隐式转换总有力不从心的时候:"15px"*2=NaN
页面上一切数据js获取到后都是字符串类型
2、强制(显示)数据类型转换:
1、转字符串:
2种方法:
1、var str=x.toString();//x不能undefined和null,会报错,undefined和null不能使用.做任何操作,因为他们不是对象
2、var str=String(x);//万能的,任何人都可以转为字符串,但是绝对不要手动使用,完全等效于隐式转换,还不如+""
不重要:页面上一切数据js获取到后都是字符串类型
2、***转数字:3种方法
1、*parseInt(str/num); - parse解析 Int整型 - 专门用于将【字符串转为整数】
执行原理:从左向右依次读取转换每个字符,碰到非数字字符就停止转换,如果一来就不认识则为NaN,不认识小数点。
console.log(parseInt(35.5));//35
console.log(parseInt("35.5"));//35
console.log(parseInt("3hello5"));//3
console.log(parseInt("hello35"));//NaN
console.log(parseInt("35px"));//35
console.log(parseInt(".35px"));//NaN
console.log(parseInt(true));//NaN
console.log(parseInt(false));//NaN
console.log(parseInt(undefined));//NaN
console.log(parseInt(null));//NaN
2、*parseFloat(str); - parse解析 Float浮点型 - 专门用于将【字符串转为小数】
执行原理:几乎和parseInt一致,认识第一个小数点
console.log(parseFloat(35.5));//35.5
console.log(parseFloat("35.5"));//35.5
console.log(parseFloat("3hello5"));//3
console.log(parseFloat("hello35"));//NaN
console.log(parseFloat("35.5px"));//35.5
console.log(parseFloat(".35px"));//0.35
console.log(parseFloat("35.5.5"));//35.5
3、Number(x);//万能的,任何人都可以转为数字,但是绝对不要手动使用,完全等效于隐式转换,还不如 -0 *1 /1
3、转布尔:
Boolean(x);//万能的,任何人都可以转为布尔,但是绝对不要手动使用,完全等效于隐式转换,还不如 !!x
***只有6个为false:0,"",undefined,NaN,null,false,其余全部都是true。
我们绝对不会手动使用,但是在分支或循环的条件之中,不管写什么,他都会悄悄的转为一个布尔值,自带此方法
不管写什么,你只需要判断为不为这六个,不为这六个就是true,为这六个就是false
1、循环结构:
问题:在控制台打印输出1000句hello world?
console.log("1hello world");
...
console.log("1000hello world");
生活中的循环?
吃饭
睡觉
上课
上班
自转
公转
活着
循环结构:反复执行 相同 或 相似的操作
循环三要素:
1、循环条件:开始 - 结束,循环的次数
2、循环体:做的操作是什么
3、循环变量:记录着我们当前在哪一次,而且他会不断的变化
2、3种循环:
1、while循环:
语法:
var 循环变量=几;
while(循环条件) {
循环体;
循环变量变化;
}
执行原理:首先创建出循环变量,判断循环条件,如果条件满足,则做一次循环体操作,并不会退出循环,而会回过头再次判断循环条件满不满足,如果满足,则做一次循环体操作,...直到条件不满足,才会退出循环
宏观上感觉循环好像一瞬间就结束了,但是微观上循环其实是一次一次执行的
特殊:
1、有的时候可能真的需要使用死循环:默认永远不会停下来的循环
何时使用:不确定循环次数的时候
while(true){死循环}
2、死循环其实也会有一天停下来,如何停下来呢?
break; - 退出整个循环,多半都是用来搭配死循环的
continue; - 退出本次循环,下一次依然会执行
2、*for循环:和while的原理是一样的,但是他比while看上去更加的简洁,更加的舒服
语法:
for(var 循环变量=几;循环条件;循环变量变化){
循环体;
}
特殊:
死循环:for(;;){}
面试题:while 和 for的区别?
while和for在原理上几乎没有区别?
一般来说我们不确定循环次数的时候,会使用while循环 - 死循环
一般来说我们确定循环次数的时候,会使用for循环 - 大部分情况都是他
3、do...while循环:废物:while我们都不想用,何况是更麻烦的do...while
语法:
var 循环变量=几;
do{
循环体;
循环变量的变化
}while(循环条件)
面试题:while 和 do...while的区别?
区别只看第一次,如果第一次条件都满足,那么两者没有任何区别。
但是如果第一次条件不满足,那么while一次都不会执行
那么do...while至少会执行一次
Function的基础:
1、概念:
Function 也叫函数也叫方法,【先预定义】好,以后可以【反复使用】的【代码段】
2、如何使用函数:2步
1、定义/创建/声明:
function 函数名(){
函数体/代码段;
}
注意:函数创建后,不会立刻执行,需要我们去调用函数
2、调用函数:2种
1、在js内部写:函数名(); - 程序员写几次就会调用几次
2、在HTML上面绑定事件:
<elem onclick="函数名()"></elem> - 什么元素都可以绑定事件
3、我们以后何时使用函数呢?
1、不希望打开页面立刻执行
2、希望用户来触发提升用户的体验感
3、以后每一个独立的功能(作业)都要封装为一个函数
函数在js里的地位极高,函数是js的第一等公民
4、但是好像和我们目前见过的别的函数不太一样
一阶段就已经见过函数了:
rotate(180deg)
url(2.jpg)
这种写法叫做带参数的函数:
1、创建出带有形参的函数 - 形参:其实就是一个变量,只不过不需要加var,而且不需要赋值,所以称之为叫做形式参数 - 简称形参
function 函数名(形参,...){
函数体/代码段;
}
2、使用带有形参的函数时,必须传入实参 - 实际参数,就是你传递过去的值
函数名(实参,...)
注意:传参的时候顺序是不能乱的,必须和形参的顺序一一对应,数量不多不少
总结:
1、不带参数的函数:用于执行一些固定操作
2、带参数的函数:可以根据我们传入的实参的不同,做的略微不同
总结:循环也能反复执行,函数也能反复执行,他们的区别在哪里?
1、循环:几乎是一瞬间就完毕了
2、函数:需要调用后才会执行
1、自定义函数Function
什么是函数:需要先定义好,以后可以反复使用的一个代码段
何时使用:不希望打开页面立刻执行,以后可以反复使用,希望用户来触发...
如何使用:
1、**创建:
1、【声明方式】创建函数
function 函数名(形参列表){
操作;
return 返回值/结果;
}
2、【直接量方式】创建函数:- 不推荐
var 函数名=function(形参列表){
操作;
return 返回值/结果;
}
感觉到函数名其实就是一个变量名
2、调用:
var 接住返回的结果=函数名(实参列表);
//其实return的本意是退出函数,但是如果return后面跟着一个数据
//顺便将数据返回到函数作用域的外部,但是return只负责返回,不负责保存,所以调用函数时要自己拿个变量来接住他
//就算省略return,默认也有,会return一个undefined
//*具体需不需要得到函数的结果,看自己:如果有一天你在全局希望拿着函数的结果去做别的操作,那么记得加return
//前辈们提供给你的方法,大部分基本上都加了return
3、***作用域:
1、全局作用域:全局变量 和 全局函数,在页面的任何一个位置都可以使用。
2、函数作用域:局部变量 和 局部函数,在【当前函数调用时,内部可用】
带来了变量的使用规则:优先使用局部的,局部没有找全局要,全局也没有那就会报错
特殊点:
缺点:
1、千万不要再函数中对着未声明的变量直接赋值 - 全局污染:全局本身没有这个东西,但是被函数作用域给添加上了
2、局部可以使用全局的,但是全局不能使用局部的 - 解决:看上面return
4、***声明提前: - 只会出现在笔试之中
规责:在程序正式执行之前,将var声明的变量(轻)和function声明的函数(重),都会悄悄的集中定义在当前作用域的顶部,但是赋值留在原地
强调:
声明方式创建的函数会完整的提前(第一种)
直接量方式创建的函数不会完整提前,只有变量名部分会提前(第二种)
何时使用:永远不会自己使用,干扰我们判断的 - 只会在笔试中遇到,为什么平时开发不会遇到呢?
只要你遵守以下规则:
1、变量名和函数名尽量不要重复
2、先创建后使用
5、***重载:相同的函数名,根据传入的实参的不同,自动选择对应的函数去执行,但是JS不支持,函数名如果重复了,后面的肯定会覆盖掉前面的
目的:减轻我们程序员的压力,记住一个方法就可以执行很多的操作
解决:在【函数内部】自带一个arguments的对象(类似数组对象):不需要我们去创建 - 哪怕没有写任何形参,他也可以接受住所有实参,所以默认你看他length长度为0
固定套路:
1、通过下标去获取传入的某一个实参:arguments[i] - i从0开始
2、通过length去获取到底传入了几个实参:arguments.length
通过判断传入的实参的不同,在内部去写判断,从而变相的实现重载
2、数组的基础:
不推荐,变量其实就是我们所谓的内存,变量创建的越多,那么我们的内存空间消耗越大,那么网站性能就会越差
解决:数组:创建一个变量可以保存【多个数据】
数组都是线性排列,除了第一个元素,每个元素都有唯一的前驱元素
除了最后一个元素,每个元素都有唯一的后继元素
***每个元素都有一个自己的位置,称之为叫做下标,下标都是从0开始的,到最大长度-1结束
1、创建数组:2种
1、*直接量方式:var arr=[];//空数组
var arr=[数据1,...];
2、构造函数方式:var arr=new Array();//空数组
var arr=new Array(数据1,...);
2、获取数组之中的元素:
数组名[i]
3、后续添加/替换元素:
数组名[i]=新数据;
如果下标处没人则为添加,如果下标处有人则为替换
4、数组具有三大不限制
1、不限制元素的类型
2、不限制元素的长度
3、不限制下标越界 - 不是一个好东西
如果获取元素时,下标越界,返回的是一个undefined
如果添加元素时,下标越界,会得到一个稀疏数组,如果我们搭配上我们学过循环去遍历获取每个元素,那么你会得到很多很多undefined
问题:自己数下标,难免会数错,导致我们下标越界
5、解决:数组中有一个唯一的属性:length
语法:数组名.length
作用:获取到数组的长度,长度是从1开始的
三个固定套路:
1、向末尾添加元素:arr[arr.length]=新数据;
2、获取数组的倒数第n个元素:arr[arr.length-n];
3、缩容:删除倒数n个元素:arr.length-=n;
6、***遍历数组:往往很多情况,我们不会拿出某个元素来使用,而是拿出每个元素来进行 相同 或 相似的操作 - 搭配上循环
固定公式:
for(var i=0;i<arr.length;i++){
arr[i];//当前次元素
}
JS由三部分组成:
1、ES3-13 - 逻辑思维,内功心法
2、DOM - Document Object Model - 和页面挂钩了
3、BOM - 一般般以后再说
1、DOM:
1.Document Object Model:文档对象模型:专门用于操作HTML文档的,提供了一些方法给你。
2、DOM树概念:DOM将我们的HTML看作了是一个倒挂的树状结构,但是树根不是html标签,而是document的对象
document对象:不需要我们程序员创建,由浏览器的js解释器自动创建,一个页面只有一个document树根
作用:可以通过树根找到我们想要的任何一个DOM元素/节点/对象(属性和方法)
DOM会将页面上的每个元素、属性、文本、注释等等都会被视为一个DOM元素/节点/对象
3、查找元素:两大方面:
1、直接通过HTML的特点去查找元素
1、通过 ID 查找元素:
1var elem=document.getElementById("id值");
特殊:
1、返回值,找到了返回当前找到DOM元素,没找到返回的一个null
2、如果出现多个相同id,只会找到第一个
3、记住控制台输出的样子,这个样子才叫做一个DOM元素/节点/对象
4、忘记此方法,不允许使用,id不好用,一次只能找一个元素。id留给后端用
5、其实根本不用查找,id直接可用
2、*通过 标签名 查找元素:
var elems=document/已经找到的父元素.getElementsByTagName("标签名");
特殊:
1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素
3、*通过 class 查找元素:
var elems=document/已经找到的父元素.getElementsByClassName("class名");
特殊:
1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素
2、*通过关系去获取元素:前提条件:必须先找到一个元素才可以使用关系
父元素:elem.parentNode; - 单个元素
子元素:elem.children; - 集合
第一个子元素:elem.firstElementChild; - 单个元素
最后一个子元素:elem.lastElementChild; - 单个元素
前一个兄弟:elem.previousElementSibling; - 单个元素
后一个兄弟:elem.nextElementSibling; - 单个元素
为什么要通过关系去找元素呢?不希望影响到别人,只希望影响到自己的关系网
4、操作元素:前提:先找到元素,才能操作元素,3方面
1、内容:
1、*elem.innerHTML - 获取和设置开始标签到结束标签之间的内容,支持识别标签的
获取:elem.innerHTML;
设置:elem.innerHTML="新内容";
2、elem.innerText - 获取和设置开始标签到结束标签之间的纯文本,不识别标签的
获取:elem.innerText;
设置:elem.innerText="新内容";
以上两个属性都是专门为双标签准备,而有一个单标签也是可以写内容,叫做,我们如何获取?
3、input.value - 专门获取/设置input里的内容
获取:input.value;
设置:input.value="新内容";
2、属性:
获取属性值:elem.getAttribute("属性名");
设置属性值:elem.setAttribute("属性名","属性值");
简化版:
获取属性值:elem.属性名;
设置属性值:elem.属性名="属性值";
简化版的缺点:
1、class必须写为className - ES6(2015年)class变成了一个关键字
2、不能操作自定义属性
3、样式:
使用样式的方式:3种
1、*内联样式
2、内部样式表
3、外部样式表 - 一阶段做开发用的都是外部样式表
二阶段我们就要用js来操作【内联样式】
1、不会牵一发动全身
2、优先级最高
获取样式:elem.style.css属性名;
设置样式:elem.style.css属性名="css属性值";
特殊点:
1、css属性名,有横线的地方,去掉横线,变为小驼峰命名法
border-radius ----- borderRadius
2、小缺陷:获取时,我们只能获取到内联样式,因为我们目前学的就是内联样式的操作
4、绑定事件:
elem.on事件名=function(){
操作;
*****关键字this - 这个
如果单个元素绑定事件,this->这个元素
如果多个元素绑定事件,this->当前触发事件元素
}
一切的获取,往往都是为了判断
一切的设置,可以说是添加也可以说是修改