知识点总结系列
:
数组相关
声明和初始化数组
我们可以使用默认值(如""、null或 )初始化特定大小的数组0。您可能已经将这些用于一维数组,但如何初始化二维数组/矩阵呢?
js
代码解读
复制代码const array = Array(5).fill('');
// 输出
(5) ["", "", "", "", ""]
const matrix = Array(5).fill(0).map(()=>Array(5).fill(0));
// 输出
(5) [Array(5), Array(5), Array(5), Array(5), Array(5)]
0: (5) [0, 0, 0, 0, 0]
1: (5) [0, 0, 0, 0, 0]
2: (5) [0, 0, 0, 0, 0]
3: (5) [0, 0, 0, 0, 0]
4: (5) [0, 0, 0, 0, 0]
length: 5
从数组中过滤出虚假值
Falsy值喜欢0
,undefined
,null
,false
,""
,''
可以很容易地通过以下方法省略
js
代码解读
复制代码const array = [3, 0, 6, 7, '', false];
array.filter(Boolean);
// 输出
(3) [3, 6, 7]
数组查找
当对数组进行查找时,indexOf()
用于获取查找项的位置。如果未找到该项,则返回值为-1
。在JavaScript中,0被视为false
,而大于或小于0的数字被视为true
。因此,需要这样来写
传统写法:
js
代码解读
复制代码if(arr.indexOf(item) > -1) {
}
if(arr.indexOf(item) === -1) {
}
简化写法:
js
代码解读
复制代码if(~arr.indexOf(item)) {
}
if(!~arr.indexOf(item)) {
}
位非(~)运算符对除了-1之外的任何值都返回一个"真"值。对其进行取反就是简单地使用!~
即可。另外,也可以使用includes()
函数:
js
代码解读
复制代码if(arr.includes(item)) {
}
打乱数组
利用内置Math.random()
方法。
js
代码解读
复制代码const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
list.sort(() => {
return Math.random() - 0.5;
});
// 输出
(9) [2, 5, 1, 6, 9, 8, 4, 3, 7]
// Call it again
(9) [4, 1, 7, 5, 3, 8, 2, 9, 6]
检测是否为一个安全数组
js
代码解读
复制代码 // 检测是否为一个安全数组,若不是返回空数组 这里借助isArray 方法
const safeArray = (array) => {
return Array.isArray(array) ? array : []
}
数组清空
- 对比arr.length=0与arr=[]
arr.length=0的应用点主要是完全清空字面量指向的真实数组
我们知道在js中,引用类型相对应的自变量实际上是在栈内存中储存了地址,指向堆内存中真实的数据 假设现有一个不空的数组arr
当我们使用 arr=[]时,实际上是为arr重新赋值为一个空数组[]
此时arr原先储存的地址所指向的原数组仍然在内存中(可能导致内存泄露)
使用arr.length=0时:命令作用在真实数组,相当于直接将原数组清空
js
代码解读
复制代码//使用arr作为模版用于循环中接收值:
res=arr
arr=[]
//等同于:
res=arr.slice()//copy
arr.length=0
实现并集、交集、和差集
js
代码解读
复制代码let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]); // Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x))); // set {2, 3}
// (a 相对于 b 的)差集
let difference = new Set([...a].filter(x => !b.has(x))); // Set {1}
map循环
map: 只有当arr为基本数据类型时,map方法才不会改变原始数组,arr为引用类型时,还是会改变原数组的
js
代码解读
复制代码const citys = [{ name: 'shenzhen' }, { name: 'hanghzhou' }];
const newCitys = citys.map((item) => {
item.country = 'china';
return item;
});
console.log('citys', citys); //[{ name: 'shenzhen', country: 'china' },{ name: 'hanghzhou', country: 'china' }]
console.log('newCitys', newCitys); //[{ name: 'shenzhen', country: 'china' },{ name: 'hanghzhou', country: 'china' }]
逻辑运算
对各种条件使用逻辑运算符
如果你想减少嵌套 if…else 或 switch case,你可以简单地使用基本的逻辑运算符AND/OR
。
js
代码解读
复制代码function doSomething(arg1){
arg1 = arg1 || 10;
// 如果尚未设置,则将 arg1 设置为 10 作为默认值
return arg1;
}
let foo = 10;
foo === 10 && doSomething();
// is the same thing as if (foo == 10) then doSomething();
// 输出: 10
foo === 5 || doSomething();
// is the same thing as if (foo != 5) then doSomething();
// 输出: 10
可选链
可选的链接 ?.如果值在 ? 之前,则停止评估。为 undefined 或 null 并返回
js
代码解读
复制代码undefined。
const user = {
employee: {
name: "Kapil"
}
};
user.employee?.name;
// 输出: "Kapil"
user.employ?.name;
// 输出: undefined
user.employ.name
// 输出: VM21616:1 Uncaught TypeError: Cannot read property 'name' of undefined
对于动态属性将其更改为:
js代码解读复制代码object?.[index]
对于方法的调用你可以这样写
js
代码解读
复制代码object.runsOnlyIfMethodExists?.()
空合并算子
空合并运算符 (??) 是一个逻辑运算符,当其左侧操作数为空或未定义时返回其右侧操作数,否则返回其左侧操作数。
js
代码解读
复制代码const foo = null ?? 'my school';
// 输出: "my school"
const baz = 0 ?? 42;
// 输出: 0
||=与??=
||=
和 ??=
是两种不同的赋值运算符,它们分别表示逻辑或赋值和空值合并赋值。
||=
运算符用于给变量赋值,但仅当左侧的变量为假值(false、null、undefined、空字符串等)时才会执行赋值操作。例如:
js
代码解读
复制代码let x = null;
x ||= 5;
console.log(x); // 输出 5,因为 x 是 null,所以赋值为 5
let y = 10;
y ||= 7;
console.log(y); // 输出 10,因为 y 已经有值了,不会执行赋值操作
??=
运算符用于给变量赋值,但仅当左侧的变量为null
或undefined
时才会执行赋值操作。例如:
js
代码解读
复制代码javascriptCopy Codelet a = null;
a ??= 5;
console.log(a); // 输出 5,因为 a 是 null,所以赋值为 5
let b = 10;
b ??= 7;
console.log(b); // 输出 10,因为 b 已经有值了,不会执行赋值操作
数字相关
将十进制转换为二进制或十六进制
在解决问题的同时,我们可以使用一些内置的方法,例如.toPrecision()
或.toFixed()
来实现许多帮助功能。
js
代码解读
复制代码const num = 10;
num.toString(2);
// 输出: "1010"
num.toString(16);
// 输出: "a"
num.toString(8);
// 输出: "12"
获取两个整数之间的随机整数
该方法用于获取两个整数之间的随机整数
js
代码解读
复制代码const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
random(1, 50);
将一个字符串变成数字
常规操作
js
代码解读
复制代码let str = '2'
console.log(Number(str)) //2
复制代码
骚操作一
js
代码解读
复制代码let str = '2'
console.log(~~str) //2
骚操作二
js
代码解读
复制代码let str = '2'
console.log(+str) //2
科学计数法
可以使用科学技术法来表示数字,以省略尾部的零。例如,1e7
实际上表示 1 后面跟着 7 个零。它表示一个十进制,相当于 10,000,000。
传统写法:
js
代码解读
复制代码for (let i = 0; i < 10000; i++) {}
简化写法:
js
代码解读
复制代码for (let i = 0; i < 1e7; i++) {}
// 下面的所有比较都将返回 true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;
指数幂运算
指数幂运算可以使用 **
来简化。
传统写法:
js
代码解读
复制代码Math.pow(2,3); // 8
Math.pow(2,2); // 4
Math.pow(4,3); // 64
简化写法:
js
代码解读
复制代码2**3 // 8
2**4 // 16
4**3 // 64
从 ES7(ECMAScript 2016)开始,JavaScript 引入了指数幂运算符 **
,使指数幂运算更加简洁。
转为布尔值
可以使用双重逻辑非操作符将任何值转换为布尔值。
js
代码解读
复制代码!!23 // TRUE
!!"" // FALSE
!!0 // FALSE
!!{} // TRUE
单一的逻辑非操作符已经可以将值转换为布尔类型并对其进行取反,所以第二个逻辑非操作符会再次对其进行取反,从而将其恢复为原始含义,并保持为布尔类型。
对象相关
检查对象是否为空
检查对象是否为空,实际上并不那么简单,即使对象为空,每次检查对象是否等于 {}
也会返回 false
。
幸运的是,下面的单行代码正是我们想要的。
js
代码解读
复制代码const isEmpty = obj => Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;
isEmpty({}) // true
isEmpty({a:"not empty"}) //false
动态属性名称:多功能对象键
可以使用方括号将变量用作对象属性名称:
js
代码解读
复制代码const key = 'name';
const person = { [key]: 'Alice' };
console.log(person.name); // Output: Alice
检测对象是否为一个安全对象
js
代码解读
复制代码 // 首先要去判断 当前对象是否为有效对象
const isVaildObject = (obj) => {
return typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length
}
// 这里直接用上面的函数 如果有效就返回本身,无效就返回空对象
const safeObject = obj => isVaildObject(obj) ? obj : {}
字符串相关
字符串首字母大写
该方法用于将英文字符串的首字母大写处理:
js
代码解读
复制代码const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
capitalize("hello world") // Hello world
翻转字符串
该方法用于将一个字符串进行翻转操作,返回翻转后的字符串:
js
代码解读
复制代码const reverse = str => str.split('').reverse().join('');
reverse('hello world'); // 'dlrow olleh'
过滤特殊字符
js
代码解读
复制代码 function filterCharacter(str){
// 首先设置一个模式
let pattern = new RegExp("[`~!@#$^&*()=:”“'。,、?|{}':;'%,\[\].<>/?~!@#¥……&*()&;—|{ }【】‘;]")
let resultStr = "";
for (let i = 0; i < str.length; i++) {
// 主要通过 replace ,pattern 规则 去把字符替换成空 最后拼接在 resultStr
resultStr = resultStr + str.substr(i, 1).replace(pattern, '');
}
// 当循环结束的时候返回最后结果 resultStr
return resultStr;
}
// 示例
filterCharacter('gyaskjdhy12316789#$%^&!@#1=123,./[') // 结果:gyaskjdhy123167891123
浏览器相关
复制内容到剪切板
该方法使用 navigator.clipboard.writeText 来实现将文本复制到剪贴板:
js
代码解读
复制代码const copyToClipboard = (text) => navigator.clipboard.writeText(text);
copyToClipboard("Hello World");
兼容性方案
js
代码解读
复制代码const copyText = async (val) => {
try {
// 使用现代 API 尝试复制
if (navigator.clipboard && navigator.permissions) {
await navigator.clipboard.writeText(val);
return; // 如果成功,直接返回
}
// 降级方案
const textArea = document.createElement('textArea')
textArea.value = val
textArea.style.width = 0
textArea.style.position = 'fixed'
textArea.style.left = '-999px'
textArea.style.top = '10px'
textArea.setAttribute('readonly', 'readonly')
document.body.appendChild(textArea)
textArea.select()
// 尝试执行复制操作
const success = document.execCommand('copy');
if (!success) {
throw new Error('无法复制文本');
}
// 清理
document.body.removeChild(textArea);
} catch (err) {
console.error('复制失败:', err);
}
};
清除所有cookie
该方法可以通过使用 document.cookie 来访问 cookie 并清除存储在网页中的所有 cookie:
js
代码解读
复制代码const clearCookies = document.cookie.split(';').forEach(
cookie => document.cookie = cookie.replace(/^ +/,'')
.replace(/=.*/, `=;expires=${new Date(0).toUTCString()};path=/`));
获取选中的文本
该方法通过内置的 getSelection 属性获取用户选择的文本:
js
代码解读
复制代码const getSelectedText = () => window.getSelection().toString();
getSelectedText();
滚动到页面顶部
该方法用于在页面中返回顶部:
js
代码解读
复制代码const goToTop = () => window.scrollTo(0, 0);
// function goTop() { window.scrollTo({ top: 0, behavior: "smooth" }); }
goToTop();
是否滚动到页面底部
该方法用于判断页面是否已经底部:
js
代码解读
复制代码const scrolledToBottom = () => document.documentElement.clientHeight + window.scrollY
>= document.documentElement.scrollHeight;
判断当前标签页是否激活
该方法用于检测当前标签页是否已经激活:
js
代码解读
复制代码const isTabInView = () => !document.hidden;
重定向到一个URL
该方法用于重定向到一个新的URL:
js
代码解读
复制代码const redirect = url => location.href = url
redirect("https://www.google.com/")
打开浏览器打印框
该方法用于打开浏览器的打印框: js
js
代码解读
复制代码const showPrintDialog = () => window.print()
检测元素是否处于焦点
activeElement
属性返回文档中当前获得焦点的元素。
js
代码解读
复制代码const elementIsInFocus = (el) => (el === document.activeElement);
elementIsInFocus(anyElement)
// 元素处于焦点返回true,反之返回false
url相关
从url获取参数并转为对象
网页路径经常是:www.baidu.com?search=js&xxx=kkk
这种形式的,我们是经常需要取参数的,可以使用第三方的qs
包实现,如果你只是要实现去参数,这一句代码就可以实现,不用再引入qs
了。
js
代码解读
复制代码const getParameters = URL => JSON.parse(`{"${decodeURI(URL.split("?")[1]).replace(/"/g, '\"').replace(/&/g, '","').replace(/=/g, '":"')}"}`
)
getParameters("https://www.google.com.hk/search?q=js+md&newwindow=1");
// {q: 'js+md', newwindow: '1'}
重定向到一个URL
该方法用于重定向到一个新的URL:
js
代码解读
复制代码const redirect = url => location.href = url
redirect("https://www.google.com/")
其他
检测是否是一个函数
js
代码解读
复制代码 // 检测是否是一个函数 其实写法以后直接 isFunction 就好了,避免重复写判断
const isFunction = (obj) => {
return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
};
防抖/节流
简单介绍
- 防抖:指定时间内 频繁触发一个事件,以最后一次触发为准
- 节流:指定时间内 频繁触发一个事件,只会触发一次
应用场景有很多比如:
防抖是: input搜索,用户在不断输入内容的时候,用防抖来减少请求的次数并且节约请求资源
节流:场景普遍就是按钮点击,一秒点击 10 下会发起 10 次请求,节流以后 1 秒点再多次,都只会触发一次
下面我们来实现
js
代码解读
复制代码 // 防抖
// fn 需要防抖的函数,delay 为定时器时间
function debounce(fn,delay){
let timer = null // 用于保存定时器
return function () {
// 如果timer存在 就清除定时器,重新计时
if(timer){
clearTimeout(timeout);
}
//设置定时器,规定时间后执行真实要执行的函数
timeout = setTimeout(() => {
fn.apply(this);
}, delay);
}
}
// 节流
function throttle(fn) {
let timer = null; // 首先设定一个变量,没有执行定时器时,默认为 null
return function () {
if (timer) return; // 当定时器没有执行的时候timer永远是false,后面无需执行
timer = setTimeout(() => {
fn.apply(this, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)
// 表示可以执行下一次循环了。
timer = null;
}, 1000);
};
}
常用正则判断
js
代码解读
复制代码 // 校验2-9位文字 不符合为 false 符合为 true
const validateName = (name) => {
const reg = /^[\u4e00-\u9fa5]{2,9}$/;
return reg.test(name);
};
// 校验手机号
const validatePhoneNum = (mobile) => {
const reg = /^1[3,4,5,6,7,8,9]\d{9}$/;
return reg.test(mobile);
};
// 校验6到18位大小写字母数字下划线组成的密码
const validatePassword = (password) => {
const reg = /^[a-zA-Z0-9_]{6,18}$/;
return reg.test(password);
};
高级技巧
模拟点击
vue.js
1,给另一个按钮添加ref
<el-button size="small" type="primary" ref="import">导入</el-button>
2,事件触发
this.$refs.import.$el.click()
利用函数给对象赋值
js
代码解读
复制代码eventDic.closeCase = (() => {
var ary = e.applicationSettle ? e.applicationSettle.split(',') : []
var dary = ary.map(o => this.eventDict.applicationSettle.get(o))
return dary.join(',')
})()
酷炫控制台技巧:调试的乐趣
使用console.table()
和console.groupCollapsed()
超越console.log()
:
js
代码解读
复制代码const users = [{ name: 'Alice' }, { name: 'Bob' }];
console.table(users);
console.groupCollapsed(’Details’);
console.log(’Name: Alice’);
console.log(’Age: 30’);
console.groupEnd();
编码好习惯
console.log({name})取代console.log('name', name)
当我们有一个变量名需要在控制台打印的时候,很多人都习惯于这样写:
js
代码解读
复制代码console.log('name', name)
这种写法本身没有问题,但是会有一些小问题:
- 代码长度较长,字符串无法自动补全需要复制粘贴,变量名较长的情况更为明显。
- 表现不直观,如果
name
是一个对象,展开的时候占位太高我们会经常找不到开头的name在哪。
有了ES6,我们其实完全可以这样写:
js
代码解读
复制代码console.log({name})
这种写法在结果上,可以和上面的写法达到一样的目的。但是不管是代码简洁程度
、还是可读性
上,都可以得到更友好的提升。尤其是name
是一个对象的时候,效果更为明显。
虽然是很简单的一行代码,但是效果还是比较实用的。
巧用JS隐式类型转换
JS是一门弱类型语言,不同type的变量可以相互转化。我们可以巧妙的利用这一特性,让我们的代码在做类型转换的时候,变得更简洁,更优雅。直接上代码:
- 快速转换Number类型:
js
代码解读
复制代码// 字符串转数字代码对比
const price = parseInt('32'); //传统方式
const price = Number('32'); //传统方式
const price = +'32'; //新方式
// 日期转换为时间戳代码对比
const timeStamp = new Date().getTime(); //传统方式
const timeStamp = +new Date(); //新方式
//布尔转数字新方式
console.log(+true); // Return: 1
console.log(+false); // Return: 0
- 快速转换Boolean类型:
js
代码解读
复制代码// 各种类型转布尔代码对比
const isTrue = Boolean('') //传统方式
const isTrue = !!'' //新方式
const isTrue = Boolean(0) //传统方式
const isTrue = !!0 //新方式
const isTrue = Boolean(null) //传统方式
const isTrue = !!null //新方式
const isTrue = Boolean(undefined) //传统方式
const isTrue = !!undefined //新方式
- 快速转换String类型:
js
代码解读
复制代码// 数字转string代码对比
const num = 1;
const str = num.toString(); //传统方式
const str = num + ''; //新方式
return取代if...else
假如我们有以下代码:
js
代码解读
复制代码if (condition1) {
// do condition1
} else if (condition2) {
// do condition2
} else if(condition3) {
// do condition3
}
这个写法逻辑上没有问题,但是当日后if
条件增加的时候,越来越多的if else
阅读起来费劲不说,更难受的是,当我们需要删除
一个条件的时候,我们需要很小心的找到每一个if else
对应的{}
,更没办法直接选中代码直接删除。其实我们完全可以改成return
形式让代码变得更简洁
、更易读
,且更容易编辑
。
js
代码解读
复制代码if (condition1) {
// do condition1
return;
}
if (condition2) {
// do condition2
return;
}
if (condition3) {
// do condition3
return;
}
可能你会说,这么简单的东西,还要写出来,谁不会呢?
但是看起来是很简单,大家都一眼就能看懂的改动,其实根据笔者的经验,很多有经验的老手,都会时常忘记这个小细节。