Js 运行机制与字符串,数组常用 API
事件冒泡与事件委托/代理
<!DOCTYPE html>
<html lang="zh-CN">
<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>事件冒泡与事件委托/事件代理</title>
</head>
<body>
<ul class="list">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
</ul>
<script>
// 先给第一个li添加一个点击事件
document.querySelector(".list").firstElementChild.onclick = () =>
console.log(event.currentTarget, event.target); //输出内容:<li class="item"> <li class="item">
// 再给他的父级ul添加一个onclick事件
document.querySelector(".list").onclick = () =>
console.log(event.currentTarget, event.target); //输出内容:<ul class="list"> <li class="item">
// 以上我只点击了一次,触发了li上的onclick事件,但是,他的父级ul上添加的点击事件也被触发了,这就是事件冒泡,我们看到li的父级ul事件输出的内容currentTarget(事件绑定者/事件主题是他本身),但是target(事件的触发者确实子集li),这个现象也叫事件委托/代理
</script>
</body>
</html>
表单事件
<!DOCTYPE html>
<html lang="zh-CN">
<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>表单事件</title>
</head>
<body>
<form action="" method="post" id="login">
<label class="title">用户登录</label>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email" value="" autofocus />
<label for="password">密码:</label>
<input type="password" id="password" name="password" />
<button name="submit" ">登录</button>
</form>
<script>
const login=document.forms.login
const email=document.forms.login.email
const password=document.forms.login.password
const button=document.querySelector('#login > button')
button.onclick=()=>event.preventDefault();
email.onfocus=()=>{
email.style.color='black';
email.placeholder='';
}
password.onfocus=()=>{
password.style.color='black';
password.placeholder='';
}
email.onblur=()=>{
if(email.value.length===0){
email.style.color='red';
email.placeholder='请填写邮箱';
setTimeout(()=>email.focus(),2000)
}
else{
password.focus()
}
}
password.onblur=()=>{
if(password.value.length===0){
password.style.color='red';
password.placeholder='请填写密码';
setTimeout(()=>password.focus(),2000)
}
}
</script>
</body>
</html>
js 运行机制:单线程+事件循环
- 单线程
1.单线程:主线程
同步:代码的书写顺序与执行顺序一致,写在前面先执行
和 html 的文档流有点像
<script>
console.log(1);
console.log(2);
console.log(3);
</script>
就像这个代码一样,先输出 1,再输出 2,再输出 3
<!DOCTYPE html>
<html lang="zh-CN">
<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>
<!-- <input type="text" placeholder="同步" onkeydown="console.log(this.value)" /> -->
<!-- 慢半拍 -->
<!-- 分析为什么第一次获取不到?
1. 当按下某个键时, 它会触发keydown事件,事件循环将事件方法从任务队列添加到主线中,并立即调用,即console.log立即执行
2. 但是此时这个键对应的值,例如1, 还没有被DOM渲染到input输入框中,所以console.log获取不到值,或获取一个空值
3. 因为"按下1" 和 "显示1" 是2步操作,而console.log是在第1步结束后一瞬间执行,而值还没被显示到input框中
4. 所以, console.log()执行时机,是在"按下"与"显示"之间,所以无法获取到用户输入的内容或获取到一个空值
5. 为什么第2次按下时,console.log()可以获取到了呢?
6. 是因为当用户再次按下时, console.log()立即执行,此时input中已经有了内容,就是上一次的输入内容,所以就正常输出了 -->
<!-- 解决方案也很简单,让console.log()异步执行即可,等到input框中的内容渲染完成之后再执行 -->
<!-- 必知内容:
1. DOM渲染是同步任务, 这里的dom渲染,是指将内容显示到input框中
2. DOM事件是异步任务, 使用keydown
3. 异步必须在同步完成后执行
-->
<!-- 现在简单了, 将console.log异步调用就可以,直接放在setTimeout中就可以,将延迟设置为0 -->
<!-- 因为setTimeout是异步任务,完毕才会进一定会等主线程中的同步任务执行入主线程,转为同步任务执行
而此时, dom渲染已完成, input框中已经有了数据,所以console.log()就正确的, 同步的获取到了数据
完美解决了"慢半拍"的问题 -->
<input
type="text"
onkeydown="setTimeout(()=>console.log(this.value),10)"
placeholder="异步"
/>
<!-- 解决方案 -->
<input type="text" oninput="console.log(this.value)" placeholder="input" />
<!-- input = keydown + setTimeout -->
</body>
</html>
字符串中常用的 api
<!DOCTYPE html>
<html lang="zh-CN">
<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>字符中常用api</title>
</head>
<body>
<script>
let str = "php中文网";
// 索引从0开始:
// [0->p,1->p,2->p,3->中,4->文, 5->网]
// index = [0, str.length-1]
// 1. length 长度
console.log(str.length);
// 2. charAt: 索引->元素
console.log(str.charAt(3));
console.log(str[3]);
// 3. indexOf: 字符->索引
console.log(str.indexOf("中"));
// 4. search: indexOf一样,但支持正则等
console.log(str.search("文"));
// 5. concat: 字符串拼装
console.log(str.concat("(", "php.cn", ")"));
// 直接用"+", 或者`模板字面量` 更方便
// 6. replace: 替换
console.log(str.replace("中文网", ".cn"));
// str = "php";
console.log(str);
// 7. slice: 子串, 忽略结束索引的值
console.log(str.slice(0, 3));
// 8. substr: 子串, 只需要知道取多少个
console.log(str.substr(0, 3));
console.log(str.substr(3, 3));
// -1最后一个, -2向前一个
console.log(str.substr(-3, 3)); // 中文网
// 9. split: str->array
console.log(str.split(""));
console.log(str.split("", 3));
// 10. toLowerCase, toUpperCase 大小写转换
console.log(str.toLowerCase());
console.log(str.toUpperCase());
// 11. 与html相关
console.log(`<a href="https://php.cn">${str}</a>`);
console.log(str.link("https://php.cn"));
console.log(str.bold());
console.log(str.big());
console.log(str.anchor("url"));
</script>
</body>
</html>
常用数组 api
<!DOCTYPE html>
<html lang="zh-CN">
<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>数组常用api-1</title>
</head>
<body>
<script>
// 字面量
let arr = [
1,
2,
"a",
"b",
true,
{ x: 1, y: 2 },
[1, 2, 3],
function () {},
];
// console.log(arr);
// ...rest
arr = [4, 5, 6];
let arr1 = [...arr];
console.log(arr1);
arr = [1, 2, 3, ...arr, 7, 8, 9];
console.log(arr);
// Array.of
// 原始数据有可能来自一个外部请求api或文件,而这个原始数据就是数组
let a = [1, 2, 3, 4, 5, 6];
// 经过一些其它操作,例如过滤,再重新生成
arr = Array.of(...a);
console.log(arr);
// Array.from
const likeArr = {
0: "red",
1: "blue",
2: "green",
length: 3,
};
console.log(likeArr);
console.log(Array.from(likeArr));
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<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>数组常用api-2</title>
</head>
<body>
<script>
// push,pop, unshift,shift,delete
let arr = [];
// 1. 尾部增删
console.log(arr.push(10));
// 从左到右进入
console.log(arr.push(20, 30));
console.log(arr);
// 尾部删除
console.log(arr.pop());
console.log(arr.pop());
console.log(arr.pop());
// 2. 头部增删
console.log(arr.unshift(10));
// 从右到左进入
console.log(arr.unshift(30, 20));
console.log(arr);
console.log(arr.shift());
console.log(arr.shift());
console.log(arr.shift());
console.log(arr);
arr = [1, 2, 3, 4, 5];
//删除指定索引位置的值,赋null值,但是实际数组长度不变,不影响数组的遍历
delete arr[1];
console.log(arr);
console.log(arr.length);
//可通过修改数组的长度来删减数组内的成员
arr.length = 4;
console.log(arr);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<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>数组常用api-3</title>
</head>
<body>
<script>
// 迭代方法, 遍历元素
// 1. forEach,map
// 2. every, some
// 3. filter, find, findIndex
// 4. reduce
// 1. forEach((item,index,arr)=>{...}), 每个元素逐个调用回调处理
let arr = [1, 2, 3, 4, 5];
let res = arr.forEach(function (item, index, arr) {
// 三个参数中, 只有第一个 item是必须的
console.log(item, index, arr);
// dom
document.body.append(item);
});
// 没有返回值
console.log(res);
// 2. map: 参数与功能 与forEach一样,只不过有返回值
res = arr.map((item) => item * 2);
console.log(res);
// 3. every, some: 断言函数,返回true,false
// every: 数组成员全部满足条件,则返回 true , 否则 false 与
console.log(arr.every((item) => item >= 0));
console.log(arr.every((item) => item >= 3));
// some: 数组成员中只要有一个满足条件,就返回 true, 否则 false, 或
console.log(arr.some((item) => item >= 3));
console.log(arr.some((item) => item >= 10));
// 4. filter: 返回数组中的满足条件的元素组成的新数组
console.log(arr.filter((item) => item >= 3)); // [3,4,5]
// arr.filter(item => item >= 3)[0] -> find
console.log(arr.find((item) => item >= 3));
console.log(arr.findIndex((item) => item >= 3));
// 5. reduce: 归并
res = arr.reduce(function (acc, cur, index, arr) {
// 查看reduce的执行过程
console.log("acc=", acc, "cur=", cur, "index=", index, "arr=", arr);
// 最终结果用 acc 返回, acc累加器
return acc + cur;
}, 5);
console.log(res);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<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>数组常用api-4</title>
</head>
<body>
<script>
// 1. sort
let arr = [1, 10, 20, 6];
console.log(arr.sort());
// asc
console.log(arr.sort((a, b) => a - b));
// desc
console.log(arr.sort((a, b) => b - a));
// 2. join: array -> string
// string.split string -> array
arr = ["red", "green", "blue"];
console.log(arr.join());
console.log(arr.join("-"));
// 3. slice: 子元素
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.slice(2, 5));
console.log(arr.slice(2));
console.log(arr.slice(-6, -3));
// 4. splce: 删除, 新增, 替换
// delete
console.log(arr);
console.log(arr.splice(1, 2));
console.log(arr);
// update
console.log(arr.splice(1, 2, "a", "b"));
console.log(arr);
// insert
console.log(arr.splice(1, 0, "red", "green"));
console.log(arr);
let data = ["red", "green", "blue"];
console.log(arr.splice(1, 0, ...data));
console.log(arr);
</script>
</body>
</html>