js第一篇(基础)
JavaScript:依赖HTML的脚本语言(网景公司的Netscape)
script标签:三种写法(行内,内联,外联)
外联后script里面不需要写代码
script可以和style一样放在页面任意位置
初期建议放在/body和/html之间
注释:
//
/**/
输出语句:
- 加载至文档流:document.write();
- 用户提示:alert();
- 删除前的进一步提示:confirm();
- 输入框:prompt();
- 调试,控制台输出:console.log();
js语法要求:
单双引号尽量保持一种
分号可加可不加,要加都加,要不加都不加
变量:
本质就是存数据的容器—放在内存中
显示声明:var a = 5;
隐式声明:b = 5;
var a= b=c = 5;相当于 var a = 5;b = 5;c = 5;
一次性定义多个变量:var a = 3,b,c,d;
规则:
- 变量名不能数字开头,字母数字下划线美元符号组成
- 关键字不能作为变量名。
变量类型:
number:
var a = 10;
String:
若干个 任意字符 引号号包含起来
boolean
true,false
undefined未定义类型
var a ;.//undefined
object对象类型
三种表现形式:
数组:
var arr =[1,2,3]
json对象
null关键字
小数问题解决方案
js进行小数计算会精度损失
var a = 0.2,b = 0.1;
var c = a + b ;
console.log(c);//0.30000000000000004
解决方案:
方法一:乘以10除以10
var a = 0.2;
var b = 0.1;
var c = (a*10 + b *10) / 10;
console.log(c);
方法二:强直保留小数点后几位
console.log(c.toFixed(3));
NaN(not a number)
var a = 10;
var b = 'abc';
var c =a -b;//NaN
console.log(c);//NaN
特点:
跟任何数据饭都不相等,包括自己
isNaN():检测一个数字是不是数字//true不是一个数字,false是数字
100a时显示true
字符串类型
单引号和双引号不可以嵌套他们自身
原因:引号虽然是字符,但是有特殊含义
解决:单嵌套双或相反;转义字符
注意:字符串拼接可以用加号
js可以输出标签的,doucment.write(“
“);
输出字符串长度:str.length
字符串也可以+=
运算符
赋值运算:
= ,+=,-=,…
作用;将右边的值赋给左边的变量
数字运算符
+ - * / %
字符串拼接:加号两边都是数字才运算
比较运算符
<等等
其中 ==是比较值的, ===是先比较类型,再比较值
因为 == 和!=是会自动进行数据类型转换的,转成数字再比较
强制类型转换
转为number:
Number():字符串纯数字才可以转为数字型,不然NaN
布尔true为1,false为0
undefined转数字是NaN
null转数字是0
parseInt();字符串前面的整数获取到
"12.34"==>12
parseFloat()字符串前面的小数获取到
"12.34"==>12.34
转boolean
Boolean(要转换的数据);
会转为false的情况;
NaN,0,’’,undefined,null
转字符串:
String():就是加个引号
数据.toString();
直接加上””;
自动类型转换
- 字符串拼接时,一边为字符串,另一边转为字符串
- 比较运算时,左右有一个是数字,另一个也会被转为数字比较
- 当进行除了加法以外的数学运算,会将两边转为数字再运算
逻辑运算
&& 与
||或
!非
通常连接两个表达式
控制台黑色数字为字符串类型,蓝色数字为数字类型
三元运算符
1 ? 2 :3;
1是正确的执行2,否则执行3
常用于双分支的替代
也可以将整个表达式赋值或者输出
进行数字加法运算的时候一定要检测是不是数字类型
逻辑分支
单分支:
if(条件){满足条件执行}
小括号内自动转换为boolean型
双分支
if(条件){当条件满足执行}else{不满足时执行}
多分支
if (条件) { 代码块 } else if ( 条件 ) { 代码块 } else if ( 条件) { 代码 块 }…else { 代码块 }(最后这个可写可不写)
单个多分支是多选一,多个单分支是多选多
分支语句可以简写
switch多路判断:
类似于多分支,只能判断一个变量跟某些值是否全等
var num =1;
switch(num){
//switch小括号里面的值只能是变量
case 1:num ===1;(重点)
执行语句;
break;
...
default:
执行语句;break;
}
break是可以省略的,称为case穿透
当num=2:
case 2: console.log(“hello”);//这里省略break
case 3:console.log(“hello”);break;//这个就不判断了
当num=3:
case 3:跳过了case 2;但是倒过来写会执行case 2。
注意:
- switch的运行效率是高于分支的,因为直接到达符合条件的地方,不需要从上往下判断
- 当判断是否相等时更加精确
分支语句的细节
小括号里面的可以放任何值,最终都转为boolean类型
自增自减运算
前缀先运算在操作,后缀先操作再运算
总结:
字符串的比较是逐位比较的,”|10”>”2”为false
switch倒着写可以实现累加的效果
剩下的多少秒:秒数%60
剩下小时 = 小时数 %24
循环
目的:处理重复
循环小括号的变量为全局变量
while循环:
var i =15;
while(i > 10){
i--;
console.log(i);
}
do-while循环(while循环的变异)
var i = 15;
do{
i--;
}while(i<10);
至少执行一次
for循环
for(var i = 15;i<10;i--){
console.log(i);
}
var i = 0;
for(;i<10;i++){
console.log(a);
}
for (var i = 0; i < 10; i+2){
console.log(i);
}
for (var i = 0;i < 10; salary = salary *0.1 ){
i++;
}
循环跳转:
break:跳出当前循环;
continue:跳出·此次循环,执行下次循环
continue的书写顺序要靠前,放在最后执行了效果等于没执行
循环的嵌套
for循环里面的还可以继续嵌套
DEBUG:
函数:
目的:处理重复
可以重复利用的工具
如何定义函数(%):
语法:function 函数名(){
代码段;
}
函数的定义其实是赋值过程,在内存中开辟fn的空间,fn存放代码
函数的调用:
函数名();//调用函数内部的代码
fn()中fn其实是数据类型(function),里面存放的是function后面的代码
定义一个函数:
function fn(){
console.log(123);
}
在内存的显示:
f fn(){
console.log(123);
}
function //返回类型
形参:形式上的参数
实参:实际意义上的参数,用于给形参赋值,调用时候的小括号内,类型和个数需要和形参相对应
函数的优点:重复执行,模块化编程
函数的书写:先写核心代码,然后用函数包裹起来
匿名函数:
var fn=function(){
//定义变量fn,赋值一个函数
console.log(123);
}
fn();//调用
使用场景:事件中
总结:函数可以没有名字,然后将函数赋值给一个变量——同样能使用
原因:函数的定义过程,其实就是在内存空间中开辟了空间,存放一段代码作为值
fn里面的值:
自调用函数(匿名函数使用小括号包起来):
匿名函数的fn代表的是:
function(){
console.log(123);
}
那么fn()就是
(function(){
console.log(123);
})();
也可以写成:
! function(){
console.log(123);
}();
!可以换成~,能看懂别人这么写就可以
好处是什么?省去了调用
函数提升篇:
代码执行顺序:
从上而下,从左至右,逐字符依次执行。只有有名字的函数才叫函数的定义(打%的地方)。
预解析:
从所有代码中找到变量的定义和函数的定义,找到了就会将变量的定义和函数的定义放到所有代码的最前面,然后再执行。
注意:函数的大括号可以约束声明提升,但是if语句等的大括号不具有约束性
var a = 10;
分为两个步骤:定义a,将a赋值为10
题目检测:
console.log(fn);
fn();
var fn = function(){
console.log(123);
}
运行结果:
undefined
报错
fun();
var fn = function(){
console.log("我是fn函数");
}
function fun(){
console.log("我是fun函数");
}
fn();
fn = 100;
fn();
运行结果
我是fun函数
我是fn函数
报错
fn();
function fn(){
console.log("我是一个fn函数");
}
fn();
var fn = 100;
fn();
运行结果
我会fn函数
报错
这里预解析的时候函数和变量重名,保留函数
var a= b;
a = 0;
b = 0;
console.log(a);
console.log(b);
直接报错
因为b没被定义就被使用,一定要先定义再使用
var fun = 200;
fun();
var fun = function(){
console.log("我是一个fun函数");
}
直接报错,因为预解析后fun这个空间的值是200,不是函数,无法调用
function fn(a){
console.log("我是fn函数");
a();
functio a(){
console.log("我是函数a");
}
}
fn(10);
我是fn函数
我是函数a
注意:形参赋值是在函数提升和参数提升之前的
console.log(num);
if(false){
var num = 100;
}
undefined
注意:不会执行的代码也是要预解析的
return关键字
让一个函数返回值,后面的语句都不会执行
return只能停止函数,break只能停止循环和switch
函数中的循环可以加return
循环中的函数可以加break;
没有return的函数默认返回undefined
函数的书写步骤
- 先写核心代码
- 再写上函数外壳
- 然后寻找形参,提出来
作用域
能起作用的区域
在不同地方定义的函数和变量,起作用的范围是不同的
不在任何函数内定义的变量称为全局变量
在函数内定义的变量称为局部变量
全局变量在局部范围内有效
局部变量在全局范围内无效
函数定义好了就相当于创建了个作用域,任何函数都可以创建作用域
作用域可以嵌套成作用域链
作用域链的使用规则:
赋值:
先从当前作用域查找变量的定义,没有找上一级,直到全局,全局有就赋值给全局变量;全局没有就隐式定义这个变量——-不过不存在提升过程。
运算、比较、输出等操作,先从当前作用域查找变量的定义,没有就杀上一级,直到全局,全局没有就报错,有则使用。
递归函数:
注意内存溢出错误(Maximum call stack size encoded)
先定义一个空函数,然后往空函数里面输入值:
function fn(){
if(num ==1){
return 1;
}
return num*fn(num-1);
}
注意一定要写return
事件
匿名函数的应用:
目的:
处理用户在网页上的行为,如点击,右击等
事件三要素:
事件源:
能触发某种行为的HTML标签
事件类型:
拖拽,移动
事件处理程序:
函数
在js中使用标签id代表标签,不要使用常见的关键字(name,start,stop)
语法(事件的定义):
事件源.onclick = function(){
console.log(123);
}
常见的事件类型
事件类型 | 含义 |
---|---|
click | 单击 |
dblclick | 双击 |
mouseover | 鼠标移入 |
mouseout | 鼠标移出 |
submit | 事件源form,点击的是submit 常见于表单验证,点击之后,跳转页面 |
keydown | 键盘按下,window.onkeydown |
keyup | 键盘抬起,window.onkeyup |
focus | 获得焦点/光标 |
blur | 失去焦点 |
load | 等页面所有加载完后最后开始加载,window.onload ,可以让script放在任何位置,不用考虑加载顺序问题 |
注意,知识点来了:事件的函数是由系统来调用的,事件的类型有系统提供的
事件的书写
第一种:
div.onclick = function(){
console.log(123);
}
第二种;
btn.onclick =fn;
function fn(){
console.log(123);
}
第三种:行内书写
onclick ="javascript:console.log(123);"//只能写一个语句
onclick=onclick(){
}
js的关键字:
this:在全局中表示window(浏览器窗口),在事件中代表事件源
对象
对象分为数组/json对象/null
json:
定义:
多个数据(键值对)组成的集合
直接定义:
var obj ={
name:"张三",
age:12
}
构造函数:
var obj =new Obj({
name:"张三"
});
对象数组的组成:
键值对形式:
键必须是字符串,在定义的时候可以不加;键中包含连字符“-”,那就须要加上引号;
值是任意类型(可以是函数)
对象的操作:
增删改查:
操作 | 写法 |
---|---|
增 | 对象.键 = 值;/对象[“键”] = 值 ; |
删 | delete 对象.键/delete 对象[“键”] |
改 | 存在那个键值对,增的形式就可以修改 |
查 | console.log(obj.name/obj[“name”]) |
对象的遍历:
js提供了特殊的for
for(var attr in obj){
obj[attr];
}
attr是键,obj是对象
**注意:**错误写法如下
var a ="name";
obj.a;//这么写是错误的,因为obj里面没有a这个键
正确写法:
var a = "name";
obj[a];
对象的方法
对象的值如果是函数,那么这个键就叫做对象的方法
如果碰到多个键值对,就用对象
构造函数初体验
被用来new创建对象的函数都是构造函数
任意函数都可以new来当构造函数,当一个函数被用来创对象,就可叫构造函数
系统提供了一些构造函数来创建对象
//系统内置的构造方法
var num = new Number(12);
String();
Booelan();
这里的num是对象型,可以参与数学运算并得到结果
原理:js的底层处理任何的数据都是对象处理的,为了让开发者更加接近于正常的理解,js提供了基本数据类型,供开发者使用。
数组
也是多个数据的集合,但是相较于对象,数组在内存是按顺序排列的
数组的定义
一:直接定义
var arr=[1,2,3,4,5];
二:构造方法
var arr =new Array(5);
创建了5个empty
不建议使用
上面两种方式的区别只存在都给里面放个数字
var arr=['a'];
vae arr = new Array('a');
//这两个是一致的
数组的特性:
数组对象里面有属性length,可通过arr.length获取数组长度
数组第一个下标为0,最后一个下标为arr.length-1
数组的操作
操作 | 写法 |
---|---|
增 | arr[i]= [1,2,3] |
删 | delete arr[i] 或者arr.length = 0; |
改 | arr[i ] =“d”,arr[i]已经存在 |
查 | arr[i] |
数组遍历:
方法一:
var length = arr.length;//因为每次判断都要取值一次,浪费时间
for(var i = 0;i <length;i++){
console.log(arr[i]);
}
方法二:
for(var i in arr){
console.log(arr[i]);
}
这个方法是遍历对象的,当然可以遍历数组
二维数组:
数组的元素类型没有限制,所以是数组类型也可以
嵌套两层为二维数组,嵌套三层为多维数组
查看三维数组中的某个元素arr[0][2][1];
建议:数组里面只放一种数据类型,对象里面放多种数据类型
数组的操作方法:
- splice(开始位置,删除个数,增加元素)
参数一和参数2必须写,参数三为可选项
最常用,插入删除修改数组
被操作数组被修改
pop():删除最后一个元素
unshifted():开头加上元素
shift():开头减少元素
push():末尾加上一个任意类型元素
- concat()数组拼接:
var res =arr1.concat(arr2);
var res1 = arr1.concat(“a”,“b”);//也是拼接在arr1数组末尾
拼接在数组末尾,arr2数组元素拼接进arr1中
- 数组的排序sort:
arr.sort(function(a,b){
return b-a;//降序 return a - b;为升序
})
- 连接join:
arr.join(“-“)
按照指定字符拼接成字符串
利用数组写页面
var arr = [
{
name: "手机",
img: "https://www.baidu.com/img/dong_8ff048ec89a4c8b4d638def4ce4dafda.gif",
price: 50,
desc: "真便宜,没好货"
}
]
document.write("<ul>");
document.write(" <li><img src="+arr[0].img +" alt=\"\"><p>"+arr[0].name+"</p><span>50</span> <div>"+arr[0].desc+"</div></li>");
document.write(" <li><img src="+arr[0].img +" alt=\"\"><p>"+arr[0].name+"</p><span>50</span> <div>"+arr[0].desc+"</div></li>");
document.write(" <li><img src="+arr[0].img +" alt=\"\"><p>"+arr[0].name+"</p><span>50</span> <div>"+arr[0].desc+"</div></li>");
document.write("</ul>");
基本类型的内存机制:
栈内开辟空间,放入数据,b=a就是将a内存里面的数据复制一份到b
引用类型的内存机制:
数组在栈内开辟空间,将数组内容放在堆内存,栈内存存放数据的地址,b=a赋值的是数组的地址,修改的是堆内存的数组,对a的值也会产生改变
冒泡算法
算法原理:每相邻的两个元素比较大小,不符合规则就交换两个元素的位置
var arr=[1, 5, 3, 7, 6, 14, 9, 1, 4, 8, 2];
var length = arr.length;
for(var i = 0; i<arr.length;i++){
for(var j = 0;j<length -1;j++){
if(arr[j]>arr[j+1]){
var tmp =arr[i];
arr[j] = arr[j+1];
arr[j+1] =tmp;
}
}
}
console.log(arr);
选择排序
原理:每次选择最小的或最大的值放在合适的位置
var arr = [1, 5, 3, 7, 6, 14, 9, 1, 4, 8, 2];
for(var j = 0; j <arr.length - 1 ; j ++ ){
var min = arr [j];
for(var i = j+1 ;i <arr.length; i++ ){
if(arr[j]> arr[i] ){
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
console.log(arr);
ES5 简单认识
ES5 兼容性最好的版本
ES6也称为ES2005
ES:ECMAScript的简写
严格模式:
“use strict”;
要求:
- 不允许隐式定义变量
- 不允许普通函数内this代表window
- 不允许形参重名(js函数形参重名是可以执行的,但是不建议这么写)
写法:
在script的最前面或者在函数的最上面写上”use strict”;
好处:
消除怪异语法,更加规范化
运行效率更高
严格模式也受到作用域限制
数组方法:
- indexOf():查第一个值在数组中第一次出现的下标,查不到返回-1
map():将数组的每个值处理,返回新元素组成的新数组
arr.map(function(v,i,a){
return v*0.3;
})
v:数组元素,i:数组下标;a:数组本身
i,a是可选项filter方法:
过滤函数
满足条件的元素组成新数组返回。
参数和map一致爱如如.filter(function(v,i,a){
return v< 60;
})
4.reduce方法:归并
arr.reduce(function(v,i,a){
return v<60;
})
a:第一次值为arr[0],之后是上一次函数的return,没有返回undefined
b:a[次数];
map和filter用的最多
字符串
字符串的比较规则
从左到右逐个字符比较的
字符大小规则遵循ASCII码
数字<大写字母<小写字母
排名越靠前越小(a<z)
字符串的操作
操作 | 形式 |
---|---|
查 | str[i] |
增删改 | 没有,都会形成新的字符串 |
遍历字符串
for(var char of String){
console.log(“字符”+char);
}
常见的API
- charAt():通过指定的下标获取字符串的字符(极其鸡肋,不要记)
str.charAt()
2.charCodeAt():通过指定下标获取字符对应的ASCII码
3.固定写法:String.fromCharCode()——-通过ASCII码返回一个字符
var num= 97;
var s = String.fromCharCode(num);
console.log(s);
- indexOf()
查字符在字符串中第一次出现的下标,没有返回-1 - lastIndexOf():
查字符串最后一次出现的下标,返回值为下标或者-1 - substr():
截取字符串,参数一开始截取的下标,参数二截取长度(不写默认截取到尾) - substring():截取字符
参数一:开始下标
参数二:结束下标(不写默认到结尾,不包含参数二的) - slice()
截取字符串,和substring一样的
截取从左到右,不是从右到左
开始下标为负数的话,-1表示倒数第一个
数组里面也有slice方法 - split():
把字符串转成数组(俗称“炸”)
使用指定的分隔符将字符串分割成很多小字符串,组成数组并返回
没有参数将整个字符串当做元素放入数组
split(“”):每个字符都当成元素组成新数组 - replace():
替换字符串中的指定内容,只能替换一次,循环才可以替换多次
str.replace(“html”,“css”);
var s = str.replace(“”) - trim()
去除左右的空格,可分为trimLeft()和trimRight()
toLowerCase();//全部小写
toUpperCase()//全部大写
Math Date
math对象:系统内置的对象
math不像String和Date是对象的类,因此没有构造函数Math(),像Math.sin()这样的函数只是函数,不是某个对象的方法。无需创建,通过把慢作为对象使用就可以调用其所有的属性和方法
格式 | 功能 |
---|---|
Math.PI | 圆周率 |
Math.round() | 四舍五入 |
Math.pow(底数,幂数) | 次方 |
Math.random() | 获取随机数 |
Math.floor() | 向下取整 |
Math.ceil() | 向上取整 |
Math.max() | 最大值 |
Math.min() | 最小值 |
Math.abs() | 求绝对值 |
对Math.random()进行封装
function Random(a,b){
var res = parseInt(Math.random()*(b-a))+a;
return res;
}
生成一个[a,b)的随机整数
进制转化
除了十进制以外的进制都是字符串形式
10进制转为其他进制:
num.toString(8);//转为八进制
其他进制转为10进制:
var res = parseInt(str,n);
//str为进制字符串,n为str是什么进制的
Date对象
系统提供的构造函数
var date =new Date();
console.log(date);//当前时间
date对象在我们打印日期的时候自动调用toString方法。
格里尼治时间戳:从格林尼治的1970.1.1.0.0.0到现在的毫秒数,就是现在的时间戳
获取:
var date =new Date();
获取什么 | 格式 |
---|---|
获取年 | var year = date.getFullYear() |
获取月 | var month = date.getMonth() |
获取日 | var day = date.getDate() |
获取时 | var hour = date.getHours() |
获取分 | var minute = date.getMinutes() |
获取秒 | var seconds = date.getSeconds() |
获取毫秒 | var milisecond = date.getMiliseconds() |
获取时间戳 | var time = date.getTime() |
获取星期几 | var week = date.getDay() |
快速获取时间戳 | var res =+new Date(); |
注意:js里面的月份是0~11,输出时需要加1
设置:
get改为set就可以了
星期是不可以设置的
设置时间戳:date.setTiems(0)//格林尼治时间
在线运行js
设置·指定时间的时间戳:
var date = new Date(“2020-10-10 11:21:05”);
var date = new Date(1010,10,10,0,0,0);
通过构造方法设置时间戳:
var d = new Date(0);
获取当前代码执行时的时间戳
Data.now()
格式化输出时间日期:
date.toDateString();//只看年月日
date.toLocaleTimeString();//只看时分秒
date.toLocaleString();//都看
BOM(浏览器对象模型)
Browser Object Model
操作浏览器都是使用对象来操作的:window对象(浏览器窗口)
window有子对象,每个子对象都针对着一个操作
js实现跳转的方法
window.open():
window.location.href=“地址”
window.location.assign():
window.location:
window子对象:BOM中的顶级对象
注:window可省略
navigator(获取浏览器信息)
没什么卵用,对于学爬虫的估计有用
window.navigator.appCodeName 浏览器内核名称
window.navigator.appName浏览器名称
window.navigator.appversion:浏览器版本
window.navigator.userAgent:浏览器信息
history历史记录(你打开的网页记录)
前进:
history.back();
后退:
history.forward()
刷新:
history.go();//正数前进,负数后退,0刷新当前页面
location:地址栏
href属性:
location.href是完整的地址栏地址,赋值可以实现跳转
search属性:
获取地址栏数据
location.search
也可以赋值设置,注意是键值对形式
hash属性:
获取地址栏的锚点:
location.hash=”#bottom”
页面重定向(跳转方法):
location.assign(“地址”);
新地址替换当前地址:
location.replace();
刷新当前页面:
location.reload();
window弹出方法:
alert();
prompt();
confirm();
注意:
全局变量其实是window的属性,全局函数是window的方法,只不过平时省略了window,全局中的普通函数中的this代表的就是window对象。
window获取浏览器的尺寸
innerWidth/innerHeight 包含滚动条,相当于视窗的宽高(去掉了window)
window事件(重点):
window.onload = function(){
//页面加载完再执行
//放在同步中就是同步加载完的最后,异步中就是异步最后
}
window.onreszize = function(){
//改变窗口大小就执行
}
window.onscroll = function(){
//浏览器滚动条滚动时执行
}
定时器(重点):
分两种:每隔一段时间执行一次和延时一段时间只执行一次
第一种:
var timer =window.setInterval(function(){
console.log("123");
},1000)
清除:
clearInetrval(timer);
//形参是当前页面第几个定时器,一般为定时器返回值或者数字,会执行一次
注意:定时器一定要停,不然内存溢出
之前的内存溢出的情况(死循环,递归函数)
第二种:
window.setTimeout(function{
console.log(123);
},2000)
//也有返回值,也用来清除,同样代表第几个定时器
清除:clearTimeout();
重点:定时器的返回值
timer这个返回值其实是最后一次点击的定时器的返回值
清除定时器的时候,其实是清除了最后一个定时器,前面几次点击产生的定时器没有清除,也清除不掉了
同步操作和异步操作
同步:
上面的语句执行完,下面才会执行,排队等待
异步:
同时执行(和同步)
运行流程:
- js是单线程的(同时只能做一件事)
- 当js线程看到异步代码(栈空间),将异步交给浏览器(多线程)
- 浏览器等异步操作执行时机,时机成熟放入一各队列等待时机
- js线程如果将所有的同步执行完,会从队列中找到需要执行的代码才会执行。
总结:
定时器和延时器不一定精准(因为异步的定时器会受到同步时间的耽误)
所有异步都是在同步执行完之后执行的
异步效率高
DOM操作
dom(document object model)文档对象模型
是 操作HTML文档 的方法
之前我么使用id来表示这个标签,如:
<div id="box"></div>
box.onclick (function(){
console.log(123);
})
如何获取标签元素
操作 | 写法 |
---|---|
使用id名获取 | document.getElementById(“id名”); |
类名获取元素 | document.getElementsByClassName(“box”); |
标签名 | document.getElementsByTagName(“”); |
使用name属性获取 | document.getElementsByName(“sex”); |
CSS选择器获取元素 | document.querySelector(“选择器”),只能获取满足css选择器的第一个 |
CSS选择器选择元素的集合 | var oDiv = Document.querySelectorAll(“li”) |
注意:2,5,6条低版本IE不兼容
在编写过程中使用name作为变量名,控制台输出出现异常,不能用name作为变量名
属性操作:
操作 | 写法 |
---|---|
查 | 元素对象.getAttribute(“属性的键”) |
删 | removeAttribute(“键”) |
有则改,无则增 | setAttribute(键,值) |
特殊的: img.src和input.value
最重要的:input.checked
内容操作
元素.innerText,值为标签内容,设置标签样式是不生效的
元素.innerHTML:标签内容,值为标签生效
特殊情况:
表单元素的值:
document.querySelector(“input”).value;
设置样式:
写在行内的style标签里面的
类名操作:
标签.className=””;
这么写清空类名
滚动过的距离
垂直滚动 | document.documentElement.scrollTop |
---|---|
水平滚动 | document.documentElement.scrollLeft |
当文档声明没有时,documentElement换成body
文档声明就是<!DOCTYPE html>
兼容写法:
var t = document.documentElement.scrollTop||document.body.scrollTop
立即回到顶部:
t = 0;(就是设置document.documentElement为0,t只是存变量值的)也可以定时器不断减少慢慢变化
html基本结构获取写法
部位 | 写法 |
---|---|
html | docuemnt.documentElement |
body | document.body |
head | document.head |
title | document.title |
节点
节点:html文档的组成部分
DOM节点分(了解):
元素节点(标签),属性节点(),文本节点(文本内容),注释节点(注释)
注意:
文本节点:标签内的文本和标签之间的换行空格(为什么写移动端最好别换行空格,因为算文本,会被当做文字放大)都算文本节点
获取节点:
上面的getElementById等都是获取节点,但是这里的获取节点是依靠关系,不是直接获取
重点:
获取什么 | 怎么获取 |
---|---|
子节点 | childNodes |
子标签 | children |
父节点 | parentNode |
父标签 | parentElement |
第一个节点 | firstChild |
最后一个节点 | lastChild |
子元素中第一个标签 | firstElementChild |
子元素中最后一个标签 | lastElementChild |
获取上一个节点 | previousSibling |
获取下一个节点 | nextSilbling |
获取上一个节点元素 | previousElementSibling |
获取下一个节点元素 | nextElementSibling |
获取所有属性节点 | atributes |
节点属性
都是属性,不是方法
写法 | 作用 |
---|---|
nodeType | 获取节点类型 |
nodeName | 获取节点名 |
nodeValue | 获取节点值 |
nodeType返回值:
1表示元素节点;3表示文本节点;8表示注释节点;2表示属性节点
nodeName:
标签节点为标签名的大写形式(DIV),文本节点为(#text),注释节点为(#comment)
nodeValue:
标签为null,文本节点为文本内容,注释节点为注释内容
节点操作
操作 | 写法 |
---|---|
删除当前元素 | 元素.remove() |
新建元素 | createElement(“元素名”) |
父元素加子节点(追加在子元素最末尾) | 父元素.appendChild(oDiv) |
将子节点插到某个子节点之前 | 父元素.insertBefore(新元素 ,被插队的节点) |
替换节点 | 父元素.replace(新节点,旧节点) |
删除节点 | removeChild(被删除的子节点) |
复制节点自身 | 元素.cloneNode() |
复制节点传参true可以将里面的内容也复制
下面全程高能
获取样式:
var styles = window.getComputedStyle(元素);
styles.属性
低版本IE不兼容
兼容写法
function getStyle(){
try{
return window.getComputedStyles(ele[attr]);
}catch(e){
return ele.currentStyle[attr];//IE兼容写法
}
获取元素大小
clientWidth/Height | number型,不含边框 |
offsetHeight/Width | 含边框 |
都是只读类型,offsetHeight对于行内一直为0
获取元素的位置
offsetLeft/offsetTop | 获取到设置过定位父元素的距离{机制和定位机制一样,逐级向上寻找定位元素} |
offsetParent | 获取设置过定位的父元素,最终到body |
获取窗口大小:
window.innerHeight/Width | 含滚动条 |
document.documentElement.clientWidth/clientHeight | 不含滚动条 |
变量定义技巧
一个局部想要使用另一个局部的变量,可以将变量定义在全局
使用自调用函数传参(形成保留作用域)
for (var i = 0; i < ulis.length; i++) {
( function(i) {
ulis[i].onclick = function () {
that.className="";
that =this;
for (var j = 0; j < ulis.length; j++) {
ulis[i].className = "";
}
this.className = "active";
for (var j = 0; j < olis.length; j++) {
olis[j].className = "";
}
olis[i].className = "active";
}
})(i);
}
下拉框select>option里面的value可以
document.querySelector(“select”).value获取到
事件
为了提高浏览器检索优先级:能不用标题标签就别用
事件:用户的动作(单击,右击等)
下面是事件类型:
鼠标类
右击 | contextmenu |
鼠标按下 | mousedown |
鼠标抬起 | mouseup |
鼠标移入 | mouseover |
鼠标移出 | mouseout |
鼠标滚轮 | mousewheel(火狐里面用DOMmousescroll) |
鼠标单击 | click |
鼠标双击 | dblclick |
鼠标移动 | mousemove |
移入 | mouseenter |
移出 | mouseleave |
document.documentElement.addEventListener('DOMMouseScroll',function(){
console.log("火狐");
})
mouseover和mouseenter的区别:
相同点:没有子元素时候行为一致
mouseover用的比较多,mouseenter经常被忘掉
mouseenter不会冒泡,mouseover会
不论鼠标指针穿过被选元bai素或其子元素,都会du触发 mouseover 事件。对应mouseout
只有zhi在鼠标指针穿过被选元dao素时,才会触发 mouseenter 事件。对应mouseleave
这样的话,mouseenter子元素不会反复触发事件,否则在IE中经常有闪烁情况发生。(复制自百度)
键盘类
keypress | 键盘按下 |
keydown | 看英文,不解释 |
keyup | 按键抬起(一定要注意执行时机,获取按下那个键的键盘码不能用这个) |
区别自己百度,使用最多的是keyup
表单事件
focus | 光标点进去 |
blur | 光标(闪烁的竖杠)丢失就触发该事件 |
change | 下拉框改变就触发 |
input | 实时监听文本框的内容变化(类似百度的搜索框,IE中是propertychange) |
submit | 给submit标签绑定的(form.submit,必须要结合提交按钮使用) |
事件流
事件从开始触发到执行结束的流程(一连串的事情)
捕捉阶段:从文档由外向内找目标元素
目标阶段:找到目标文件,执行文件
冒泡阶段:执行完就要离开
事件外的元素也绑定了事件的话,冒泡阶段由内向外会触发外面的事件
事件侦听器(一个事件绑多个函数)
onClick的缺点:一个元素绑多个onClick会被覆盖
事件侦听器(兼容性):
元素.addEventListener(“click”,function(){
//可以实现多个不覆盖,但是IE不行
})
元素.attachEvent(onclick,function(){})
function bindEvent(btn,type,handler){
try{
btn.addEventListenter("type",handler);
}catch(e){
btn.attachEvent(on+"type",handler);
}
}
第二种:
function bindEvent(btn ,type,hander){
if(btn.addEventListener){
btn.addEventListener(type,hander)
}else if(btn.attachEvent)){
btn.attachEvent("on"+type,handler)
}else{
btn["on"+type] = handler
}
}
第三种:
function bindEvent(btn,type,handler){
try{
btn.addEventListener(type,handler)
}catch(err){
try{
btn.attachEvent("on"+type,handler)
}catch(e){
btn["on"+type] = handler }}}
访问对象中不存在的属性是undefined
好处:
同一类型事件可以绑定多次:
button.addEventListener(“click”,function(){
console.log("点击");
});
button.addEventListener("click",function(){
console.log("点击");
});
button.addEventListener("click",function(){
console.log("点击");
});
可以指定当前事件在捕获阶段执行
- 有第三个参数,代表是否在捕捉阶段执行(默认false表示冒泡阶段执行)
attachEvent没有第三个参数,因为IE浏览器的事件流,没有捕获阶段
事件解绑
按钮能点击,说明加载到内存中了,所以点击才能生效
点击完后还能点击,希望只执行一次,减少内存负担(所需要解绑)
null为引用类型的空,undefined为基本类型的空
btn.onclick = null;//解绑
事件监听器解绑
前提里面的函数不能是匿名函数了
var fn = function(){
console.log(123);
}
解绑:
事件源.removeEventListener("click",fn);
事件源.detachEvent("onclick",fn);
解绑又有兼容性问题——封装函数:
function unbindEvnet(ele,type,handler){
if(ele.removeEventListener){
ele.removeEventListener(type,handle)
}else if(ele.detachEvent){
ele.detachEvent(“on”+type,handle);
}else {
ele[“on”+type] = null;
}
}
阻止事件冒泡
事件时有系统调用的,不是我们手动调用的,系统将事件对象放在小括号内,存放和当前事件相关的一系列信息。
small.onclick = function(e)
{
console.log(e);
e.stopPropagation();//阻止事件冒泡
}
在IE中的兼容写法
事件对象:window.event
阻止冒泡:e.cancelBubble=true;
事件对象的简单操作
e.type | 事件类型 | 如“click”等 |
e.button | 鼠标按键信息 | 左键是0,右键是2,滚轮是1 |
e.keyCode | 键盘码 | 回车13,数字字母遵循ASCII码 |
e.shiftKey/ctrlKey/altKey | 组合键 | true或者false |
e.offsetX/Y | 光标在元素上的坐标位置 | |
e.clientX/Y | 指光标在浏览器上的位置 | 指视窗距离,不包含滚动过的距离 |
e.pageX/Y | 光标在房钱页面上的绝对位置 | 包含滚动过的距离 |
注意:键盘码低版本火狐不兼容
兼容写法:
var keycode =e.keyCode||e.which
简单的拖拽效果
var div = document.querySelector("div");
//拖拽一定先按下鼠标
div.style.position="absolute"
div.style.left="0"
div.style.top="0"
div.onmousedown = function(e){
//这里代吗都是在鼠标按下的时候执行的-----按下后再移动鼠标(鼠标移动事件)
var e = e ||window.event;
var x = e.offsetX;
var y =e.offsetY;
div.onmousemove = function(ev){
//这里写div可以将鼠标甩出来,换成 document,解绑也需要document
//鼠标移动只会执行这里的代码
var ev = ev ||window.event;
var x1 = ev.clientX;
var y1= ev.clientY;
var l = x1 - x;
var t = y1 - y;
div.style.left=l+"px";
div.style.top = t+"px";
}
}
只要鼠标在div上,触发onmosemove,外面的onmousedown就不会停止,需要解绑里面的
这时需要解绑:
div.onmouseup= function(){
div.onmousemove =null;
}
存在点击后快速离开,解绑无效果,那么把移动的事件源由div改为document(就算被甩出div范围也依旧在document范围)
拖拽限制
var div = document.querySelector("div");
//拖拽先按下鼠标
div.style.position = "absolute"
div.style.left = "0"
div.style.top = "0"
div.onmousedown = function (e) {
//这里代吗都是在鼠标按下的时候执行的-----移动鼠标-----鼠标移动事件
var e = e || window.event;
var x = e.offsetX;
var y = e.offsetY;
document.onmousemove = function (ev) {
//鼠标移动只会执行这里的代码
var ev = ev || window.event;
var x1 = ev.clientX;
var y1 = ev.clientY;
var l = x1 - x;
var t = y1 - y;
if (l < 0) {
l = 0;
}
if (t < 0) {
t = 0;
}
if (l > document.documentElement.clientWidth - div.offsetWidth) {
l = document.documentElement.clientWidth - div.offsetWidth;
}
if (t > document.documentElement.clientHeight - div.offsetHeight) {
t = document.documentElement.clientHeight - div.offsetHeight;
}
div.style.left = l + "px";
div.style.top = t + "px";
}
}
div.onmouseup = function () {
document.onmousemove = null;
}
阻止默认行为
链接的跳转,鼠标右键出现的窗口都是默认行为
- return false(事件函数最后加上)
- e.preventDefaulte e.returnValue =false(IE中)(利用事件对象来阻止)
- 将链接地址改为javascript:;
事件委托
将子元素的事件委托给父元素:例如点击事件,委托后每个子元素都可以有点击
好处:你新增的元素不需要再次单独绑定事件,十分方便
兼容写法:
target = e.target ||e.srcElement;(兼容低版本IE)
target代表的是所有子元素
<ul>
<li>11111111111</li>
<li>22222222222</li>
<li>33333333333</li>
<span>4444444444</span>
</ul>
<button>添加</button>
</body>
<script>
var ul = document.querySelector("ul");
ul.onclick = function(e){
var e = e||window.event;
var target = e.target ||e.srcElement;
if(target.nodeName=="LI"){
target.innerText="修改";//加条件限制target范围
console.log(target);
}
}
注意点:
- 拖拽的时候一定是事件嵌套,事件的事件对象是不一样的
- mouseover和mouseout是一对,mouseenter和mouseleave是一对,尽量不要混用
- 在head里面写script标签,要将代码写在这个事件内部;script在body的底部,就不要加了,加了也没用,还会覆盖前面的
- 键盘事件通常是keyup
- 获取键盘码时有些特殊键盘码无法显示,大小写有时候会混乱,不要研究为什么
offset的一个坑
没有设置小盒子的时候,光标就是大盒子上的位置,就是offsetX
一旦设置了小盒子的位置,光标立马就会在小盒子上,此时的offset就是光标在小盒子上的位置。
拖拽效果不要使用offsetX/Y
e.clientX/Y都是只读数据
正则表达式
用处:验证字符串,提取满足的字符串,替换字符串
但是还有很多用法,无法说清,不仅仅只是简单地实现表单验证
书写规则:
- 创建:
var reg =new RegExp();
var reg = /规则/; - 可接受写法
var reg = /html/;
var reg =/^html$/;
var reg = /\w$/;
var reg =/\d$/;
var reg =/^\d{5,12}$/;
符号 | 意义 |
---|---|
^ | 放在规则前表示必须是这个开头 |
$ | 放在规则结尾表示必须以这个结尾 |
{m,n} | 至少m个,至多n个 |
{n,} | 至少n位,多了不限制 |
{n} | 必须是n位 |
\w | 任意字母数字下划线 |
\d | 任意数字 |
. | 代表一个字符(注意字符是重点) |
\s | 代表一个空格 |
[a-z] | 小写a到小写z,不是固定解法,[a-zA-Z]表示任意一个字母 |
\u4e00 -\u9fa5 | 汉字,不要记,会查就行 |
+ | 至少一个 |
? | 最少0个,最多1个 |
* | {0,},任意个 |
() | 表示包起来的是一个整体,还有个用法是用来捕获变量 |
手机号:
方式一:
var str = "28715260980";
var reg =/^1[3-9][0-9]{9}$/;
var res= reg.test(str);
console.log(res);
方式2:
var str = "28715260980";
var reg =/^1[3-9]\d{9}$/;
var res= reg.test(str);
console.log(res);
qq邮箱
var reg = /^[1-9]\d{4,11}@qq\.com$/; //.有特殊意义,需要转义
var res = reg.test("1974744790@qq.com");
console.log(res);
网易邮箱
var reg = /^[a-zA-Z]\w{5,17}@(163|162)\.com$/;
var str = "shaoguoqing10@163.com";
console.log(reg.test(str));
注意:空格也算在规则内
QQ邮箱+网易邮箱:
var reg= /(^[1-9]\d{4,11}@qq\.com$)|(^[a-zA-Z]\w{5,17}@(163|162)\.com$)/;
var str = "1974744790@qq.com";
console.log(reg.test(str));
方法:
test | 正则方法,验证是否满足规则 |
search | 验证是否有满足规则的那一段,有返回下标,没有返回-1 |
exec | 正则方法,找到匹配的输出为数组的第一个元素,找不到为null |
match | 字符串方法,没有匹配返回null,和exec没什么区别 |
replace(reg,“str”) | 将str里和reg匹配的替换成js,只能替换一次,替换多次/html/g;多次忽略大小写/html/gi; |
注意:
exec(): 正则方法
在字符串中找到匹配的为输出的数组第一个元素,找不到为null
如果想要具体的某个值,可以给那个值加上(),第二个元素为小括号内的值
文件格式检测:
var reg = /^\w{1,}\.(jpg|jpeg|bmp)$/
var str ="1.jpg";
var res= reg.test(str);
console.log(res);
字符串首行去空格
var str=" ab dc ";
var reg = /(^\s+)|(\s+$)/g;
var replace = str.replace(reg,"");
console.log(replace);
ES5,ES6语法
表单验证要么都是失去焦点的验证,要么都是提交按钮的验证,不然冲突,失去焦点优先级高,提交按钮无效。
数组方法
v,i,a | 形参,名字随便起的,代表数组元素,下标,调用数组,一般第二第三个参数都是省略不写的 |
---|---|
foreach() | 只能遍历,没有返回值 |
some | 判断数组中至少有一个满足条件 |
every | 判断数组中是否所有元素都满足条件 |
find() | 查找数组中第一个满足元素的元素 |
findIndex() | 满足条件的下标(用法类似find) |
foreach:
arr.forEach(function(v,i,a){
console.log(v);
})
some:
var res = (function(v,i,a){
return v>30;
})
every:
var res = arr.every(function(v,i,a){
return v==60;
})
find:
var res = arr.find(function(){
return v>5;
})
ES6:
定义变量:
var的特点:能预解析,全局变量属于window
两个关键字定义变量: const,let
特点:不能预解析;不在window上(因为自己的作用域)
let定义的变量,创建了一个作用域
for(let i = 0; i<3;i++){
};
console.log(i);//报错,表示i未定义
let定义过的变量,不能重复定义:
好处:以前事件外循环参数需要函数传入,现在将循环参数改为let就可传入,因为let创建了个作用域
var button = document.querySelectorAll("button");
for (let i = 0; i < button.length; i++) {
button[i].onclick = function () {
console.log(i);
}
}
function f2(){
var i = 5;
for(var i=0;i<=10;i++){
}
console.log(i); // 11
var j = 5;
for(let j=0;j<=10;j++){
}
console.log(j); // 5
}
f2();
const:常量,值可被初始化,但不能赋值。也不在window上,也不能预解析,不希望改变的量就用const来定义
箭头函数
形参列表只有一个参数,小括号可以省略
大括号内只有一行代码,省略大括号
若一行代码内只有return关键字,return关键字可以省略
let fn = res=> res;
let fn= function (res){
return res;
}
函数默认值
function(a,b=10){
console.log(a,b);//b不传值就是10,传值10被覆盖
}
如果a有默认值,不想改变,可以实参传undefined
…运算符
将多个形参整合成一个数组:
let fn = (…arr)=>{
console.log(arr);
}
fn(10,20,30);
将数组拆分成多个值
let fn = (a,b,c)=>a+b+c;
let arr =[1,2,3];
const res = fn(…arr);
console.log(res);可以将对象拆分成多个键值对
var ch ={
naem:"翠花",age:12}
var zz = {
name="李四",age:14,wife:{
...ch}}
这里注意加载顺序
总结:实参分解形参合并,对象直接拆
对象
键与值相同可以只写一个:
var name=”张三”;
var age = 12;
var obj = {name,age}
方法也可以简写:
var ff ={
eat:function(){
console.log("eat");}};
改写:
var ff = {
eat(){
console.log("eat")}}
调用:
obj.eat();
解构赋值
快速将对象或者数组中的值赋给多个变量var name=”张三”;
var age = 12;
var zs ={name,
age,
eat(){
console.log("吃");},
sport(){
console.log("运动");},
wife:{
name:"翠花",age:12}
}
var {name.age,eat,sport}=zs;
console.log(name,age,eat,sport);
注意变量名和键名需要保持一致
取别名:
var {name:n,age:a,eat:e,sports:s}=zs;
console.log(n,a,e,s);
套娃操作:
var {wife}=zs;
var name={wife};
简化套娃操作:var {wife:{name:n}} = zs;
数组结构:
var arr = [1,2,3,4];
var[a,b,c] =arr;
var [a] =arr;
//只想获取c
var [_,_,c]=arr;
//数组的多重解构(套娃)
var arr =[
"马蓉",
"王宝强",
[
"贾乃亮",
"PGOne",
"李小璐"
]
]
var [_,_,[a]] = arr;
字符串
字符串是不支持多行定义的,使用模板字符串就可以了(反引号)
var name="张三";
var str=`
姓名:${
name}
`;
name+str;
字符串方法
返回值是boolean型:
startsWidth:字符串是否以某个文字开头;
字符串是否以某个文字结尾;
includes:判断字符串是否有某个字符(split炸要是成三段就是含有这个字符)
具体查看数据类型:
Object.portotype.toString.call(对象名);
伪数组
是对象,像数组能遍历,但是不能用数组方法
之前getElementByTagNames等获取到的就是。
特点:
- 键是数字,有一个键为length,值为元素个数
- 数组的length属性颜色淡,但是可以调用
- 对象没有length,但是伪数组有
- 伪数组的键其实是字符串,也有引号
arr[“0”];
自创伪数组:
var weishuzu={
0:"第一个",
1:"第二个",
2:"假设这是极限",
length:3
}
for(let i = 0;i<wieshuzu.length;i++{
console.log(weishuzu[i]);
}
伪数组转为数组
var arrv = Array.prototype.slice.call(obj);
伪数组的遍历
for(var i = 0 ; i <obj.length;i++){
console.log(obj[i});
}
函数中的关键字:arguments
function fn(){
console.log(arguments);
}
fn(1,2,3);arguments是存放实参的伪数组
this关键字代表什么
所在范围 | 代表 |
---|---|
全局,普通函数 | window |
定时器中 | window |
自调用函数 | window |
对象方法中 | 当前对象 |
箭头函数 | 自己所处作用域的this |
用对象调用的方法 | this代表这个对象 |
事件 | 代表事件源 |
所有用对象调用的方法,this代表这个对象
函数定义不知道this是什么,只有调用的时候才知道。
点击调用函数的时候,相当于调用了document的onclick方法
for(var i=0;i<imgs.length;i++){
imgs[i].onclick = function(){
var path = this.src; //利用this获取变化的i值
document.body.style.backgroundImage = 'url('+path+')';
document.body.style.backgroundRepeat = 'no-repeat';
document.body.style.backgroundSize = '100% 100%';
box.style.height = 0;
}
}
点击跳转至推荐文章
如何改变this
将fn中的this改为arr
1. call方法:被函数调用的方法
fn.call(arr)//相当于函数的调用
本质:调用函数被改成函数.call()
调用call之后函数就被调用了
var obj = {
fn(a,b){
console.log(a,b);}
}
var arr =[1,2,3];
obj.fn.call(arr,1,2);
相当于arr调用了obj里面的fn方法,第一个参数后面的都是obj.fn需要的参数
感觉讲的非常详细,可以点这个链接去看看
undefined+undefined = NaN
apply:
也是调用函数,和call差不多,也能改变this
函数的实参会组成数组传入
var arr =[1,2,3];
var obj ={
name:"张三",
fn(a,b,c){
console.log(c)
}
}
obj.fn.apply(arr,[1,2,3]);
bind:
复制函数,参数相当于复制出函数里面的this
点击跳转至推荐文章
var obj = {
name: "张三",
fn(a,b){
console.log(this);
console.log(a+b);
}
}
var arr = [1,2,3]
//下面都是实现相同功能的不同写法,bind返回的是复制的函数
// obj.fn(1,2)
// obj.fn.call(arr,1,2)
// obj.fn.apply(arr,arr)
//obj.fn.bind(arr,...arr)();
下一篇:DOM高级-运动
注:全篇为个人笔记,仅供参考,如有错误请指出
还没有评论,来说两句吧...