小知识随手记(九):兄弟选择器(~和+)区别、forEach无法return和break的替换方法、html结构转为markdown语法、beforeunload离开当前页面提示、利用set及解构数组去重、设置函数必传参数
一、CSS选择器之兄弟选择器(~和+)
以前还没注意,兄弟元素选择器 ~ 和 + 的区别:
‘+’选择器:表示某元素后相邻的兄弟元素,也就是紧挨着的,是单个的。
‘~’选择器:则表示某元素后所有同级的指定元素,强调所有的。
二、forEach无法return或break跳出循环的替换方法
我们都知道for循环里要跳出整个循环是使用break,但在数组中用forEach循环如要退出整个循环使用break会报错,使用return也不能跳出循环。
针对这个问题,可以使用数组的另外2个方法 some() 和 every(),或者是使用for循环,或者抛出异常,捕获异常。主要介绍下some和every方式
some():当内部return true时跳出整个循环
every():当内部return false时跳出整个循环
顾名思义,some要找一些,找到了true就结束了,every本意要每个,必须明确不要了false才算退出。但是由于js函数在没有显式return值时会隐式return undefined,undefined转换为布尔值是false,相当于return false。所以在使用every时,必须显示return true才会查询每一个。
1、every 当内部return false时跳出整个循环;但不想跳出循环时,return true;也需要写
//every()当内部return false时跳出整个循环
let list = [1, 2, 3, 4, 5];
list.every((value, index) => {
if(value > 3){
console.log(value)// 4
return false; // 跳出循环
} else {
console.log(value)// 1 2 3
return true;
}
});
list.every((value, index) => {
if(value > 3){
console.log(value)
return false;
}else{
console.log(value)// 1
// return true;
// 如果没有返回值true 的话,也会跳出循环
}
});
// 1
// false
2、forEach没有返回值,只针对每个元素调用func
// forEach没有返回值,只针对每个元素调用func。
let list2 = [1, 2, 3, 4, 5];
list2.forEach((value, index) => {
if(value > 3){
console.log(value)// 4 5
return false;//没有返回值,ruturn false 仍向下执行,且最后返回undefined
}else{
console.log(value)// 1 2 3
return true;
}
});
VM27068:9 1
VM27068:9 2
VM27068:9 3
VM27068:5 4
VM27068:5 5
undefined
3、some 当内部return true时跳出整个循环
let list3 = [1, 2, 3, 4, 5];
list3.some((value, index) => {
if(value === 3){
return true;//当内部return true时跳出整个循环
}
console.log(value)// 1 2
});
VM27073:6 1
VM27073:6 2
true
4、map 有返回值,返回一个新的数组,每个元素为调用func的结果。
let list5 = [1, 2, 3, 4, 5];
let arr = [];
arr = list5.map((value, index) => {
return value * 2;
});
console.log(arr, list5);
VM27113:6 (5) [2, 4, 6, 8, 10] (5) [1, 2, 3, 4, 5]
具体也可以看下之前的博客:JS中map、forEach、filter、reduce等Array新增方法的区别
三、html结构转为markdown语法
推荐一个比较好用的插件:to-markdown,目前已经改名叫: turndown,5.2K star,使用方便简单,感觉不错
github地址:https://github.com/domchristie/turndown
四、当离开当前页面时给予用户提示
mounted () {
window.onbeforeunload=function(event){
let e = window.event || event
e.returnValue=("确定离开当前页面吗?")
}
},
beforeDestroy () {
window.onbeforeunload = null
}
需要注意的是在退出页面的时需要解绑onbeforeunload事件,否则会存在引用未清,无法回收,导致内存泄漏问题。
//方法一
window.onbeforeunload = function(){
return '真的要关闭此窗口吗?';
}
//or 方法二
window.addEventListener("beforeunload", function(event) {
//event.preventDefault();
event.returnValue = "真的要关闭此窗口吗?";
});
在写一个需求,要求用户进入页面,返回/刷新/关闭该页面提示用户一些信息。发现在使用window.onbeforeunload的时候,必须打开调试才会生效,而且只有第一次有效,再次点击就会失效。
在实际使用中让用户打开调试模式肯定是不可能的,后来发现出现这种情况是因为没有在该页面有任何操作,或者是操作时间间隔太短,所以不会有提示。
打开该页面后,在该页面没有任何操作,不会有提示,在input中输入文字或者其他信息,刷新/返回/关闭该页面都会有提示;刷新/返回/关闭操作时间间隔太短有时有提示,有时没有。
所以只有在该页面有操作,并且时间间隔大于5秒左右即会有提示。
五、利用set及解构数组去重及合并对象
let a = [1,2,3,2,5,6,3,3,1]
let b = [...new Set(a)]
console.log(b, a)
// (5) [1, 2, 3, 5, 6]
// (9) [1, 2, 3, 2, 5, 6, 3, 3, 1]
不改变原数组。
同理可以合并或拷贝对象(深拷贝)
const person = { name: 'David Walsh', gender: 'Male' };
const tools = { computer: 'Mac', editor: 'Atom' };
const attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };
const summary = {...person, ...tools, ...attributes};
/*
Object {
"computer": "Mac",
"editor": "Atom",
"eyes": "Blue",
"gender": "Male",
"hair": "Brown",
"handsomeness": "Extreme",
"name": "David Walsh",
}
*/
拷贝对象(深拷贝)
let p1 = { name: 'David Walsh', gender: 'Male',aa: {a: 1} };
let p2 = {...p1}
p2.name = 'test'
console.log(p2, p1)
// {name: "test", gender: "Male", aa: {a: 1}} {name: "David Walsh", gender: "Male", aa: {a:1}}
注意很多时候,我们需要解构别名:ES6中我们经常会使用对象结构获取其中的属性,但有时候会想重命名属性名,以避免和作用域中存在的变量名冲突,这时候可以为解构属性名添加别名。
const obj = { x: 1 };
// Grabs obj.x as { x }
const { x } = obj;
// Grabs obj.x as as { otherName }
const { x: otherName } = obj;
六、设置函数必传参数
借助ES6支持的默认参数特性,我们可以将默认参数设置为一个执行抛出异常代码函数返回的值,这样当我们没有传参时就会抛出异常终止后面的代码运行。
const isRequired = () => { throw new Error('param is required'); };
const hello = (name = isRequired()) => { console.log(`hello ${name}`) };
// This will throw an error because no name is provided
hello();
// This will also throw an error
hello(undefined);
// These are good!
hello(null);
hello('David');