1.JS的基本概念
JavaScript是运行在客户端浏览器的解释型、弱类型、面向对象的脚本语言
编程语言分类
- 按翻译的方式:
- 编译型:程序运行前先检查语法是否正确,正确则运行,否则不允许运行,语法严格
- 解释型:程序运行前不需要检查语法是否正确,直接运行,遇到错误则停止后续代码,语法宽松
- 按严格程度
- 强类型:变量保存的数据,是由定义的数据类型决定的
- 弱类型:变量保存的数据可以是任意类型,数据类型由数据本身决定
- 按编程的核心分类
- 面向过程
- 面向对象:常使用的写法:对象名.属性名;对象名.方法名();
组成部分
- BOM:Browser Object Model 浏览器对象模型,用来操作浏览器
- DOM:Document Object Model 文档对象模型,可以用js来操作HTML和CSS
- ECMAScript 核心语法(算法题/逻辑题)
DOM树概念:DOM将我们的HTML看做了是一个倒挂的树状结构,但是树根不是html标签,而是document对象
document对象:不需要我程序员创建的,由浏览器的js解释器自动创建,一个页面只有一个document
作用:可以通过树根找到我们想要的任何一个DOM元素/节点/对象(属性和方法)
DOM会将页面上每个元素、属性、文本、注释都会当作一个DOM元素/节点/对象
查找元素
- 通过ID查找元素
语法:var elem=document.getElementById("id值");
特殊:
- 返回值,找到了返回的是一个当前找到的DOM元素;没找到,返回一个null,做了别的操作可能就会报错
- 找到了多个相同的id,那么只会返回第一个
- 一次只能获取一个元素,也只能操作一个元素
- 其实根本不需要使用此方法,直接写ID也可以找到元素
- 通过标签名查找元素
语法:var elems=document/已经找到了的父元素.getElementsByTagName("标签名");
特殊:
- 返回值:找到了返回的一个是类数组DOM集合(很像数组,都能用下标,都能用length,都能遍历),没找到返回一个空集合
- JS不能直接操作DOM集合,只能直接操作DOM元素,解决:要么使用下标拿到某一个元素,要么使用遍历拿到每一个元素
- 不一定非要从document开始查找,如果document去找,会找到所有的元素,可以换成我们已经找到的某个父元素,就只会找到这个父元素下面的元素了
- 通过class名查找元素 语法:var elems=document/已经找到了的父元素.getElementsByClassName("标签名"); 等同于通过标签名查找元素
- 通过关系查找元素:
前提条件:必须先找到一个元素才可以调用关系网
- 父元素:elem.parentNode;
- 子元素:elem.children; (找到的是一个子元素集合)
- 第一个儿子:elem.firstElementChild;
- 最后一个儿子:elem.lastElementChild;
- 前一个兄弟:elem.previousElementSibling;
- 后一个兄弟:elem.nextElementSibling;
操作元素
前提:找到元素才能操作元素: <标签 属性名="属性值" style="样式">内容</标签 >
1.内容:
- innerHTML:获取 和 设置 开始标签到结束标签之间的内容 - 支持识别标签 获取:elem.innerHTML; 设置:elem.innerHTML="新内容";
- innerText:获取 和 设置 开始标签到结束标签之间的文本 - 不支持识别标签 获取:elem.innerText; 设置:elem.innerText="新文本"; 以上两个属性都是为双标签准备的,但是操作不了单标签input的内容
- value:专门为input的value值准备的 获取:input.value; 设置:input.value="新值";
2.属性: 获取属性值:elem.getAttribute("属性名"); 设置属性值:elem.setAttribute("属性名","属性值");
简化版: 获取属性值:elem.属性名; 设置属性值:elem.属性名="新属性值"; 缺陷: 1.class必须写为className - 2015年过后,ES6诞生过后,class变成了一个关键字 2.不能操作自定义属性,只能操作标准属性
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->当前触发事件的元素 }
总结: 获取 - 往往都是用与判断比较 设置 - 就是添加/修改
扩展:计算字符串 - 脱字符串的衣服: eval(str);
2.引用js的方法
- 行内式:
- a标签:书写在href属性上 如,<a href="javascript: alert('hellow world')">点我一下</a>
- 非a标签:书写在行为属性上 如,<div onclick="alert('hello world')">点我一下</div>
- 内嵌式: 在body中添加<script> </script> 在标签内直接书写JS代码 (直接执行,不需要依赖任何行为)
- 外链式: 在body中输入<script src="XXX.js"></script> 另建XXX.js文件直接书写js代码 (直接执行,不需要依赖任何行为)
注意:script标签只要有了src属性,标签之间不能再写代码
3.js的输出方式
- 在控制台输出日志 console.log() 在F12控制台显示日志
- 在页面输出日志 ducument.write()/ducument.writeIn() 在页面上输出,而且支持识别标签; 但如果绑定了点击事件后输出,会把页面上原来的HTML和CSS都全部替换掉
- 在警告弹出框输出日志 alert()/window.alert() 在一个浏览器自带的弹出框中输出日志,但是弹出框会卡住页面,用户只能看到一个白板
4.变量
用来保存程序运行过程中的中间值,创建后可以再次修改 var nub=100; var是容器 nub是自定义的容器名字 在js中=的含义是赋值 一个变量只能储存一个值,当新写入值时,会清除原来的值 例:
<script>
var num=100
alert(num)
var num=200
alert(num)
// 会先弹窗显示100,点击确定后显示200,此时变量num的值为200
</script>
变量命名规则:
- 由数字、字母、下划线、$组成
- 不能以数字开头
- 严格区分大小写
- 不能使用==关键字==或==保留字==(目前还不是关键字,以后可能是关键字的字),如 var for function等js中有特殊意义的单词
- 最好是使用一些有语义的单词,能直观展示变量的内容,建议下划线命名法或小驼峰命名法
注意: 如果变量名为name,自动转为字符串数据类型 可以在一条语句里面,声明多个变量,用逗号分隔
用户输入弹出框 var user=prompt("提示文字","默认值")
常量
常量,值不能改变 使用const关键字声明一个常量 习惯上,常量名使用纯大写形式
const PI = 3.1415926;
//常量的值是不能改变的。
PI = 3.1416 ;
console.log( PI);
//报错,无法改变常量的值
5.数据类型
- 基本数据类型:
- 数值类型Number
var num=2e5 科学计数法 2 * 10的五次方
var num=0x100 十六进制
var num=0o100 八进制
var num=0b100 二进制
NaN:
- not a number 不是一个数值
- 表示存储数据是数值类型的数据,但不是一个数值
- NaN参与任何算数运算结果为NaN
- NaN参与任何比较运算结果为false
- 因此↑,判断是否为NaN不能用== 或 === ,而使用 isNaN(需要判断的对象)==true则为NaN
- 字符串类型String
包含在引号内的数据(不区分单引号双引号) var s='hello world' var s="好好学习,努力赚钱" 注意:页面上的一切东西,数据类型默认都是一个字符串 - 布尔类型Boolean
var b=true 真 var b=false 假 - 空类型Null
var k=null null表示有值,有一个空值,用于释放变量/内存,节约内存空间 - 未定义型Undefined
var k undefined表示没有值
- 数值类型Number
- 引用/对象数据类型:11个引用类型的对象
object 对象
function 函数
array 数组
...
数据类型检测
语法: typeof 要检测的变量
结果:该变量存储的数据的数据类型(这个结果的数据类型是字符串)
检测返回值
数值类型 返回 number
字符串类型 返回 string
布尔类型 返回 boolean
undefined 返回 undefined
null 返回 object
6.数据类型的转换
-
转数值
- Number(需要转化的对象)
所有数据类型都可以转换,完全等效于隐式转换 - parseInt(需要转化的对象)
字符串和小数转为整数型数字,从左向右依次读取每个字符,碰到非数字字符,就停止转换,如果一来就碰到了不认识的,则为NaN - parseFloat(需要转化的对象)
执行原理同parseInt,可以识别第一个小数点 - 隐式转换(X-0 X*1 X/1 X%1)
true->1 false->0 undefined->NaN null->0 ''->0
- Number(需要转化的对象)
-
转字符串
- String(需要转化的对象)
- 需要转化的对象.toString()
注意:undefined或null不可用,因为两者都不能使用任何的.操作 - 隐式转换(X+'')
- String(需要转化的对象)
-
转布尔
- Boolean(需要转化的对象)
注意:除了0 NaN '' undefined null转化为false;其他都会转化为布尔数据true - 隐式转换(!!X)
- Boolean(需要转化的对象)
7.js运算符
算数运算符 进行数学运算的符号
赋值运算符 进行赋值操作的符号
比较运算符 进行比较运算的符号
逻辑运算符 进行逻辑运算的符号
自增自减运算符 单独对一个变量进行+1或-1操作的符号
- 算数运算符:具有隐式的数值类型转换(当字符串为纯数字的情况下,转为数值类型,如果字符串包含了非数字字符,直接转为NaN)
+正常为加法数学运算,当符号任意一边是字符串的时候,就会进行字符串的拼接
-*/%分别是减法、乘法、除法、取余的数学运算
取余运算的运用:
1.判断奇偶性:num%2,结果为0说明是偶数,结果为1说明奇数
2.获取一个数字的倒数n位 - 赋值运算符:
= 进行赋值操作
+= 加等于 例如n1+=3 相当于n1=n1+3
-= 减等于
*= 乘等于
/= 除等于
%= 取余等于 - 比较/关系运算符:结果一定是布尔数据true或false
- 常规比较:
> 大于
< 小于
>= 大于等于
<= 小于等于 - 特殊比较:
== 等于比较 只比较值是否相等,不考虑数据类型
=== 全等于比较 值和数据类型都相同
!= 不等于比较
!== 不全等于比较
想要判断多个条件,只能运用逻辑运算符
- 常规比较:
- 逻辑运算符:符号两侧只能是布尔数据
&& 与运算 必须符号两边都为true,最终结果才是true
|| 或运算 只要符号任意一边是true,最终结果为true
! 非运算 本身是true结果为false,本身是false结果为true(取反运算) - 自增自减运算符:
++ 自增 在自身基础上+1
前置++:先改变变量值,再参与运算
后置++:先参与运算,再改变变量值
-- 自增 在自身基础上-1
前置--
后置--
关于NaN的运算:
console.log ( '北京'-100=='北京'- 100 );//false;左侧'北京'-100结果是NaN;右侧'北京'-100 结果是NaN;NaN≠NaN
console.log ( '北京'+100=='北京'+ 100 );//true;执行字符串拼接,结果是true;
8.条件分支语句
程序的流程控制语句:3种
1、顺序执行 - 默认,从上向下的依次执行
2、分支结构 - 通过条件的判断,选择部分代码执行
3、循环结构 - 通过条件的判断,选择要不要重复执行某些代码
- if语句
if(){} 条件满足就执行if的{},不满足不执行
if(){}else{} 条件满足就执行if的{},不满足就执行else的{}
if(){}else if(){} 哪一个条件满足就执行哪一个if的{},前面条件满足了,就不考虑后面的条件
if(){}else if(){}else{} 多个条件依次判断是否满足,满足则执行if的{},所有条件都不满足,执行else的{}
在()中书写条件
在{}中书写条件满足时执行的代码
9.循环结构语句
循环结构:反复执行【相同或相似】的操作时使用
循环三要素:
1.循环条件:开始 - 结束,循环的次数
2.循环体:做的操作是什么
3.循环变量:记录着我们当前在哪一次,而且他会不断的变化,往往都会向着不满足循环条件进行
- while语句
语法:
var 循环变量=几;
while(循环条件){
循环体;
循环变量变化;
}
执行原理:首先创建了循环变量,然后判断条件,如果条件满足,则做【一次】循环体操作,并不会退出循环,回过头继续判断条件是否满足,如果满足,则再做【一次】循环体操作.直到循环条件不满足,才会退出循环
宏观上感受循环一瞬间就结束了,但是微观上来说其实是【一次一次】执行的
特殊:
1.死循环:永远不会停下来的循环
何时使用:不确定循环次数的时候
while(true){
循环体;
}
2.退出循环语句:break - 只能在循环中使用,多半都是搭配死循环使用的
- for语句
语法:
for(var 循环变量=几;循环条件;变量的变化){
循环体;
}
死循环:
for(;;){
循环体;
}
面试题:while 和 for 的区别?
语法上有区别,但两者都能做到相同的操作
一般来说我们不确定循环次数的时候,会使用while循环 - 死循环
一般来说我们确定循环次数的时候,就用for循环 - 更漂亮更简洁,大部分情况都会使用它
10.函数
Function:函数,称之为方法:需要提前【预定义好】的,以后就可以【反复使用】的【代码段】
定义/声明/创建函数: function 函数名(){ 函数体; } 调用/使用函数:
- 要么在js中程序员直接写死,要执行几次:函数名();
- 交给用户绑定在某个元素上,写上点击事件,让用户来触发
何时使用:
- 不希望打开页面立刻执行,而需要时再使用或由用户触发
- 希望能够反复执行,不用刷新页面
- 以后任何一个独立的功能体,都要单独封装为一个函数(你的每一个作业)
- 函数的地位非常高,函数是第一等公民地位,随时随地考虑能不能封装为一个函数,尤其是重复的代码
- 函数内的一切内存,函数调用完毕后都会自动释放
带参数的函数
定义:function 函数名(形参1,形参2,...){
函数体;
}
调用:函数名(实参1,实参2,...)
形参:形式参数,其实就是一个变量,但是不需要写var,而且默认也没有保存任何值,默认值为undefined
实参:实际参数,真正的值,需要再你调用时再传入
注意:
- 传实参的顺序一定要和形参的顺序一一对应,并且数量也要对应
- 不是一定要带参数的函数才是好函数,具体情况,需要具体分析:
如果函数体就是固定的,则使用普通函数
如果函数体希望根据传入的实参不同,做的略微不同,则使用带有参数的函数
11.数组
场景: 当需要保存多个数据时,不推荐使用变量,因为变量其实就是我们所谓的内存,变量创建的越多,那么我们内存空间消耗就越大,那么网站的性能就会越差.这种情况就使用数组.
定义:创建一个变量可以保存【多个数据】的集合 数组都是线性排列,除了第一个元素,每个元素都有唯一的前驱元素 除了最后一个元素,每个元素都有唯一的后继元素 每个元素都有一个自己的位置,称之为叫做下标(索引),下标是从0开始的,到最大长度-1 与对象不同点:不需要键名,自带顺序
创建一个数组
1.直接量方式:
var arr=[];//空数组
var arr=[数据1,数据2,...];
2.构造函数方式:
var arr=new Array();//空数组
var arr=new Array(数据1,....);//注意:此方法只写一个值的时候为数组长度,即一个定义了数组长度的空数组
数组具有三大不限制
- 不限制元素的个数
- 不限制元素的类型
- 不限制元素的下标越界 如果获取元素,下标越界,返回的一个undefined 如果添加元素,下标越界,会得到一个稀疏数组,导致下标不再连续,如果搭配上循环去遍历每一个元素的话,我们会得到很多很多的undefined
数组的操作
- 长度的操作
- 获取长度 arr.length 其值为最大下标+1
- 设置长度 arr.length=数值 长度小于原数组长度时,会按照顺序删除靠后的数据
- 三个固定套路: 1. 获取倒数第n个元素:arr[arr.length-n] 2. 始终向末尾添加元素:arr[arr.length]=新值; 3. 缩容:删除倒数n个元素:arr.length-=n
- 数据的操作
- 获取数据 arr[索引值]
- 设置数据 arr[索引值]=数值 下标处没有元素为添加,有则替换
数组的遍历 从头到尾依次访问数组的每一个数据即遍历 利用循环进行遍历,开始为0,结束为小于数组长度,步长为1,使用循环控制变量当做数组的索引来访问数组中的每一个数据
for(var i=0;i < arr.length;i++){
console.log(arr[i])
}