6 表示数组的长度,
fill 表示用什么内容填充 数组
let arr = Array(6).fill(",");
filter()
let arr = [1, 0, undefined, 6, 7, "", false];
arr.filter(Boolean); // [1,6,7]
// 下面写法 跟上面写法返回结果一样
arr.filter((item) => item); // [1,6,7]
if (a > 10) {
doSomething();
}
// 优化
a > 10 && doSomething();
if (a > 10) doSomething();
let arr = [1, 2, 3, 4, 5, 6];
arr.length = 0;
console.log(arr); // []
a ?? doSomething();
注意: 转换过后会返回一个新数组,原数组内元素类型不变.
const numArr = ["12", "1", "3.1415", "-10.01"];
// 方法一:
let temporary = numArr.map(Number); // [12, 1, 3.1415, -10.01]
// 方法二:
let temporary = numArr.map((item) => +item); // [12, 1, 3.1415, -10.01]
console.log(temporary);
let propertyDynamic = "color";
let obj = {
name: "coco",
age: 18,
[propertyDynamic]: "tomato",
};
判断一个对象上是否包含某个属性,方法功能类似与 Object.hasOwnProperty() 返回一个 布尔值。
let people = {
name: "coco",
age: 18,
address: "赛博坦星球",
};
console.log("name" in people); // true
console.log(people.hasOwnProperty("name")); // true
与
赋值,当表达式左侧为真
时,给左侧变量赋值
let a = 1;
let b = 0;
console.log((a &&= 21));
console.log((b &&= 21));
或
赋值,当表达式左侧为假
时,给左侧变量赋值
let a = 1;
let b = 0;
console.log((a ||= 21));
console.log((b ||= 21));
// test.js 文件
/*
中断和恢复任务序列:
1. 首先判断当前函数的状态.(执行中or中断)
2. 每次执行一个任务之后,都判断一下当前队列的状态(执行中or中断)
3. 保证函数暂停后,重新开始是从暂停处继续执行函数
4. 考虑返回的promise 状态.
*/
function processTasks(...tasks) {
// 判断函数是否在执行中
let isRunning = false;
// 用于接受函数执行成功的结果
let resultTasks = [];
// 全局变量,方便暂停后,从暂停函数出执行下一个任务
let i = 0;
// 判断 start 函数返回的promise 状态
let promiseState = null;
return {
start() {
return new Promise(async (resolve, reject) => {
if (promiseState) {
// 如果promise 函数已经有了返回结果就抛出得到的结果,结束了(成功or失败)
promiseState.then(resolve, reject);
return;
}
if (isRunning) {
// 判断队列任务正在执行,则不做任何操作
return;
}
isRunning = true;
while (i < tasks.length) {
try {
console.log(i, "执行中");
// 循环一次执行传入的函数,并将返回结果添加到数组中
resultTasks.push(await tasks[i]());
console.log(i, "执行完成");
} catch (error) {
isRunning = false;
// 失败 抛出错误
reject(error);
promiseState = Promise.reject(error);
return;
}
// i++ 暂停后重新执行任务,从暂停处函数开始执行
i++;
if (!isRunning && i < tasks.length - 1) {
console.log("执行被中断");
// 判断当前任务队列状态是否中断,如果中断就跳出循环
return;
}
}
isRunning = false;
// 成功 抛出执行结果
resolve(resultTasks);
// 给promise状态赋值
promiseState = Promise.resolve(resultTasks);
});
},
pause() {
isRunning = false;
},
};
}
实战案例
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>study-practicetitle>
head>
<body>
<button id="start">开始button>
<button id="end">结束button>
<script src="./test.js">script>
<script>
const tasks = [];
for (let i = 0; i < 6; i++) {
tasks.push(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(i);
}, 2000);
});
});
}
const processcor = processTasks(...tasks);
let startBtn = document.getElementById("start");
let endBtn = document.getElementById("end");
startBtn.addEventListener("click", async () => {
console.log("开始");
let result = await processcor.start();
console.log("任务执行完成", result);
});
endBtn.addEventListener("click", () => {
console.log("任务暂停");
processcor.pause();
});
script>
body>
html>
情况一: 多个分支,操作相同
优化方案: 可以写一个映射关系,从而简化代码分支
源代码;
function speak(name) {
if (name === "老虎") {
console.log("嗷呜嗷呜嗷呜");
} else if (name === "小狗") {
console.log("汪汪汪");
} else if (name === "小猫") {
console.log("喵喵喵");
} else {
console.log("不知道怎么叫");
}
}
speak("小猫"); // 喵喵喵
speak("狐狸"); // 不知道怎么叫
优化代码;
function optimizeSpeak(name) {
const nameMap = {
老虎: "嗷呜嗷呜嗷呜",
小狗: "汪汪汪",
小猫: "喵喵喵",
};
if (nameMap[name]) {
console.log(nameMap[name]);
} else {
console.log("不知道怎么叫");
}
}
optimizeSpeak("老虎"); // '嗷呜嗷呜嗷呜'
optimizeSpeak("狐狸"); // 不知道怎么叫
情况二: 多个分支,但是对应的操作不同.(比如操作一想要打印,操作二想要写入某个文件等)
解决办法: 同样可以写一个映射关系, 不过匹配到对应的内容后,去执行对应的函数
,从而做不同的操作.
关键是去执行匹配到的函数
源代码;
function speak(name) {
if (name === "老虎") {
console.log("嗷呜嗷呜嗷呜");
} else if (name === "小狗") {
console.log("写入文件: 汪汪汪");
} else if (name === "小猫") {
console.log("上传服务器: 喵喵喵");
} else {
console.log("不知道怎么叫");
}
}
speak("小狗"); // '写入文件: 汪汪汪'
speak("老牛"); // '不知道怎么叫'
代码优化: function optimizeSpeak(name) {
// 关键是执行匹配到函数
const nameMap = {
老虎: () => console.log("嗷呜嗷呜嗷呜"),
小狗: () => console.log("写入文件:", "汪汪汪"),
小猫: () => console.log("上传服务器", "喵喵喵"),
};
if (nameMap[name]) {
nameMap[name]();
} else {
console.log("不知道怎么叫");
}
}
optimizeSpeak("老虎"); // '嗷呜嗷呜嗷呜'
optimizeSpeak("老牛"); // '不知道怎么叫'
情况三: 没办法具体的去映射某个字段,要求传入的内容只要包含匹配的内容就要执行响应的操作.
解决办法 : 可以写一个元组,然后根据匹配到的元组内容做不同的操作
关键是匹配符合条件的元组,然后执行元组对应的执行函数
function speak(name) {
if (name.includes("虎")) {
console.log("嗷呜嗷呜嗷呜");
} else if (name.endsWith("猫") && !name.includes("狗")) {
console.log("喵喵喵");
} else if (name.endsWith("狗") && name.length <= 3) {
console.log("汪汪汪");
} else {
console.log("不知道怎么叫");
}
}
speak("小猫"); // 喵喵喵
speak("小小小狗"); // 不知道怎么叫
function optimizeSpeak(name) {
// [[需要满足的条件,满足条件后需要执行的操作],[]]
const nameArr = [
[() => name.includes("虎"), () => console.log("嗷呜嗷呜嗷呜")],
[
() => name.endsWith("猫") && !name.includes("狗"),
() => console.log("喵喵喵"),
],
[
() => name.endsWith("狗") && name.length <= 3,
() => console.log("喵喵喵"),
],
];
// 找到符合条件的元组
const target = nameArr.find((item) => item[0]());
if (target) {
target[1]();
} else {
console.log("不知道怎么叫");
}
}
optimizeSpeak("大老虎"); // '嗷呜嗷呜嗷呜'
optimizeSpeak("小小小狗"); // 不知道怎么叫
当我们需要使用 三目运算符返回一个 Boolean 的时候
场景: 当目标值等于 3
的时候不隐藏
;不等于 3
的时候隐藏
.
优化后的代码,当 val !== 3 成立的时候,就会返回一个 true. 对应 三元表达式 不成立时的返回值.
// 错误案例
targetObj.isHidden = val === 3 ? false : true;
// 优化后
targetObj.isHidden = val !== 3;
当需要判断某一个值满足某一条件时取 true,反之则取 false
// 错误案例
if (val === 3) {
this.sqeApproveFormList.fileds.find(
(item) => item.slotName === "rejectTable"
).isHidden = false;
console.log(this.sqeApproveFormList.fileds);
} else {
this.sqeApproveFormList.fileds.find(
(item) => item.slotName === "rejectTable"
).isHidden = true;
}
// 优化后代码
let targetObj = this.sqeApproveFormList.fileds.find(
(item) => item.slotName === "rejectTable"
);
targetObj.isHidden = val !== 3;
Async
标识通过判断函数原型上的
Symbol.toStringTag
这个属性是否等于 AsyncFunction
async function a() {}
function b() {}
function isAsyncFunction(fn) {
return fn[Symbol.toStringTag] === "AsyncFunction";
}
console.log(isAsyncFunction(a)); // true
console.log(isAsyncFunction(b)); // false
- 函数的原型链上有一个属性
Symbol.toStringTag
可以判断(设置)函数的类型.(也就是打上一个标识)- Object.prototype.toString.call(“”) 方法判断数据类型,会返回[object string] 的格式.
但是只针对js内置的几种数据类型的原型构造函数有用
,如果自己声明的构造函数使用这种方法是没用的.
// 正常数据类型使用 Object.prototype.toString.call()
console.log("字符串-类型判断", Object.prototype.toString.call("")); // [object String]
// 正常声明 一个函数,使用 Object.prototype.toString.call()
function b() {}
console.log("普通函数-类型判断", Object.prototype.toString.call(b)); // [object Function]
// 自己声明构造函数 并实例后,使用Object.prototype.toString.call()
function A() {}
let pa = new A();
console.log("构造函数-类型判断", Object.prototype.toString.call(pa)); // [object Object]
// 使用 Symbol.toStringTag 方法重置自己写的构造函数
function C() {}
let pc = new C();
pc[Symbol.toStringTag] = "Holy shit!";
console.log(Object.prototype.toString.call(pc)); // [object Holy shit!]
// 带 async 标识的函数
console.log(Object.prototype.toString.call(async function d() {})); // [object AsyncFunction]
跨页面通讯
)注意:
- 若是只打开一个 tab,那么监听 storage 是不起效果的,
需要
在多个 tab
中方可以看到效果- 监听事件要在
父组件中
,也就是第一个 tab 中,而非新打开的 tab。(这是我的理解)
// storage储存事件
export function sendMsg(type, content) {
localStorage.setItem(
"##" + type,
JSON.stringify({ content, temp: Date.now() })
);
}
// 监听 Storage 变化事件
export function listenMsg(handler) {
const storageHandler = (e) => {
const data = JSON.parse(e.newValue);
handler(e.key.slice(2), data.content);
};
window.addEventListener("storage", storageHandler);
// 移除监听事件
return () => {
window.removeEventListener("storage", storageHandler);
};
}
父组件(监听组件)代码
<template>
<div class="container">
<button @click="go">go childrenbutton>
div>
template>
<script>
import { listenMsg } from "@/utils/storage.js";
export default {
mounted() {
// 接收监听函数返回的函数,在文件销毁时调用清除监听事件
this.listener = listenMsg((a, b) => {
console.log(a, b);
});
},
destroyed() {
// 组件销毁时清空storage监听事件
this.listener();
},
data() {
return {
listener: null,
};
},
methods: {
go() {
window.open("#/new-father", "_blank");
},
},
};
script>
子组件 (数据存储组件)
<template>
<div class="father_class">
<button @click="testhandler">本地数据新增button>
div>
template>
<script>
import { sendMsg } from "@/utils/storage.js";
export default {
data() {
return {
i: 0,
};
},
methods: {
testhandler() {
sendMsg("add", this.i++ + "coco");
},
},
};
script>
- 快捷键 cmmb (
需安装插件
)- 输入
/**
然后回车可以快速生成
优点:
- 当鼠标放在
拥有解释文档
的函数上时,编辑器会有写好的注释内容
- 当规定好入参类型时,在使用入参时编辑器会有相关数据类型的属性提示.
/**
* 函数防抖
* @author Coco 作者注释
* @license Es6-2.01 版本注释
* @param {function} fn 需要执行的函数
* @param {number} [delay] 延期执行时间,默认1s
* @return {Function} 防抖函数
*/
function debounce(fn, delay = 1000) {}
{“GET”|“POST”} 这种写法,当传入 method 属性时,编辑器会有这两种选择提示
/**
* @param {object} options 配置对象
* @param {string} options.url 请求地址
* @param {"GET"|"POST"} options.method 请求方法
* @param {object} options.body 请求方式
* @param {object} options.header 请求头
*
*/
function request(options) {}
// 函数调用
request({ method: "GET" });
实现 add[2][3][4] + 100
视频讲解@渡一教育
知名符号表示: 将一个对象转为 原始类型时,即会调用知名符号
const add = new Proxy(
{
_store: 0,
},
{
get(target, p, receiver) {
console.log(p); // 2,3,4 Symbol(Symbol.toPrimitive)
if (p === Symbol.toPrimitive) {
// 判断如果返回了知名符号 ,则表示在进行类型转换,就返回一个函数
return () => {
return target._store;
};
}
target._store += +p;
return receiver;
},
}
);
console.log(add[2][3][4] + 100); // 109
要实现一个函数包含两个步骤: 1. 设计 2. 实现 (
先设计后实现
)
设计主要内容:函数签名
函数签名包含三个部分: 1. 函数名 2. 参数 3. 返回值
函数签名举例
- 下面的例子给出了一个判断一个数是否为素数的函数签名(
设计
)- 随后在函数中实现相关代码 (
实现
)
/**
* 判断一个数是否为素数
* @param {number} num
* @return {boolean}
*/
function isPrime(n) {}
- 首先调用 对象原型上的 valueOf 方法
- 如果 valueof 得不到原始类型,则调用 toString() 方法,进行类型转换
案例操作
使 a1 && a2 && a==3 成立
let a = {
n: 1,
valueOf() {
return this.n++;
},
};
console.log(a == 1 && a == 2 && a == 3); // true
// 小例子
console.log(typeof {}); // 'object'
console.log(typeof 1); // 'number'
console.log({ valueOf: () => 1 } == 1); // true
使用场景: 需要将匹配到的问题进行指定内容的替换时
/**
* 匹配字符串中相关内容并替换
*
* @param {string} content 原始内容
* @param {string|Array|object} matchContent 匹配到的值
* @param {stringt} replaceContent 需要替换的内容
* @returns {boolean}
*/
let sentence6 = "fuck you,shit!fuck!";
function sensitivenessChange(content, matchContent, replaceContent = "*") {
// 最基本的匹配替换
let regexp = new RegExp(matchContent, "ig");
// 数组类型处理 用于匹配多个敏感词汇
if (Array.isArray(matchContent))
regexp = new RegExp(`${matchContent.join("|")}`, "ig");
// 对象类型处理 用于匹配到的文字替换为指定内容
if (Object.prototype.toString.call(matchContent) === "[object Object]") {
// 用于储存第一次替换后的字符串
let rep = "";
// 遍历需要指定替换的内容 然后赋值给正则表达式
for (let key in matchContent) {
regexp = new RegExp(`${key}`, "ig");
// 第一次使用传入的字符串
if (!rep) rep = content.replace(regexp, matchContent[key]);
// 之后每次都使用储存的字符串
else rep = rep.replace(regexp, matchContent[key]);
}
return rep;
}
return content.replace(regexp, replaceContent);
}
// 匹配多个敏感词
console.log(sensitivenessChange(sentence6, ["fuck", "shit"])); // * you,*!*!
// 替换指定内容
console.log(sensitivenessChange(sentence6, "fuck", "honey")); // honey you,shit!honey!
// 指定匹配问题 替换 指定内容
console.log(sensitivenessChange(sentence6, { you: "money", shit: "love" })); // fuck money,love!fuck!
/**
* 生成随机值
* @param {number} length 长度
* @returns {string}
*/
var createRandomID = function (length) {
if (length === void 0) {
length = 12;
}
var result = [];
var word =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
var wordLength = word.length;
for (var i = 0; i < length; i++) {
result.push(word[Math.round(Math.random() * wordLength)]);
}
return result.join("");
};
console.log(createRandomID(26));
主要方法 : 实例一个 URLSearchParams 对象
/**
* 获取 URL 查询参数
* @param {string} url URL 查询参数
* @param {string} key 参数名
* @returns {string}
*/
function searchParams(url, key) {
if (url === void 0) {
url = location === null || location === void 0 ? void 0 : location.search
}
var searchParams = new URLSearchParams(url)
return searchParams.get(key)
}