Javascript 作为一门强大的脚本语言,主要是用于前端开发。相比于其他脚本语言来讲,是有一定难度,所以要想学好它就必须下足功夫。对于如何学好一门语言想必大家都有各自的一套办法,但是方法再五花八门,有一点一定是相同的——那就是打好基础!下面来介绍五个重要的基础知识:
- js 循环
- js 函数
- dom 操作
- classList 对象的使用
- dataset 对象的使用
一,js 循环
循环:只要满足条件,将不断的执行重复的语句
1,while
入口判断型,循环前先判断括号内条件符不符合要求,如果符合要求则执行代码块中语句
- 语法
while (condition) { //do something... }
- 源码
//初始化执行条件
let i = 0;
//因为i=0不符合要求,大括号中代码不执行
while (i > 10) {
console.log(i);
i--;
}
// i<10符合要求,括号内代码执行
while (i < 10) {
console.log(i); // 0,1,2,3,4,5,6,7,8,9
i++;
}
2,do-while
出口判断型。不管条件如何,至少执行一次循环体。
- 语法
do { //do something... } while (condition);
- 源码
//初始化执行条件
let j = 0;
// 条件不符合,只执行一次大括号内代码
do {
console.log(j); // 0
} while (j > 10);
console.log("-------------------");
//条件符合,正常执行代码
do {
console.log(j);
j++;
} while (j < 10); // 0,1,2,3,4,5,6,7,8,9
3,for
计数型: 可视为 while 的简化版本
执行流程是: a,初始化执行条件;b,判断条件是否符合要求.符合继续往下执行,不符合立即停止执行;c,执行完计数+1
- 语法
for (let i = 0; i < num; i++) {//do something...}
- 源码
// 不符合条件不执行
// for (let k = 0; k > 10; k--) {
// console.log(k);
// }
//可以再括号内和括号外初始化执行条件
// let k = 0;
// for (k; k < 10; k++) {
for (let k = 0; k < 10; k++) {
console.log(k); //0,1,2,3,4,5,6,7,8,9
}
4,for in
遍历对象中的允许遍历的属性(枚举的属性)
也可以用来遍历数组,但是一般不用,遍历数组可以用for of
- 语法
for (let prop in object) { //do something... }
- 源码
const obj = {
name: "zhangshan",
age: 20,
sex: "male",
};
for (let prop in obj) {
// console.log(prop);
//console.log(obj.prop); //undefined (这里面用`.`获取属性名是不行的,必须用`[]`)
console.log("属性:", prop, " 值:", obj[prop]);
}
console.log("-------------------");
//遍历数组
const arr = ["a", "b", "c"];
for (let index in arr) {
// console.log(prop);
//console.log(obj.prop); //undefined (这里面用`.`获取属性名是不行的,必须用`[]`)
console.log("下标:", index, " 值:", arr[index]);
}
- 结果
5,forEach|map
用于遍历数组
注意:不能直接遍历对象,会报错
- 语法
Array.forEach(function (value, index, array) { //do something... });
value:遍历的当前元素
index:当前索引
array:正在操作的数组
- 源码
// 不能直接遍历对象
// const user = {
// name: "zhangshan",
// age: 20,
// sex: "male",
// };
//报错 Uncaught TypeError: user.forEach is not a function
// user.forEach((value, key, user) => {
// console.log("属性:", key, "值:", value, "对象:", array);
// });
//遍历数组
const array = [1, 2, 3, 4];
array.forEach((value, index, array) => {
console.log("键:", index, "值:", value, "数组:", array);
});
- 结果
6,for of
es6 后用于遍历数组
只能用于遍历数组
- 语法
for (const iterator of object) { //do something... }
- 源码
const fruits = ["apple", "peach", "pear", "banana"];
for (let fruit of fruits) {
console.log("水果:", fruit);
}
- 结果
7,循环汇总
forEach 和 map 的比较
- 相同点
forEach 和 map 用法类似,都可以遍历到数组的每个元素,而且参数一致- 不同点
forEach() 方法对数组的每个元素执行一次提供的函数。总是返回 undefined
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。返回值是一个新的数组
- 源码
// forEach
const retForEach = array.forEach((v) => {
return v * 10;
});
console.log(retForEach); //undefined
// map
const retMap = array.map((v) => {
return v * 10;
});
console.log(retMap); // [10, 20, 30, 40] (返回一个新的数组)
- 结果
“for 系”循环的作用场合
- for in 总是得到对像的属性名,数组、字符串的下标
- for of 和 forEach 一样,是直接得到数组的值(forEach 也可以从函数第二个参数获得数组的键,但很少用)
- for of 不能用于对象
循环参考博客:https://www.cnblogs.com/amujoe/p/8875053.html
二,js 函数
把一段需要重复使用的代码,用 function 语法包起来,方便重复调用,分块和简化代码
JavaScript 函数是被设计为执行特定任务的代码块。
JavaScript 函数会在某代码调用它时被执行。
1,函数
- 函数的声明和调用
声明一个函数有三种方式:函数名,函数表达式,箭头函数
//最常见的方式
function foo(val) {
//do something...
}
//函数表达式(匿名函数)
const foo = function (val) {
//do something...
};
//箭头函数
() => {
//do something...
};
函数的调用通常都是一个函数名加一个()
,但是匿名函数可以(function(){})()
这种方式调用。
//调用
foo();
//函数表达式的调用(匿名函数)
foo();
//箭头函数
(() => {
console.log("这是箭头函数的调用");
})();
- 函数的参数
形参
全称为”形式参数” 由于它不是实际存在变量,所以又称虚拟变量。是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
.在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值。
实参
全称为”实际参数”是在调用时传递给函数的参数。
实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
// 函数传参
function bar(val) {
console.log(val);
}
let name = "小明";
bar(name);
// 输出:小明
代码段 function bar(val)
中的 val
是形参。函数调用表达式 bar(name)
中的 name
是实参。
默认参数
默认参数指的是当函数调用中省略了实参时自动使用的一个值
// 默认参数
function barz(val1, val2 = "world") {
console.log(val1, val2, "!");
}
barz("hello");
//输出 hello world !(调用时省略了一个参数)
barz("hello", "小明");
//输出 hello 小明 !
剩余参数(重点)
使用剩余运算符,
...rest
,...rest
将剩余参数全部打包到一个数组变量中
一般情况,当我们要向函数传多个参数时,要一个一个写进去。有时候还会遇到参数个数改变的情况
function show(val1, val2, val3, val4, val5) {
console.log("我喜欢的水果是:", val1, val2, val3, val4, val5, "!");
}
show("apple", "orange", "peach", "bannan", "watermelon");
// 输出:我喜欢的水果是: apple orange peach bannan watermelon !
这样写非常费力,而且代码也不美观,没逼格
这时候就可以用...rest
了。
//...rest
function show(val1, ...val2) {
let str = "我喜欢的水果是:";
for (let v of val2) {
str += " " + v;
}
console.log(str + "!");
}
show("apple", "orange", "peach", "bannan", "watermelon");
// 输出:我喜欢的水果是: apple orange peach bannan watermelon !
show("apple", "orange");
// 输出:我喜欢的水果是: apple orange !
这样是不是代码逼格瞬间提升了几个档次?
不仅如此,我们还可以传随意个数的实参都没问题。
...rest
不仅美观还实用,真的太好了。
与...rest
类似的用法还有...spread
展开运算符。
展开运算符(重点)
...spread
将数组展开成一个个独立的单元.
...rest
, ...spread
语法的形式完全一样,怎么区别....name
用在函数的参数中就是将所有参数打包到一个数组...name
用在函数的调用参数就是展开操作
function info(name, tel, email, sex) {
console.log(name, tel, email, sex);
}
const user = ["zhangshan", "13888888888", "zhangshan@qq.com", "male"];
// 不用展开形式
info(user);
// 输出:(4) ["zhangshan", "13888888888", "zhangshan@qq.com", "male"] undefined undefined undefined
// 展开形式
info(...user);
// 输出: zhangshan 13888888888 zhangshan@qq.com male
如图
2,匿名函数
匿名函数顾名思义指的是没有名字的函数,在实际开发中使用的频率非常高!也是学好 JS 的重点.
函数表达式声明一个匿名函数
//匿名函数的声明
const callback = function () {
//输出函数名字
console.log(callback.name);
};
正常调用
// 调用
callback();
有时我们不用函数表达式也可以声明一个匿名函数
(function(){})
调用
(function(){})()
匿名函数多用作回调函数
// 用于回调
// 每5秒输出当前的时间
setInterval(function () {
console.log(new Date().toLocaleTimeString());
}, 5000);
如图
3,箭头函数
ES6 标准新增了一种新的函数:Arrow Function(箭头函数)
为什么叫 Arrow Function?因为它的定义用的就是一个箭头
箭头函数相当于匿名函数,并且简化了函数定义。
声明一个箭头函数
x => x+2
上面的函数相当于
function (x) {
return 2 * x;
}
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,一行代码,连{ ... }
和return
都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }
和return
(x) => {
if (x > 0) {
return x * x;
} else {
return -x * x;
}
};
如果参数不是一个,就需要用括号()括起来
// 两个参数:
(x, y) => x * x + y * y
// 无参数:
() => 3.14
// 剩余参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
注意:箭头函数中没有自己的 this
箭头函数博文参考:https://www.cnblogs.com/lfxiao/p/9360238.html
三,dom 操作
1,获取 DOM 元素
在开始之前我们应该了解一个新的概念就是:类数组。
什么是类数组?
就是一个拥有数组的length
属性和从 0 开始递增的索引
,但不能直接使用数组所具有的方法的一个对象。
其本质还是对象
,它的原型是Object
而非Array
。
- 根据标签名获取 dom 对象
语法: document.getElementsByTagName(tagName)
返回: 根据标签名所匹配到的所有元素的名为HTMLCollection
的类数组。
html 源码
<ul>
<li class="get-dom">item1</li>
<li class="get-dom">item2</li>
<li class="get-dom" name="third">item3</li>
<li class="get-dom">item4</li>
<li class="get-dom" id="item5">item5</li>
<li class="get-dom">item6</li>
<li class="get-dom">item7</li>
<li class="get-dom">item8</li>
</ul>
js 源码
//根据tag获取doms
// 获取ul
let ul = document.getElementsByTagName("ul");
console.log(ul);
console.log(ul[0]);
console.log("----------------------");
//获取li
let li = window.document.getElementsByTagName("li");
console.log(li);
console.log(li[2]);
console.log(li[2].innerHTML);
console.log("----------------------");
结果
注意:它返回的是一个多个数的
Collection
,而不是单个元素。因此,要得到单个元素得用获取数组元素的办法——用[索引]
。
- 根据元素
id
属性获取 dom 对象
语法: document.getElementById(id属性名)
返回: 根据id
属性名所匹配到的单个元素对象。
js 源码
// 根据id获取doms
// 括号内是id名而不是id选择器(#item5)
let byId = document.getElementById("item5");
// 返回单个的值,非类数组
console.log(byId);
console.log(byId.innerHTML);
结果
注意:括号内是 id 名而不是 id 选择器(#item5)。
- 根据元素
类名
获取 dom 对象
语法: document.getElementsByClassName(类名)
返回: 根据元素类名
所匹配到的所有元素的名为HTMLCollection
的类数组。
js 源码
//根据类名获取元素,返回类数组
let byClassName = document.getElementsByClassName("get-dom");
console.log(byClassName);
console.log(byClassName[1]);
console.log(byClassName[1].innerHTML);
结果
注意:返回的是一个类数组。
- 根据元素
name
属性名获取 dom 对象
语法: document.getElementsByName(name属性名)
返回: 根据元素name
属性名所匹配到的所有元素的名为NodeList
的类数组。
js 源码
//根据 name 属性名获取元素
let byName = document.getElementsByName("third");
console.log(byName);
console.log(byName[0]);
console.log(byName[0].innerHTML);
结果
注意:返回的是一个类数组。
- 根据选择器获取
单个
元素对象
语法: document.querySelector(选择器)
返回: 返回匹配的集合中的第一个元素。
js 源码
//根据选择器获取ul元素
let mySelector = document.querySelector("li");
// 获取到的是一组数据中的第一个
console.log(mySelector);
console.log(mySelector.innerHTML);
// 根据伪类选择器获取最后一个子元素对象
let lastChild = document.querySelector("ul>li:last-child");
console.log(lastChild);
console.log(lastChild.innerHTML);
结果
注意:根据选择器获取元素,括号内可以使用伪类选择器。
- 根据选择器获取
所有
元素
语法: document.querySelectorAll(选择器)
返回: 返回包含匹配集合中所有元素的名为NodeList
的类数组。
js 源码
//根据选择器获取匹配的所有元素
let childs = document.querySelectorAll("ul>li");
console.log(childs);
console.log(childs[0]);
console.log(childs[0].innerHTML);
结果
注意:返回的是一个类数组。
2,DOM 元素之间的关系
DOM 可以将任何 HTML 描绘成一个由多层节点构成的结构。
节点分为 12 种不同类型,每种类型分别表示文档中不同的信息及标记。
每个节点都拥有各自的特点、数据和方法,也与其他节点存在某种关系。
节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。
节点中的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。
现在以一段 html 代码为例,讲解他们之间的”族谱”关系。
<ul>
<li class="relation">item1</li>
<li class="relation">item2</li>
<li class="relation">item3</li>
<li class="relation">item4</li>
<li class="relation">item5</li>
<li class="relation">item6</li>
</ul>
- 子元素
以某个元素节点为参考,这个元素节点下面所有的节点都是这个元素的子元素。
例如上面的代码片段中,以<ul>
为参考, 下面的<li>
都是<ul>
的子元素。
子元素相关属性
childNodes
childNodes 是一个只读的类数组对象NodeList
对象,它保存着该节点的第一层子节点// childNodes
// 获取参照元素 ul
const ul = document.getElementsByTagName("ul")[0];
console.log(ul);
// 获取ul的子节点
const result = ul.childNodes;
console.log(result);
结果
children
children 是一个只读的类数组对象HTMLCollection
对象,但它保存的是该节点的第一层元素子节点// childNodes
// 获取参照元素 ul
const ul = document.getElementsByTagName("ul")[0];
console.log(ul);
//children
// 获取ul的元素子节点
const elemChild = ul.children;
console.log(elemChild);
结果
children.length | childElementCount
子元素的数量js 源码
// 获取子元素的长度
// children.lenght
let childLenght = ul.children.length;
console.log(childLenght); // 6
// childElementCount
let childCount = ul.childElementCount;
console.log(childCount); // 6
这两个属性返回的值是一样的。
firstChild | firstElementChild
第一个子节点 | 第一个元素子节点// 获取参照元素 ul
const ul = document.getElementsByTagName("ul")[0];
// 获取第一个子节点
let firstNode = ul.firstChild;
console.log(firstNode); //#test
// 获取第一个元素子节点
let firstElement = ul.firstElementChild;
console.log(firstElement);
结果
lastChild | lastElementChild
最后一个子节点 | 最后一个元素子节点// 获取参照元素 ul
const ul = document.getElementsByTagName("ul")[0];
// 获取最后一个子节点
let lastNode = ul.lastChild;
console.log(lastNode); //#test
// 获取最后一个元素子节点
let lastElement = ul.lastElementChild;
console.log(lastElement);
结果
兄弟元素
以某个元素节点为参考,这个元素相邻的同级元素就是这个元素的兄弟元素。
例如上面的代码片段中,以<li>item3</li>
为参考, 相邻的<li>item2</li>
和 <li>item4</li>
都是<li>item3</li>
的兄弟元素。
兄弟元素相关属性
previousSibling | previousElementSibling
前一个节点 | 前一个元素节点// 获取第三个li
let thirdLi = document.querySelector("ul>li:nth-of-type(3)");
// console.log(thirdLi);
// console.log(thirdLi.innerHTML);
// 获取前一个节点
let preNode = thirdLi.previousSibling;
console.log(preNode);
// 获取前一个元素节点
let preElement = thirdLi.previousElementSibling;
console.log(preElement);
console.log(preElement.innerHTML);
结果
nextSibling | nextElementSibling
后一个节点 | 后一个元素节点// 获取第三个li
let thirdLi = document.querySelector("ul>li:nth-of-type(3)");
// console.log(thirdLi);
// console.log(thirdLi.innerHTML);
// 获取后一个节点
let nextNode = thirdLi.nextSibling;
console.log(nextNode);
// 获取后一个元素节点
let nextElement = thirdLi.nextElementSibling;
console.log(nextElement);
console.log(nextElement.innerHTML);
结果
父元素
以某个元素节点为参考,这个元素的上级元素就是这个元素的父元素。
例如上面的代码片段中,以<li>
为参考, 上面的<ul>
是所有<li>
的父元素。
父元素相关属性
parentNode
每个节点都有一个 parentNode 属性,该属性指向文档树中的父节点。对于一个节点来说,它的父节点只可能是三种类型:element
节点、document
节点和documentfragment
节点。如果不存在,则返回null
// 获取第三个li
let thirdLi = document.querySelector("ul>li:nth-of-type(3)");
// console.log(thirdLi);
// console.log(thirdLi.innerHTML);
// 获取当前节点的父节点
let pNode = thirdLi.parentNode;
console.log(pNode);
返回
ul
元素。parentElement
与parentNode
属性不同的是,parentElement
返回的是父元素节点// 获取第三个li
let thirdLi = document.querySelector("ul>li:nth-of-type(3)");
// console.log(thirdLi);
// console.log(thirdLi.innerHTML);
// 获取当前节点的父元素节点
let peNode = thirdLi.parentElement;
console.log(peNode);
返回
ul
元素。
dom 元素关系博文参考:https://www.cnblogs.com/xiaohuochai/p/5785297.html
3,DOM 遍历
前面我们知道,通过document
对象的方法匹配到的多个元素都是以类数组返回,因此我们遍历 dom 元素的思路就是:先取得 dom 元素的 类数组 然后想办法把它转为数组后,我们就可以用遍历数组的方法遍历 dom 元素了。
正好 js 数组原型 给我们给我们提供了一个方法:Array.from()
可以把 类数组转换为数组。
// dom遍历子元素
// 如何遍历dom元素
// 思路:把其转为数组或者对象再用遍历数组或对象的方法遍历它
// 先获取一个元素的类数组
const lis = document.querySelectorAll("li");
// 把类数组转为数组Array.from()
const lisArr = Array.from(lis);
// console.log(Array.isArray(lisArr)); //true
//遍历forEach()/for of
// forEach()
lisArr.forEach((e) => {
// 文本字体变红
e.style.color = "red";
});
// for of
for (let e of lisArr) {
// 给父元素加边框
if (e.parentElement.hasChildNodes(e)) {
e.parentElement.style.border = "1px solid #000";
break;
}
}
结果
四,classList 对象
classList
对象是用来操作元素的 class
的。
之前我们要想改变一个元素的class
值有两种方法:
style 属性
className 属性
这两个都可以改变一个元素的class
属性,但是有一个区别是style
改变的是 class 的行内样式,它的优先级要比className
属性要高。而且操作起来不够灵活。
要知道详情可以访问博文:https://blog.csdn.net/sinat_32017511/article/details/86497912
现在有一个可以操作元素类属性的对象可以用了:classList
;
该
Element.classList
是一个只读属性,返回现场DOMTokenList
的集合class
元素的属性。然后可以使用它来操作类列表。使用
classList
是通过空格分隔的字符串访问元素的类列表的便捷替代方法element.className
。
下面通过实例演示classList
对象的几种常用的方法
css 源码
/* 样式初始化 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 变紫色 */
.rebeccapurple {
background-color: rebeccapurple;
}
/* 变成灰色 */
.gray {
background-color: #ccc;
}
/* 变绿色 */
.green {
background-color: green;
}
/* 加边框 */
.add-border {
border: 1px solid #000;
}
div {
min-height: 5em;
max-width: 10em;
}
html 源码
<div></div>
方法
element.classList.add()
添加一个类名// 获取div
let div = document.querySelector("div");
// 给div添加样式
// 添加边框
div.classList.add("add-border");
//添加紫色
div.classList.add("rebeccapurple");
//添加灰色
div.classList.add("gray");
//添加绿色
div.classList.add("green");
结果
element.classList.remove()
删除一个类名// 获取div
let div = document.querySelector("div");
//删除样式
// 删除边框
div.classList.remove("add-border");
//删除绿色
div.classList.remove("green");
//删除灰色
div.classList.remove("gray");
结果
element.classList.replace(old , new)
替换一个类名// 获取div
let div = document.querySelector("div");
// 替换样式
// 把紫色替换成灰色
div.classList.replace("rebeccapurple", "gray");
结果
element.classList.contains()
判断一个类型是不是存在,返回 true 和 false// 获取div
let div = document.querySelector("div");
// 判断一个类名是否存在
// 判断元素是否含有rebeccapurple
let ret = div.classList.contains("rebeccapurple");
console.log(ret); //false
let ret1 = div.classList.contains("gray");
console.log(ret1); //true
结果
element.classList.toggle()
自动切换,有这个类就去掉, 没有就加上<div></div>
<button>切换样式</button>
// 获取botton
let btn = document.querySelector("button");
// 获取div
let div = document.querySelector("div");
// 监听点击事件
btn.addEventListener("click", clk, false);
// 切换,有这个类就去掉, 没有就加上
function clk(e) {
// 切换,有这个类就去掉, 没有就加上
div.classList.toggle("rebeccapurple");
}
结果
五,dataset 对象
data-
:为前缀的属性,称为数据属性。可以使用 dataset 对象来获取,获取时请省略掉”data-“。
例如
html 源码
<div
class="user"
id="user-div"
data-id="10"
data-user-name="xiaoming"
data-email="xiaoming@qq.com"
data-tell="13866668888"
></div>
js 源码
// dataset对象
// 获取目标div
let div = document.getElementById("user-div");
//console.log(div);
// 获取id属性的值
let id = div.dataset.id;
console.log(id); //10
// 将使用连接线命名的多个单词的属性名,转换"驼峰命名法"来获取
//获取用户名
let userName = div.dataset.userName;
console.log(userName); //xiaoming
// 获取邮箱
let email = div.dataset.email;
console.log(email); //xiaoming@qq.com
//获取电话号码
let tell = div.dataset.tell;
console.log(tell); //13866668888
结果
注意:将使用连接线命名的多个单词的属性名,转换”驼峰命名法”来获取
六,总结
js 的一些基础知识就介绍到这里了,基础的东西要学的扎实以后用起来得心应手。