这段时间在hexo上看见一种 object.filter(event => !!~array.indexOf(event.item)) 的语法
举个栗子
deleteImage () {
const oldPhotos = [] // 原来的照片数组[]
const oldAlbums = app.globalData.allData.albums // 原来的照片集合[{x1,y1},{x2,y2},{x3,y3}]
for (var i = 0; i < oldAlbums.length; i++) {
oldPhotos[i] = oldAlbums[i].src // 添加原来的照片[x1,x2,x3]
}
const newPhotos = oldPhotos.filter(src => src != IMG_OLD_SRC) // 添加所有不等于IMG_OLD_SRC的照片[x1,x3]
const newAlbums = oldAlbums.filter(albums => !!~newPhotos.indexOf(albums.src)) // 添加新照片集合[{x1,y1},{x3,y3}]
app.globalData.allData.albums = newAlbums // 将新照片集赋值给全局变量
}
1.箭头函数(=>)
首先,我们先改写一下上述代码中的箭头函数,箭头函数相当于匿名函数,并且简化了函数定义。
好比 const newPhotos = oldPhotos.filter(src => src != IMG_OLD_SRC)
这句话,可以写成如下形式:
deleteImage () {
... ...
const newPhotos = this.newPhotos(oldPhotos)
... ...
}
function newPhotos (oldPhotos) {
return oldPhotos.filter(function (src) {
if (src != IMG_OLD_SRC) {
return -1;
}
return 0;
});
}
于是上述代码可以改写成如下形式:
deleteImage () {
const oldPhotos = []
const oldAlbums = app.globalData.allData.albums
for (var i = 0; i < oldAlbums.length; i++) {
oldPhotos[i] = oldAlbums[i].src
}
const newPhotos = this.newPhotos(oldPhotos)
const newAlbums = this.newAlbums(oldAlbums, newPhotos)
app.globalData.allData.albums = newAlbums
}
function newPhotos(oldPhotos) {
return oldPhotos.filter(function (src) {
if (src != IMG_OLD_SRC) {
return -1;
}
return 0;
});
}
function newAlbums(oldAlbums, newPhotos) {
return oldAlbums.filter(function (albums) {
if (!!~newPhotos.indexOf(albums.src)) {
console.log(albums.src)
return -1;
}
return 0;
});
}
2.滤波器(filter)
filter用于把Array的某些元素过滤掉,然后返回剩下的元素。
语法:
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
参数:
- callback
用于测试数组的每个元素,返回true保留元素,否则返回false。
它接受三个参数:- element
数组中正在处理的当前元素。 - index
数组中正在处理的当前元素的索引。 - array
召唤出滤波器的这个数组。
- element
- thisArg
执行回调时用作此值的值。
返回值:包含通过测试的元素的新数组。如果没有元素通过测试,则返回空数组。
依旧拿 const newPhotos = oldPhotos.filter(src => src != IMG_OLD_SRC)
这句话来分析
// oldPhotos = [x1,x2,x3] -> 原来的元素集合
// IMG_OLD_SRC = x2 -> 需要被过滤掉的元素
function newPhotos (oldPhotos) {
return oldPhotos.filter(function (src) {
if (src != IMG_OLD_SRC) {
return -1;
}
return 0;
});
}
/* 不用 filter 来实现相同功能 */
function newPhotos (oldPhotos) {
const newPhotos = []
for(var i = 0; i < oldPhotos.length; i++) {
if (oldPhotos[i] != IMG_OLD_SRC) {
newPhotos.push(oldPhotos[i])
}
}
return newPhotos;
}
由此可见 .filter()
在执行过程中会对数组内的元素进行遍历,
而这里面的 src
为 oldPhotos
里各个元素的值,滤波器(filter)当值为-1(假)时保留;0(真)时不保留。
PS:利用filter结合indexOf,可以巧妙地去除Array的重复元素:
deleteRepElements() {
var newPhotos, oldPhotos = ['x1', 'x2', 'x3', 'x2', 'x3', 'x4'];
newPhotos = oldPhotos.filter(function (element, index, self) {
return self.indexOf(element) === index;
});
console.log(newPhotos)
}
因为indexOf总是返回第一个元素的位置,后续的重复元素位置与indexOf返回的位置不相等,因此被filter滤掉了。
运行结果:
(4) ["x1", "x2", "x3", "x4"]
接下来我们看 const newAlbums = oldAlbums.filter(albums => !!~newPhotos.indexOf(albums.src))
这段代码
3.检索的字符串(indexOf)
indexOf()的意思:查找一个字符串中,第一次出现指定字符串的位置。
语法:
arr.indexOf(searchElement[, fromIndex])
参数:
- searchElement
要在数组中定位查找的元素。 - fromIndex
开始搜索的索引值。如果索引值大于或等于数组的长度,则返回-1,这意味着不会搜索数组。如果提供的索引值是负数,则将其作为从数组末尾开始的偏移量。注意:如果提供的索引为负,则仍然从前面到后面搜索数组。如果提供的索引为0,则将搜索整个数组。默认值:0(搜索整个数组)。
返回值:数组中元素的第一个索引值;如果找不到,则为-1。
于是在 const newAlbums = oldAlbums.filter(albums => !!~newPhotos.indexOf(albums.src))
这段代码中:
newPhotos.indexOf(albums.src)
的值为int
类型- 当
newPhotos
数组里有名字叫albums.src
的元素时,返回值大于等于0 - 当
newPhotos
数组里没有名叫albums.src
的元素时,返回值等于-1
- 当
function newPhotos (oldAlbums, newPhotos) {
return oldAlbums.filter(function (albums) {
console.log("在外面:" + newPhotos.indexOf(albums.src))
if (!!~newPhotos.indexOf(albums.src)) {
console.log("在里面:"+ newPhotos.indexOf(albums.src))
return -1;
}
return 0;
});
}
运行结果:
在外面:0
在里面:0
在外面:-1
在外面:1
在里面:1
4.强制转换为布尔型后加一取反(!!~)
4.1 强制转换为布尔型 (!!)
!!一般用来将后面的表达式转换为布尔型的数据(boolean)
因为javascript是弱类型的语言(变量没有固定的数据类型)所以有时需要强制转换为相应的类型
类似的如:
a = parseInt("1234") //转换为数字
a = "1234" + 0 //转换为数字
b = 1234 + "" //转换为字符串
c = someObject.toString() //将对象转换为字符串
其中:
- 第1种、第4种为显式转换
- 第2种、第3种为隐式转换
布尔型的转换,javascript约定和c类似,规则为:
- false、undefinded、null、0、“” 为
false
- true、1、“somestring”、[Object] 为
true
回来看 newPhotos.indexOf(albums.src)
这句话,
- 当
newPhotos.indexOf(albums.src)
的值不为-1时,需要添加此元素,即在filter中return -1
- 当
newPhotos.indexOf(albums.src)
的值等于-1时,需要过滤此元素,即在filter中return 0
如果是写成 !!newPhotos.indexOf(albums.src)
的话
- 当
newPhotos.indexOf(albums.src)
的值不为0时,添加此元素,即返回值为true
执行if判断
- 当
newPhotos.indexOf(albums.src)
的值等于0时,过滤此元素,即返回值为false
跳过if判断
很显然,if里面只要写成 !!newPhotos.indexOf(albums.src) + 1
就可以达到相同的效果
function newAlbums(oldAlbums, newPhotos) {
return oldAlbums.filter(function (albums) {
if (!!newPhotos.indexOf(albums.src) + 1) {
console.log(albums.src)
return -1;
}
return 0;
});
}
4.2 按位取反 (~)
~是按位取反的意思,表现出来的现象是 ~X = -(X+1)
引用某位评论区大佬的栗子:~1999 = -2000
1999 = [0111 1100 1111]原 = [0111 1100 1111]反 = [0111 1100 1111]补
然后按位取反:
[0111 1100 1111]补 => [1000 0011 0000]补
最后,转换为原码:
[1000 0011 0000]补 =>[1000 0011 0000]补 - 1 = [1000 0010 1111]反 = [1111 1101 0000]原 = -2000
因此:~(-1) = -(-1+1) = 0
于是 !!newPhotos.indexOf(albums.src) + 1
即可以写为 !!~newPhotos.indexOf(albums.src)
至此,object.filter(event => !!~array.indexOf(event.item)) 的语法形式终于看懂个一二了~
参考文献
[1] 按位与(&)按位或(|)按位异或(^)按位取反(~)左移() https://blog.youkuaiyun.com/zhongjling/article/details/8004103
[2] JS按位非( ~ )运算符与 ~~ 运算符的理解分析 https://www.cnblogs.com/moqiutao/p/6275483.html
[3] JS中 === !== || !! 是什么意思 https://zhidao.baidu.com/question/520676431.html
[4] javascript 中 !~ 什么意思 https://www.cnblogs.com/lonny/p/4282055.html
[5] js中!!()的作用 https://blog.youkuaiyun.com/qq_31411389/article/details/70332999