JavaScript学习笔记 内容较多较杂,适合稍有基础偏进阶
JavaScript学习笔记
前言:
个人的JavaScript学习笔记,方便自己忘了东西回来复习
小知识
- DOM 属性不总是字符串类型的(大部分是字符串类型),input.checked是布尔型,style是对象。
- 特性(Attributes)可以转为属性(properties),属性不能转为特性。
- HTML特性总是不分大小写,并且他们大多是字符串类型。
- 用JavaScript渲染html的时候,当在后面想除去这个修改,比如说背景颜色呀,字体颜色呀这种,不要用delete,直接置空就好,例如:
document.body.style.background=""
就恢复原样相当于没修改了 - 关于对象,对象有属性、方法,有两种方式访问他们。一种是
objectName.propertyName
另一种是objectName["propertyName"]
,对象里可以有多个属性,但需要注意的是,对象语法里不能用“=”而要用“:”,例如:
var person={
firstname:"John",
lastname:"Doe",
id:5566
};
特性工具
- elem.hasAttribute(name) — 检查特性是否存在。
- elem.getAttribute(name) — 获取这个特性值。
- elem.setAttribute(name, value) — 设置这个特性值。
- elem.removeAttribute(name) — 移除这个特性。
浏览器事件简介
(应该放在DOM版块里,但主要应用于JavaScript,所以放在这里总结)
鼠标事件:
- click —— 当鼠标点击一个元素时(触摸屏设备会在点击时生成)。
- contextmenu —— 当鼠标右键点击一个元素时。
- mouseover / mouseout —— 当鼠标指针移入/离开一个元素时。
- mousedown / mouseup —— 当在元素上按下/释放鼠标按钮时。
- mousemove —— 当鼠标移动时。
键盘事件:
- keydown 和 keyup —— 当按下和松开一个按键时。
表单(form)元素事件:
- submit —— 当访问者提交了一个
<form>
时。 - focus —— 当访问者聚焦于一个元素时,例如聚焦于一个
<input>
。
Document 事件:
- DOMContentLoaded —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时。
CSS 事件:
- transitionend —— 当一个 CSS 动画完成时。
一些DOM牛逼函数
- prompt
用法:prompt() 函数显示一条消息,并等待输入。第二个参数是默认的输入值,如果用户没有输入值,就会返回这个值。该函数返回用户输入的值或默认值。
prompt(text,defaultinput)
(单独用可能只是给变量提供一个字符串,但如果结合特性,就能起到不错的渲染效果)例如:
document.body.style.backgroundColor = prompt('background color?', 'green');
点确定,网页的body部分变为绿色,点否,无事发生。
- location(不能算是函数,其实是对象,这里介绍它是结合window.location)
用法:Location 对象包含有关当前 URL 的信息。
Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问。
如果只是location.href,那就是当前页面位置信息,但如果使用window.location.href=“一个链接”
就实现了类似于HTML里的<a></a>
既然可以用a标签,为什么使用window.location呢?因为放进函数里,可以实现先执行命令再跳转,例如:
function fun()
{
document.body.style.background="red";
setTimeout(()=>document.body.style.background="",3000)
window.location.href="https://www.php.cn/";
}
代码比较简单,这里就不多解释了
- confirm
用法:confirm函数用于提供确认功能,它首先显示给定的message参数所包含的信息,并提供两个可选择的回答“ok”和“cancel”,然后等待用户选择其中的一个。
我用的比较多的就是配合if使用,点击确定->返回ok->执行if语句
例如:
if(confirm("go to baidu?")){
location.href="https://baidu.com";
}
JavaScript讲究的就是个“动”,尤其是DOM,注重与用户的交互(个人拙见,后期学习发现有问题还会调整)
- getComputedStyle
用法:读取css样式,style只对style有用,无法读取他们
语法:getComputedStyle(element, [pseudo])
element
需要被读取样式值的元素。
pseudo
伪元素(如果需要),例如 ::before。空字符串或无参数则意味着元素本身。
结果是一个具有样式属性的对象,像 elem.style,但现在对于所有的 CSS 类来说都是如此。
例如:
<head>
<style> body { color: red; margin: 5px } </style>
</head>
<body>
<script>
let computedStyle = getComputedStyle(document.body);
// 现在我们可以读取它的 margin 和 color 了
alert( computedStyle.marginTop ); // 5px
alert( computedStyle.color ); // rgb(255, 0, 0)
</script>
</body>
一、创建新变量
1.var
2.let
3.const
前两者其实差不多,var的作用域被规定为一个函数作用域,而let则被规定为块作用域.因此let的作用范围会比var稍小一点,不过平时体现不明显,只有循环的时候会有体现。var定义的变量在整个函数都有被定义(也就是循环外也有),而let只在循环内有。还有就是被let声明的变量不会作为全局对象window的属性,而被var声明的变量可以。
那么什么时候用let什么时候用var呢?其实都可以…只是let对全局的污染会小一点,目前我还没发现有什么差别
var允许在同一作用域中声明同名的变量,而let不可以。
const又和let差不多,const和let都是在声明的块作用域中有效,不过需要注意的是let的申明是可以被改变的,而const不行,它必须立刻被初始化
const PI=3.141592653589;
PI=3.14;
像这样就会出错,只能保留第一行。
二、创建新元素/属性节点
1.appendChild(a)
2.insertBefore(a,b)
3.setAttributeNode(a)
前两个创建新元素节点,第三个创建新属性节点,用法一样,就不重复说明了
第一个就是添加元素(a)到尾部,第二个就是添加元素(a)到后一个参数(b)的前面。放一段代码便于理解。
对了,两个都需要在用之前告诉他们在哪个区域进行增加,比如下面代码的这一行,就是告诉他们要在”div1“里增加,还是比较好懂的。
下面代码里的“creat什么什么”的用法,我在下面讲
element.appendChild(para);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="div1">
<p id="p1">这是一个段落</p>
<p id="p2">这是另外一个段落</p>
</div>
<script>
var para=document.createElement("p");
var node=document.createTextNode("这是一个新的段落");
para.appendChild(node);
var element=document.getElementById("div1");
element.appendChild(para);
//添加新元素到尾部
</script>
</body>
</html>
这段代码的效果是这样的:
这是一个段落
这是另外一个段落
这是一个新的段落
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para=document.createElement("p");
var node=document.createTextNode("这是一个新的段落");
para.appendChild(node);
var element=document.getElementById("div1");
var child=document.getElementById("p1");
element.insertBefore(para,child);
//添加元素到头部
</script>
</body>
</html>
这段代码的效果是这样的:
这是一个新的段落
这是一个段落。
这是另外一个段落。
三、creat三兄弟
1.createElement(”元素“)
这个用法比较简单也比较好理解,就是在引号里面放元素就好,比如:p、button…
2.creatTextNode(”文本“)
这个就是创建一个文本节点,一般是和1一起使用,下面是例子:
var para=document.createElement("p");//A
var node=document.createTextNode("这是一个新的段落");//B
para.appendChild(node);//C
A:申明一个变量para,它的属性是p(现在没有任何内容)
B:申明一个变量node,它的文本节点是双引号里的内容
C:结合“二、创建新元素节点”所讲内容,“para”:告诉appendChild要在“para”这个区域加东西。括号里的“node”,则是把node加在para上,简单来说就是把文本节点放在这个元素里
3.creatAttribute(“属性”)
这个就是给原本的内容加属性,换颜色什么的,这个函数我不知道常用不,但挺难理解的比起前两个。所以这个我先放代码再结合代码讲
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
.democlass{
color:red;
}
</style>
</head>
<body>
<h1>Hello World</h1>
<p id="demo">单击按钮来创建一个“类”属性值“democlass”插入到上面的H1元素。</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction(){
var h1=document.getElementsByTagName("H1")[0];
var att=document.createAttribute("class");
att.value="democlass";
h1.setAttributeNode(att);
}
</script>
</body>
</body>
</html>
中间的getElementsByTagName就和getElementsById差不多,这个我们后面再说。
先看最上面css那里,我们是用的.democlass,也就是说这个选择器是class选择器(关于css选择器可以在我的另一个文章里看,很短),也就是class属性,因此createAttribute后加的是(“class”)。后面几行其实和上面差不多,只不过因为我们加的不是元素而是属性,所以不能用appen或者insert,而是setAttributeNode
如果我们修改一下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style type="text/css">
#democlass{
color:red;
}
</style>
</head>
<body>
<h1>Hello World</h1>
<p id="demo">单击按钮来创建一个“类”属性值“democlass”插入到上面的H1元素。</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction(){
var h1=document.getElementsByTagName("H1")[0];
var att=document.createAttribute("id");
att.value="democlass";
h1.setAttributeNode(att);
}
</script>
</body>
</html>
把css里的“.”换成“#”,下面的createAttribute就要跟(“id”)
att.value="democlass";
h1.setAttributeNode(att);
这句话很好理解,就是让att得到名为democlass的属性,再把它插入给h1
四、搜索
这是很重要的部分,因为容易搞混或者搞忘,重点重点!!
1.getElement*
它最多最常用的就是getElementBy*,比如:getElementById、getElementByTagName、getElementsByClassName、getElementsByName
- getElementById
- getElementByTagName
- getElementByName
- getElementByClassName
通过它的名字也可以看出它的用法,分别是通过id找、通过元素类型找、通过class属性找、直接通过name找(很少用)
因为ById的用法比较常见,我这里就不多说了,说一下ByTagName和ByClassName
首先说ByClassName:
<form name="my-form">
<div class="article">Article</div>
<div class="long article">Long article</div>
</form>
<script>
// 按 name 特性查找
let form = document.getElementsByName('my-form')[0];
// 在 form 中按 class 查找
let articles = form.getElementsByClassName('article');
alert(articles.length); // 2, 找到两个属性名里有“artical”
</script>
得到的结果是2,因为有两个clss里都找到了“artical”。
那么为什么
let form = document.getElementsByName('my-form')[0];
这里要用[0]呢,因为getElementsBy* 都是返回的集合,而不是元素也不是数组,但是可以使用调用数组的方法,[0]就是第一个,依次类推。
getElementsByTagName其实也是同理,同样是返回集合,所以在上一节同样是getElementsByTagName(“h1”)[0],意思是找到第一个h1属性。
2.querySelector*
这个比上面的少,就两个
- querySelector(css)
- querySelectorAll(css)
第一个是返回找到的第一个,第二个是返回找的到所有的一个集合
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2 class="example">class="example" 的标题</h2>
<p class="example"> class="example" 的段落。</p>
<p>点击按钮为第一个 class="example" 的元素添加背景颜色。</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction() {
document.querySelector(".example").style.backgroundColor = "red";
}
</script>
</body>
</html>
我们有三个example,但是querySelector(".example")只返回第一个。
这里注意一下,因为是querySelector(css),所以括号里基本上是“.”或者“#”这两种,当然我指的是用“class和id”取了名字的,如果用的是元素类型,比如p、h1这种就不需要
querySelectorAll差不多,只是是个集合而已,就不多说了。
两个方式最大的不同
getElementsBy*是返回一个实时的集合,而querySelectorAll是返回一个静态的集合,放两段代码
<div>First div</div>
<script>
let divs = document.getElementsByTagName('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 2
</script>
可以看到,第一个script里长度只有1,但是在两个script中间加一个div,它的长度还是会被计算进去
<div>First div</div>
<script>
let divs = document.querySelectorAll('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 1
</script>
而这里当我调用document.querySelectorAll(‘div’)后,它只会执行到我调用这里,当执行后我的集合就被定死了,不会改变了,所以就算我再加div,我的长度也还是1。
五、插入
- 元素或文本插入方法:
- node.append(…nodes or strings) —— 在 node 末尾 插入节点或字符串
- node.prepend(…nodes or strings) —— 在 node 开头 插入节点或字符串,
- node.before(…nodes or strings) —— 在 node 前面 插入节点或字符串,
- node.after(…nodes or strings) —— 在 node 后面 插入节点或字符串,
- node.replaceWith(…nodes or strings) —— 将 node 替换为给定的节点或字符串。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ol id="ol">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
ol.before('brfore');
ol.after('after');
let liFirst=document.createElement('li');
liFirst.innerHTML='prepend';
ol.prepend(liFirst);
let liLast=document.createElement('li');
liLast.innerHTML='append';
ol.append(liLast);
</script>
</body>
</html>
完成插入后,相当于:
before
<ol>
<li>prepend<li>
<li>append<li>
<li>0<li>
<li>1<li>
<li>2<li>
<ol>
after
- 插入HTML
- insertAdjacentHTML/Text/Element
使用格式:elem.insertAdjacentHTML(where, html)。
该方法的第一个参数是代码字(code word),指定相对于 elem 的插入位置。必须为以下之一:
- “beforebegin” — 将 html 插入到 elem 前插入,
- “afterbegin” — 将 html 插入到 elem 开头,
- “beforeend” — 将 html 插入到 elem 末尾,
- “afterend” — 将 html 插入到 elem 后。
例如:
<div id="div"></div>
<script>
div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
div.insertAdjacentHTML('afterend', '<p>Bye</p>');
</script>
产生的效果是:
<p>Hello</p>
<div id="div"></div>
<p>Bye</p>
- 节点移除
node.remove()
挺简单的,就不多论述了 - 克隆节点
elem.cloneNode(true):
克隆 — 具有所有特性(attribute)和子元素。如果我们调用
elem.cloneNode(false):
克隆不具有子元素
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert" id="div">
<strong>Hi there!</strong> You've read an important message.
</div>
<script>
let div2 = div.cloneNode(true); // 克隆消息
div2.querySelector('strong').innerHTML = 'Bye there!'; // 修改克隆
div.after(div2); // 在已有的 div 后显示克隆
</script>
六、数组操作方法
添加:
unshift() 在第一位新增一或多个数据,返回长度
var a=['a','b','c'];
var len=a.unshift('o');
console.log(len);//4
console.log(a);//o,a,b,c
push() 在最后一位新增一或多个数据,返回长度
var a=['a','b','c'];
var len=a.push('o');
console.log(len);//4
console.log(a);//a,b,c,o
删除:
pop() 删除最后一位,并返回删除的数据
var a=['a','b','c'];
var b=a.pop();
console.log(b);//c
console.log(a);//a,b
shift() 删除第一位,并返回删除的数据
var a=['a','b','c'];
var b=a.shift();
console.log(b);//a
console.log(a);//b,c
合并:
concat() 合并数组,并返回合并之后的数据
var a=['a','b','c'];
var b=['d','e'];
var c=a.concat(b);
console.log(c);//a,b,c,d,e;
转换:
join() 根据指定分隔符将数组中的所有元素放入一个字符串,并返回这个字符串。
var a=['a','b','c'];
console.log(a.join());//a,b,c;
console.log(a.join("-"))//a-b-c;
console.log(a);//[a,b,c]原数组不会改变
倒置:
reverse() 颠倒数组中元素的顺序。
var a=['a','b','c'];
console.log(a.reverse());//c,b,a
console.log(a);//c,b,a 原数组也会被改变
截取:
slice() 可从已有的数组中返回选定的元素。该方法接收两个参数slice(start,end),strat为必选,表示从第几位开始;end为可选,表示到第几位结束(不包含end位),省略表示到最后一位;start和end都可以为负数,负数时表示从最后一位开始算起,如-1表示最后一位。
var a=['a','b','c','d'];
console.log(a.slice(1,3));//b,c
console.log(a.slice(1));//b,c,d
console.log(a.slice(-4,-2));//a,b
console.log(a.slice(-3));//b,c,d
console.log(a);//a,b,c,d 原数组不改变
排序:
sort() 对数组中的元素进行排序,默认是升序。
var a=[5,8,1,3,2,9,4,6,6];
console.log(a.sort());//1,2,3,4,5,6,6,8,9
console.log(a);//1,2,3,4,5,6,6,8,9 原数组改变
但是在排序前,会先调用数组的toString方法,将每个元素都转成字符之后,再进行排序,此时会按照字符串的排序,逐位比较,进行排序。
var a=[7,1000,338,28456];
console.log(a.sort());//1000, 28456, 338, 7
如果需要按照数值排序,需要传参。
sort(callback) callback为回调函数该函数应该具有两个参数,比较这两个参数,然后返回一个用于说明这两个值的相对顺序的数字(a-b)。其返回值如下:
若 a 小于 b,返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
var a=[7,1000,338,28456];
console.log(a.sort(fn));//7,338,1000,28456
function fn(a,b){
return a-b;
}
添加,删除,替换
splice() 向数组中添加,或从数组删除,或替换数组中的元素,然后返回被删除/替换的元素
1. 不传参:无操作
var a=['a','b','c','d','e'];
console.log(a.splice());//[]
console.log(a);//['a','b','c','d','e']
- 只传入start:表示从索引为start的数据开始删除,直到数组结束
```js
var a=['a','b','c','d','e'];
console.log(a.splice(2));//['c','d','e']
console.log(a);//['a','b'] 原数组改变
```
- 传入start和num:表示从索引为start的数据开始删除,删除num个
```js
var a=['a','b','c','d','e'];
console.log(a.splice(2,2));//['c','d']
console.log(a);//['a','b','e'] 原数组改变
```
- 传入更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
```js
var a=['a','b','c','d','e'];
console.log(a.splice(2,2,'g','f'));//['c','d']
console.log(a);//['a','b','g','f','e'] 原数组改变
```
-
传入更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
var a=['a','b','c','d','e']; console.log(a.splice(2,0,'g','f'));//[] console.log(a);//['a','b','g','f','c','d','e'] 原数组改变
转换:
toString() 转换成字符串,类似于没有参数的join()。该方法会在数据发生隐式类型转换时被自动调用,如果手动调用,就是直接转为字符串。var a=['a','b','c','d','e']; console.log(a.toString());//a,b,c,d,e console.log(a);//['a','b','c','d','e'] 原数组不改变
查询:
indexOf() 根据指定的数据,从左向右,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变.
参数: indexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1var a=['h','e','l','l','o']; console.log(a.indexOf('l'));//2 console.log(a.indexOf('l',2));//3 console.log(a.indexOf('k'))//-1 console.log(a.indexOf("l",-3));//2
lastIndexOf() 根据指定的数据,从右向左,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。
参数: lastIndexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1var arr = ["h","e","l","l","o"]; console.log(a.lastIndexOf("l"));//3 console.log(a.lastIndexOf("l",3));//3 console.log(a.lastIndexOf("l",1));//-1 console.log(a.lastIndexOf("l",-3));//2 console.log(a.lastIndexOf("l",-4));//-1
遍历:
forEach() 用来遍历数组,该方法没有返回值。var a=['a','b','c']; var b=[]; a.forEach(function(item){ b.push(item); }) console.log(b);//a,b,c;
map() 1.同forEach功能;2.map的回调函数会将执行结果返回,最后map将所有回调函数的返回值组成新数组返回。
var a = [2,3,4,5]; var b = a.map(function(x) { return x - 1; }); console.log(a);//2,3,4,5 console.log(b);//1,2,3,4
some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。与every相反,只要有一个回调函数的返回值都为true,some的返回值为true,所有回调函数的返回值为false,some的返回值才为false
function fn(data){ return data>10; } var a=[2,4,5,8,10,12]; var b=[1,2,3,4,5]; console.log(a.some(fn));//true console.log(b.some(fn));//false
every() 判断数组中每一项是否都满足条件,只有所有项都满足条件,才会返回true。当回调函数的返回值为true时,类似于forEach的功能,遍历所有;如果为false,那么停止执行,后面的数据不再遍历,停在第一个返回false的位置。当每个回调函数的返回值都为true时,every的返回值为true,只要有一个回调函数的返回值为false,every的返回值都为false
function fn(data){ return data>10; } var a=[2,4,5,8,10,12]; var b=[1,2,3,4,5]; var c=[11,12,13,14]; console.log(a.every(fn));//false console.log(b.every(fn));//false console.log(c.every(fn));//true