这是一篇测试 FixIt 主题在打印视图表现的测试文章。所有居中的说明文字将不会出现在打印视图。
按 ctrl + P 或者 ⌘ + P 可以打印此页面。
FR: https://lruihao.cn/posts/js-rediscover/
前言
前端框架轮替变化越来越快,JavaScript 也在不断地升级迭代,越来越多的新特性让我们的代码写起来变得简洁有趣。
每隔一段时间就该重新认识一下 JS,这篇文章会介绍 6 种新特性,一起研究一下吧。
数组方法 Some, Every, Find, Filter
共同点:这几个方法都不会改变原始数组。
some
some()
方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试,它返回一个布尔值。
数组中有至少一个元素通过回调函数的测试就会返回 true
,所有元素都没有通过回调函数的测试返回值才会为 false
。
1
arr.some(callback(element[, index[, array]])[, thisArg])
1
2
[ 2 , 5 , 8 , 1 , 4 ]. some ( x => x > 10 ); // false
[ 12 , 5 , 8 , 1 , 4 ]. some ( x => x > 10 ); // true
技巧
some()
不会对空数组进行检测,空数组返回 false
every
助记:every()
和 some()
功能相反
every()
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值。
在这个位置使用 page-break-before
进行了强制分页
如果回调函数的每一次返回都为 truthy 值,返回 true
,否则返回 false
。
1
arr.every(callback(element[, index[, array]])[, thisArg])
1
2
[ 12 , 5 , 8 , 130 , 44 ]. every ( x => x >= 10 ); // false
[ 12 , 54 , 18 , 130 , 44 ]. every ( x => x >= 10 ); // true
技巧
every()
不会对空数组进行检测,空数组返回 true
Find
助记:功能和 some()
类似,some()
返回布尔值,find()
返回找到 的元素
find()
方法返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined
。
1
arr.find(callback[, thisArg])
1
2
3
4
5
6
const array1 = [ 5 , 12 , 8 , 130 , 44 ];
const found = array1 . find ( element => element > 10 );
console . log ( found );
// expected output: 12
filter
助记:如字面意思,它是一个筛子,会筛选出满足条件的元素
filter()
方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
在这个位置使用 page-break-after
进行了强制分页
返回值是一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。
1
var newArray = arr . filter ( callback ( element [, index [, array ]])[, thisArg ])
1
2
3
4
5
6
const words = [ 'spray' , 'limit' , 'elite' , 'exuberant' , 'destruction' , 'present' ];
const result = words . filter ( word => word . length > 6 );
console . log ( result );
// expected output: Array ["exuberant", "destruction", "present"]
使用 Object.hasOwn
替代 in
操作符
有时,我们想知道对象上是否存在某个属性,一般会使用 in
操作符或 obj.hasOwnProperty
,但它们都有各自的缺陷。
in
如果指定的属性位于对象或其原型链中,in
运算符将返回 true
。
1
2
3
4
5
6
7
8
const Person = function ( age ) {
this . age = age
}
Person . prototype . name = 'fatfish'
const p1 = new Person ( 24 )
console . log ( 'age' in p1 ) // true
console . log ( 'name' in p1 ) // true 注意这里
obj.hasOwnProperty
hasOwnProperty
方法会返回一个布尔值,表示对象自身属性 中是否具有对应的值(原型链上的属性不会读取)。
1
2
3
4
5
6
7
8
const Person = function ( age ) {
this . age = age
}
Person . prototype . name = 'fatfish'
const p1 = new Person ( 24 )
console . log ( p1 . hasOwnProperty ( 'age' )) // true
console . log ( p1 . hasOwnProperty ( 'name' )) // fasle 注意这里
在这个位置使用 page-break-after
进行了强制分页
obj.hasOwnProperty
已经可以过滤掉原型链上的属性,但在某些情况下,它还是不安全。
1
2
Object . create ( null ). hasOwnProperty ( 'name' )
// Uncaught TypeError: Object.create(...).hasOwnProperty is not a function
Object.hasOwn
别急,我们可以使用 Object.hasOwn
来避免这两个问题,这比 obj.hasOwnProperty
方法更加方便、安全。
1
2
3
4
5
let object = { age : 24 }
Object . hasOwn ( object , 'age' ) // true
let object3 = Object . create ( null )
Object . hasOwn ( object3 , 'age' ) // false
使用 &Ldquo;#” 声明私有属性
以前,我们一般用 _
表示私有属性,但它并不靠谱,还是会被外部修改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person {
constructor ( name ) {
this . _money = 1
this . name = name
}
get money () {
return this . _money
}
set money ( money ) {
this . _money = money
}
showMoney () {
console . log ( this . _money )
}
}
const p1 = new Person ( 'fatfish' )
console . log ( p1 . money ) // 1
console . log ( p1 . _money ) // 1
p1 . _money = 2 // 依旧可以从外部修改_money 属性,所以这种做法并不安全
console . log ( p1 . money ) // 2
console . log ( p1 . _money ) // 2
在这个位置使用 page-break-after
进行了强制分页
使用 #
实现真正私有属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person {
# money = 1
constructor ( name ) {
this . name = name
}
get money () {
return this . # money
}
set money ( money ) {
this . # money = money
}
showMoney () {
console . log ( this . # money )
}
}
const p1 = new Person ( 'fatfish' )
console . log ( p1 . money ) // 1
// p1.#money = 2 // 没法从外部直接修改
p1 . money = 2
console . log ( p1 . money ) // 2
console . log ( p1 . # money ) // Uncaught SyntaxError: Private field '#money' must be declared in an enclosing class
有用的数字分隔符
可以使用 _
分隔数字,当然也可以用于计算
1
2
3
4
5
6
7
// ✅ 更加易于阅读
const newSixBillion = 6000_000_000
// ❌ 难以阅读
const originSixBillion = 6000000000
console . log ( newSixBillion === originSixBillion )
// expected output: true
1
2
const sum = 1000 + 6000_000_000
// expected output: 6000001000
技巧
另外,我们写时间时,24*60*60*1000
的可读性也是远大于 86400000
的。
在这个位置使用 page-break-after
进行了强制分页
&Ldquo;?.”, &Ldquo;??”, &Ldquo;??=” 的使用
可选链 ?.
以前我们为了简化 if else
,通常会写出这样的代码
1
2
3
4
5
const obj = null
console . log ( obj && obj . name )
const $title = document . querySelector ( '.title' )
const title = $title ? title . innerText : undefined
使用 ?.
简化 &&
和三元运算符
1
2
3
4
5
const obj = null
console . log ( obj ? . name )
const $title = document . querySelector ( '.title' )
const title = $title ? . innerText
空值合并运算符 ??
之前给变量赋默认值时,我们一般会用 ||
来写,比如
1
2
3
4
5
6
7
let foo = 1
let bar = foo || 2
console . log ( bar ) // 1
let foo = 0
let bar = foo || 2
console . log ( bar ) // 2 注意这里
所以,||
有时候并不是很安全,所以我们不得不加判断
1
2
3
let foo = 0
let bar = foo !== undefined ? foo : 2
console . log ( bar ) // 0
在这个位置使用 page-break-after
进行了强制分页
现在使用 ??
可以使代码更加优雅
1
2
3
4
5
6
7
let foo = 1
let bar = foo ?? 2
console . log ( bar ) // 1
let foo = 0
let bar = foo ?? 2
console . log ( bar ) // 0
空值赋值运算符 ??=
1
2
3
4
5
6
7
let foo = 0
foo ??= 2
console . log ( foo ) // 0
let foo = 1
foo ??= 2
console . log ( foo ) // 1
很好理解,这里的 foo ??= 2
等价于 foo = foo ?? 2
在这个位置使用 page-break-after
进行了强制分页
使用 BigInt 支持大数计算
JS 中超过 Number.MAX_SAFE_INTEGER
的数字计算将是不安全的。
Example:
1
2
3
Math . pow ( 2 , 53 ) === Math . pow ( 2 , 53 ) + 1 // true
// Math.pow(2, 53) => 9007199254740992
// Math.pow(2, 53) + 1 => 9007199254740992
使用 BigInt
完全可以避免这个问题
1
2
3
BigInt ( Math . pow ( 2 , 53 )) === BigInt ( Math . pow ( 2 , 53 )) + BigInt ( 1 ) // false
// BigInt(Math.pow(2, 53)) => 9007199254740992n
// BigInt(Math.pow(2, 53)) + BigInt(1) => 9007199254740993n
要创建一个 BigInt,可以在一个整数的末尾添加字符n
,或者调用函数 BigInt()
。
1
2
3
4
5
let foo = BigInt ( 1 ) // 1n
let bar = BigInt ( 2 ) // 2n
console . log ( foo > bar ) // false
console . log ( 1 n > 2 n ) // false
学无止境,与未来的自己共勉