JS的基本概念
js是一种弱类型的语言,变量保存的数据可以是随意的,数据类型由数据来执行决定。
例如:1 -- 代表Number 数字1;"1" -- 代表String 字符串
js的特点:可以使用任何编辑工具编写js代码,可以做一切css完成不了的效果,和服务器端进行沟通。
如何使用:使用方式有两种,
①直接在HTML上写一个script标签,写在body里面,一般放在body的最后,body结束标签的上面。
②创建一个xx.js文件,在其中写入一个js代码,最后在HTML里面引入。
输出方式
在控制台上输出日志:console.log()
在页面上输出日志:document.write()
在浏览器的警告框输出日志:alert
注意:数字颜色:蓝色
变量和常量
变量:创建后,值可以再次修改
语法:var 变量名 = 值;
何时使用:以后会反复用到数据,都要提前保存在一个变量中,以后使用变量名相当于使用的是一个变量的值
特殊:① 变量名不是随意的,不能以数字开头。
② 命名要见名知意,使用驼峰命名法或者下划线取法
③ 变量名不能是关键字,比如:var this
④ 变量可以只创建,不赋值,默认值为undefined
⑤ 如果多个变量连续创建,可以多个赋值。比如:
var name = "Lucy", age = 16, gender = "man";
常量:创建后,值不允许再次修改的
语法:const 常量名 = 值;
数据类型有哪些?分为两大类
有原始类型和引用类型两大类
①原始类型:5个
<1>.Number - 数字,取值有无数个,而且数字就是直接写,不用加任何东西(控制台输出一个蓝色数字)
<2>.String - 字符串,取值有无数个,但必须加上"" 或 '';控制台输出为蓝色
<3>.Boolean - 布尔,取值有两个,true或false,一般用于判断条件
<4>.NUll - 空,取值只有一个,就是null,唯一的作用就是用于释放我们的内存(变量)空间的,节约内存,但是每次需要我们手动释放。
<5>.undefined - 未定义的,取值只有一个,就是undefined,变量默认值就是undefined
②引用/对象类型:有11个,可以暂时理解为有11个对象(属性和方法)
运算符
运算符有:算数运算符、比较/关系运算符、逻辑运算符、赋值运算符、自增和自减运算符、位运算符。
1.算数运算符:+ - * / %
特殊:% 模运算 小的数%大的数 取的是小的数;
作用:任意数%2 - 判断奇偶数
取出某个数字的后N位 1234%10 -> 4; 1234%100 -> 34;
默认带有隐式转换:会悄悄的将运算符左右两边转为数字,再运算。
true -> 1 ; false -> 0 ; null -> 0 ; undefined -> NaN
字符串 -> NaN;
2.比较/关系运算符 > < >= <= != == === !==
何时使用:一般出现在分支结构,我们可以通过判断条件满不满足,走不同的路线
结果:一定是布尔值
默认也带有隐式转换,默认左右两边都会转为数字再比较大小。
特殊:1.如果参与比较的两边都是一个字符串,则会按位pk每个字符的十六进制Unicode号(或十进制ASCII码)
数字0-9 < 大写A-Z < 小写a-z < 汉字
常识:汉字的第一个字:一 Unicode号:4e00 ASCII:19968
汉字的最后一个字:龥 Unicode号:9fa5 ASCII:40869
2.NaN参与任何比较运算结果都为false,如何判断是不是NaN:!isNaN(x)
3.undefined == null;
解决:=== 全等,不带隐式转换的等值比较,要求数据相同,值也相同
3.逻辑运算符:&& 与 || 或 !非
4.赋值运算符:= += -= *= /= %=
5.自增自减运算符:++ --
自增/自减:固定每次加/减1
(i++/i--)和(++i/--i)的区别?
单独使用没有任何区别,但参加了表达式,变量始终都会加/减1,只是返回的结果不同,(i++/i--)返回的是加/减了之前的旧值,(++i/--i)返回的是加/减了之后的新值。
6.位运算
左移:m<<n,读作m左移了n位,翻译:m*2的n次方
右移:m>>n,读作m右移了n位,翻译:m/2的n次方
缺点:底数只能是2,不可以修改
分支结构
3大类:if分支 if...else switch...case分支
if(条件){
操作;
}
if(条件){
操作;
}else if(条件1){
操作1;
}...else if(条件n){
操作n;
}else{
默认操作;
}
swicth(变量/表达式){
case 值1:操作1;
break;
...
case 值n:操作n;
break;
default:默认操作;
}
if和switch的区别?谁好谁坏?
1.switch...case:优点:执行效率高,速度比较快;且他比较的时候,
case做的是等值比较而不是范围查找,且不带隐式转换
2.if...else:优点:可以做范围比较
缺点:执行效率低,速度比较慢
代码优化,尽量少用if...else,尽量替换成switch...case
3.三目运算:纯粹是为了简化简单的分支,操作只能一句话!
语法:条件?操作1:默认操作; === if...else
条件?操作1:条件2?操作2:默认操作; === if..else if..else
扩展:短路逻辑:条件&&(操作) === if
注意:1.默认操作是不能省略的,省略了会报错
2.如果操作比较复杂,不能使用三目运算
强制数据类型转换(显式)
1.转字符串
① var str = x.toString(); x不能undefined和null
② var str = String(x); 万能的,任何人都可转字符串,完全等效于隐式转换
其实String()就是隐式转换的底层原理,还不如"+";
2.转数字:3种
① ParseInt(str/num) - parse解析 Int整形
执行原理,从左向右依次读取每个字符,碰到非数字字符就停止,且不认识小数点
如果一来就不认识就会转换为NaN
② ParseFloat(str) - Float浮点型(小数)认识第一个小数点
③ Number(x); 万能的,任何人都可以转换数字,完全等效于隐式转换,不如x-0
*1 /1;
3.转布尔
Boolean(x); 万能的,任何人都可以转布尔,完全等效隐式转换,还不如!!X;
只有六个会为false:0, undefined, NaN, null, false, " ",其余为true。
循环结构
1.循环结构:反复执行 相同 或 相似的操作
循环三要素:
1.循环条件:开始 - 结束,循环的次数
2.循环体:每次循环要做什么操作
3.循环变量:记录着我们当前在哪一次,且它会不断的变化,变化往往
是向着不满足循环条件前进的。
2.三种循环结构
1.while循环:
语法:var 循环变量 = 值;
while(循环条件){
循环体;
循环变量变化;
}
死循环操作,在不确定循环次数的时候用
语法:while(true){
死循环操作;
}
break - 退出整个循环 - 多半都是搭配死循环
continue - 退出当前迭代,从下一次迭代继续执行
2.for循环:
语法:for(var 循环变量 = 值;循环条件;循环变量变化起来){
循环体;
}
死循环:for( ; ; ){ 循环体;}
***while和for的区别?
while和for从原理上没有区别
while更麻烦,一般不确定循环次数的时候使用死循环
for更简单,一般确定循环次数的时候使用 - 大部分情况都是使用他。
函数的基础
1.概念:function函数,也称为方法,先预定义好,以后可以反复使用的代码段
2.如何使用函数:有2步
① 定义/创建/声明
function 函数名(){ 函数体/代码段
② 调用函数:2种
直接在js内部书写:函数名()
在HTML页面上绑定点击事件:<elem onclick="函数名()">文字</elem>
用户点几次就调用几次
3.何时使用函数:不希望打开页面立刻执行、希望由用户来触发
4.形参函数的创建:带参数的函数其实就是一个变量,只不过不需要写var,且不需要复制
语法:function 函数名(形参,...){ 函数体
使用带参数的函数必须传入实参,函数名(实参,...)
注意传入的实际参数的顺序必须和形参的顺序一一对应,数量不要多也不要少
总之:不带参数的函数用于一些固定操作
5.总结:循环可以反复执行,函数也可以反复执行,他们的区别在于时机不同
1.循环:几乎是页面打开一瞬间就完成了
2.函数:需要调用后执行
自定义函数Function
1.创建:2种(目前) - 其实3种
① 声明方式 - 创建函数
function 函数名(形参){ 函数体; return 返回值;}
② 直接量方式 - 创建函数
var 函数名 = function(形参){ 函数体; return 返回值;}
2.调用函数:var 变量名 = 函数名(实参);
return后跟一个数据是将数据返回到函数作用域的外部,return只负责返回不负责
保存,所以在调用函数时需要用一个变量去接住它。
注:就算省略return,默认也会有一个return,会悄悄返回一个undefined,所以
函数有返回值才去用变量接住它
3.作用域:2种
1.全局作用域:全局变量和全局函数,在页面的任何一个位置都可以访问和使用
2.函数作用域:局部变量和局部函数,只能在函数调用时,内部可用。
注意:它带来了变量的使用规则,优先使用局部的,局部没有找全局的
缺点:1.局部可以使用全局的,但全局不能使用局部的;解决:加return
2.千万不要在函数中对未声明的变量赋值(例:a=1;)会造成全局污染,
全局本身没有这个东西,但函数作用域却给他添加上了。会降低网站性能
4.声明提前
原理:在程序执行之前,会将var声明的变量(轻)和function声明的函数(重),集中提前
到当前作用域的顶部,但赋值会留在原地
**强调:声明方式创建的函数会完整提前,直接量创建的方式不会完整提前,只有变量名部分会提前**
**变量名和函数名尽量不要重复,遵循先创建后使用**
5.函数内部的变量,都会在函数值执行完后,自动释放,意味着我们不需要自己写xx=null
6.重载
相同的函数名,根据传入的实参不同,自动选择对应的函数去执行,但js不支持,如果函数名重复了,后面的会把前面的覆盖
解决:在函数的内部自带一个arguments对象(类数组对象)
作用:哪怕没有写过任何形参,它也可以接收所有实参。
固定套路:
通过下标去获取传入的某一个实参:argument[i] – i下标从0开始
通过length去获取到到底传入了几个实参:arguments.length;
所以我们可以通过在函数内部开启分支判断arguments的不同,而执行不同的操作
数组Array的基础
数组:创建一个变量可以保存【多个数据】
数组都是线性排列的,除了第一个元素,每一个元素都有唯一的前驱元素
除了最后一个元素,每一个元素都有唯一的后继元素
**每个元素都有一个自己的位置,称之为下标,下标都是从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.数组具有三大不限制
① 不限制元素类型
② 不限制元素个数
③ 不限制下标越界
如果获取下标越界,返回的是一个undefined
如果添加元素下标越界,会得到一个稀疏数组
5.问:自己数下标,多了过后,难免数错,导致下标越界怎么解决?
解决:数组中的唯一属性:length
语法:数组名.length
作用:获取到数组的长度,长度是从1开始数的
三个固定套路:获取数组倒数的第n个元素:arr[arr.length-n]
向数组添加元素:arr[arr.length]=新值
缩容:删除数组倒数n个元素:arr.length -= n
6.遍历数组
往往很多情况,我们不会拿出数组的某个数组来操作,而是拿出数组中的所有数组来进行
相同 或 相似的操作 - 搭配循环
公式:for(var i = 0
arr[i]
}
注:JS里面只有两大类数据类型:1.原始 2.引用
DOM
1.全称:Document Object Model 文档对象模型;专门用来操作HTML文档的,提供了一些方法
2.DOM树概念:DOM将我们的HTML看作一个倒挂的树结构,但树根不是HTML标签,而是document对象
一个页面只有一个document对象
作用:可以通过树根对象找到我们想要的任何一个DOM元素/节点/对象(属性和方法)
DOM会将页面上的每个元素、属性、文本、注释等都会被视为一个DOM元素/节点/对象
3.查找元素:两大方面
<1>.直接通过HTML的特点去查找元素:
① 通过ID去查找元素:
var elem = document.getElementById("id值")
特殊:
返回值:找到了返回当前找到的DOM元素,没找到返回一个null
如果出现多个相同的id,那么只会找到第一个(id的唯一性)
**其实id根本不需要查找。可以直接使用,id的唯一性**
<2>.通过标签名去查找元素
var elem = document.getElementsByTagName("标签名")
特殊:
返回值:找到了返回的是一个类数组DOM集合,没找到返回一个空数组
JS只能操作DOM元素,不能直接操作DOM集合!解决:要么拿到某一个下标,要么遍历拿到所有人。
不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成已经找到的某个元素。
<3>.通过class名去查找元素
var elem = document.getElementsByClassName("Class名")
4.通过元素之间的关系去查找元素:前提:至少要【先找到一个元素】才可以使用
父级:elem.ParentNode
子级:elem.Children
子级之间的第一个:elem.firstElementChild
子级之间的最后一个:elem.lastElementChild
兄弟元素之间的前一个:elem.PreviousElementSibling
兄弟元素之间的后一个:elem.nextElementSibling
5.操作元素:前提是先找到元素
1.内容的获取与设置:
<1>. 内容:.innerHTML 获取或设置开始标签到结束标签之间的内容【支持识别标签】
获取:elem.innerHTML
设置:elem.innerHTML = " "
<2>. innerText - 获取或设置开始标签到结束标签之间的纯文本【不支持识别标签】
获取:elem.innerText
设置:elem.innerText = " "
以上两个专门双标签准备的,而有一个单标签也可以写内容:<input/>
<3>. value - 专门用于获取或设置input的内容
获取:input.value
设置:input.value = " "
2.属性的获取与设置
<1>.获取属性:elem.getAttribute("属性名")
设置属性:elem.setAttribute("属性名","属性值")
简化版:获取属性:elem.属性名
设置属性:elem.属性名 = "属性值"
简化版有两个小缺陷:
class必须写为className,ES2015(es6)class变成了一个关键字
只能操作标准属性,不能操作自定义属性
3.样式:
一般JS是操作的内联样式
获取样式:elem.Style.css属性名
设置样式:elem.Style.css属性名 = "属性值"
特殊点:css属性名,有横线的地方,去掉横线,换为小驼峰命名
例:border-radius 换为 borderRadius
小缺陷:获取时,只能获取内联样式
4.绑定事件:
elem.onclick = function(){
操作
***关键字this***
如果单个元素绑定事件,this->这个元素
如果多个元素绑定事件,this->当前元素
}
结束