浅谈 javascript 中 箭头函数(=>) 及 (filter) && (indexOf) && (!!~) 的含义

本文详细介绍了JavaScript中的箭头函数、filter方法、indexOf方法以及!!~操作的用法。通过实例展示了如何使用箭头函数改写匿名函数,filter与indexOf结合如何去除数组重复元素,以及如何理解indexOf返回值和!!~的布尔转换及按位取反的原理。文章还提供了相关参考文献以深入学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这段时间在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])
参数:
  1. callback
    用于测试数组的每个元素,返回true保留元素,否则返回false。
    它接受三个参数:
    1. element
      数组中正在处理的当前元素。
    2. index
      数组中正在处理的当前元素的索引。
    3. array
      召唤出滤波器的这个数组。
  2. 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() 在执行过程中会对数组内的元素进行遍历,
而这里面的 srcoldPhotos 里各个元素的值,滤波器(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类似,规则为:

  • falseundefindednull0“”false
  • true1“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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值