使用Javascirpt的一些小技巧
陣列
先來羅列陣列操作中,常用的一些小技巧。
陣列去重
在ES6中,你首先想到的應該是使用
new Set()
來過濾掉陣列中重複的值。但該方法並不適合處理非基本型別的陣列。
const
array
=
[
1
,
1
,
2
,
3
,
5
,
5
,
1
]
const
uniqueArray
=
[。。。
newSet
(
array
)]
console
。
log
(
uniqueArray
)
>
Result
:
(
4
)
[
1
,
2
,
3
,
5
]
該技巧適用於包含基本型別的陣列:
undefined
、
null
、
boolean
、
string
和
number
。如果陣列中包含了一個
object
,
function
或其他陣列,那就需要使用其他方法。
除了上面的方法之外,還可以使用
Array。from(new Set())
來實現:
const array = [1, 1, 2, 3, 5, 5, 1]
Array。from(new Set(array))
> Result:(4) [1, 2, 3, 5]
另外,還可以使用
Array
的
。filter
及
indexOf()
來實現:
const array = [1, 1, 2, 3, 5, 5, 1]
array。filter((arr, index) => array。indexOf(arr) === index)
> Result:(4) [1, 2, 3, 5]
注意,
indexOf()
方法將返回陣列中第一個出現的陣列項。這就是為什麼我們可以在每次迭代中將
indexOf()
方法返回的索引與當索索引進行比較,以確定當前項是否重複。
確保陣列的長度
在處理網格結構時,如果原始資料每行的長度不相等,就需要重新建立該資料。為了確保每行的資料長度相等,可以使用
Array。fill
來處理:
let array = Array(5)。fill(‘’)
console。log(array);
> Result: (5) [“”, “”, “”, “”, “”]
陣列截斷
如果你想從陣列末尾刪除值(刪除陣列中的最後一項),有比使用
splice()
更快的替代方法。
例如,你知道原始陣列的大小,可以重新定義陣列的
length
屬性的值,就可以實現從陣列末尾刪除值:
let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console。log(array。length)
> Result: 10
array。length = 4
console。log(array)
> Result: (4) [0, 1, 2, 3]
這是一個特別簡潔的解決方案。但是,
slice()
方法執行更快,效能更好:
let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
array = array。slice(0, 4)
console。log(array)
> Result: [0, 1, 2, 3]
過濾掉陣列中的falsy值
如果你想過濾陣列中的
falsy
值,比如
0
、
undefined
、
null
、
false
,那麼可以透過
map
和
filter
方法實現:
const array = [0, 1, ‘0’, ‘1’, undefined, true, false, null, ‘undefined’, ‘null’, NaN, ‘NaN’, ‘1’ + 0]
array。map(item => {
return item
})。filter(Boolean)
> Result: (10) [1, “0”, “1”, true, “undefined”, “null”, “NaN”, “10”]
獲取陣列的最後一項
陣列的
slice()
取值為正值時,從陣列的開始處擷取陣列的項,如果取值為負整數時,可以從陣列末屬開始獲取陣列項。
let array = [1, 2, 3, 4, 5, 6, 7]
const firstArrayVal = array。slice(0, 1)
> Result: [1]
const lastArrayVal = array。slice(-1)
> Result: [7]
console。log(array。slice(1))
> Result: (6) [2, 3, 4, 5, 6, 7]
console。log(array。slice(array。length))
> Result: []
正如上面示例所示,使用
array。slice(-1)
獲取陣列的最後一項。
過濾並排序字串列表
你可能有一個很多名字組成的列表,需要過濾掉重複的名字並按字母表將其排序。
在例子裡準備用不同版本語言的JavaScript 保留字的列表,但是你能發現,有很多重複的關鍵字而且它們並沒有按字母表順序排列。所以這是一個完美的字串列表(陣列)來測試。
const
keywords
=
[
‘do’
,
‘if’
,
‘in’
,
‘for’
,
‘new’
,
‘try’
,
‘var’
,
‘case’
,
‘else’
,
‘enum’
,
‘null’
,
‘this’
,
‘true’
,
‘void’
,
‘with’
,
‘break’
,
‘catch’
,
‘class’
,
‘const’
,
‘false’
,
‘super’
,
‘throw’
,
‘while’
,
‘delete’
,
‘export’
,
‘import’
,
‘return’
,
‘switch’
,
‘typeof’
,
‘default’
,
‘extends’
,
‘finally’
,
‘continue’
,
‘debugger’
,
‘function’
,
‘do’
,
‘if’
,
‘in’
,
‘for’
,
‘int’
,
‘new’
,
‘try’
,
‘var’
,
‘byte’
,
‘case’
,
‘char’
,
‘else’
,
‘enum’
,
‘goto’
,
‘long’
,
‘null’
,
‘this’
,
‘true’
,
‘void’
,
‘with’
,
‘break’
,
‘catch’
,
‘class’
,
‘const’
,
‘false’
,
‘final’
,
‘float’
,
‘short’
,
‘super’
,
‘throw’
,
‘while’
,
‘delete’
,
‘double’
,
‘export’
,
‘import’
,
‘native’
,
‘public’
,
‘return’
,
‘static’
,
‘switch’
,
‘throws’
,
‘typeof’
,
‘boolean’
,
‘default’
,
‘extends’
,
‘finally’
,
‘package’
,
‘private’
,
‘abstract’
,
‘continue’
,
‘debugger’
,
‘function’
,
‘volatile’
,
‘interface’
,
‘protected’
,
‘transient’
,
‘implements’
,
‘instanceof’
,
‘synchronized’
,
‘do’
,
‘if’
,
‘in’
,
‘for’
,
‘let’
,
‘new’
,
‘try’
,
‘var’
,
‘case’
,
‘else’
,
‘enum’
,
‘eval’
,
‘null’
,
‘this’
,
‘true’
,
‘void’
,
‘with’
,
‘break’
,
‘catch’
,
‘class’
,
‘const’
,
‘false’
,
‘super’
,
‘throw’
,
‘while’
,
‘yield’
,
‘delete’
,
‘export’
,
‘import’
,
‘public’
,
‘return’
,
‘static’
,
‘switch’
,
‘typeof’
,
‘default’
,
‘extends’
,
‘finally’
,
‘package’
,
‘private’
,
‘continue’
,
‘debugger’
,
‘function’
,
‘arguments’
,
‘interface’
,
‘protected’
,
‘implements’
,
‘instanceof’
,
‘do’
,
‘if’
,
‘in’
,
‘for’
,
‘let’
,
‘new’
,
‘try’
,
‘var’
,
‘case’
,
‘else’
,
‘enum’
,
‘eval’
,
‘null’
,
‘this’
,
‘true’
,
‘void’
,
‘with’
,
‘await’
,
‘break’
,
‘catch’
,
‘class’
,
‘const’
,
‘false’
,
‘super’
,
‘throw’
,
‘while’
,
‘yield’
,
‘delete’
,
‘export’
,
‘import’
,
‘public’
,
‘return’
,
‘static’
,
‘switch’
,
‘typeof’
,
‘default’
,
‘extends’
,
‘finally’
,
‘package’
,
‘private’
,
‘continue’
,
‘debugger’
,
‘function’
,
‘arguments’
,
‘interface’
,
‘protected’
,
‘implements’
,
‘instanceof’
]
因為我們不想改變我們的原始列表,所以我們準備用高階函式叫做
filter
,它將基於我們傳遞的回撥方法返回一個新的過濾後的陣列。回撥方法將比較當前關鍵字在原始列表裡的索引和新列表中的索引,僅當索引匹配時將當前關鍵字push到新陣列。
最後我們準備使用
sort
方法排序過濾後的列表,sort只接受一個比較方法作為引數,並返回按字母表排序後的列表。
在ES6下使用箭頭函式看起來更簡單:
const filteredAndSortedKeywords = keywords
。filter((keyword, index) => keywords。lastIndexOf(keyword) === index)
。sort((a, b) => a < b ? -1 : 1)
這是最後過濾和排序後的JavaScript保留字列表:
console
。
log
(
filteredAndSortedKeywords
)
>
Result
:
[
‘abstract’
,
‘arguments’
,
‘await’
,
‘boolean’
,
‘break’
,
‘byte’
,
‘case’
,
‘catch’
,
‘char’
,
‘class’
,
‘const’
,
‘continue’
,
‘debugger’
,
‘default’
,
‘delete’
,
‘do’
,
‘double’
,
‘else’
,
‘enum’
,
‘eval’
,
‘export’
,
‘extends’
,
‘false’
,
‘final’
,
‘finally’
,
‘float’
,
‘for’
,
‘function’
,
‘goto’
,
‘if’
,
‘implements’
,
‘import’
,
‘in’
,
‘instanceof’
,
‘int’
,
‘interface’
,
‘let’
,
‘long’
,
‘native’
,
‘new’
,
‘null’
,
‘package’
,
‘private’
,
‘protected’
,
‘public’
,
‘return’
,
‘short’
,
‘static’
,
‘super’
,
‘switch’
,
‘synchronized’
,
‘this’
,
‘throw’
,
‘throws’
,
‘transient’
,
‘true’
,
‘try’
,
‘typeof’
,
‘var’
,
‘void’
,
‘volatile’
,
‘while’
,
‘with’
,
‘yield’
]
清空陣列
如果你定義了一個數組,然後你想清空它。 通常,你會這樣做:
let array = [1, 2, 3, 4];
function emptyArray() {
array = [];
}
emptyArray();
但是,這有一個效率更高的方法來清空陣列。 你可以這樣寫:
let array = [1, 2, 3, 4]
function emptyArray() {
array。length = 0
}
emptyArray()
拍平多維陣列
使用
。。。
運算子,將多維陣列拍平:
const
arr
=
[
1
,
[
2
,
‘a’
],
3
,
[
‘b’
,
‘1’
,
2
,
3
]]
const
flatArray
=
[]。
concat
(。。。
arr
)
console
。
log
(
flatArray
)
>
Result
:
(
8
)
[
1
,
2
,
“a”
,
3
,
“b”
,
“1”
,
2
,
3
]
不過上面的方法只適用於二維陣列。不過透過遞迴呼叫,可以使用它適用於二維以下的陣列:
function
flattenArray
(
arr
)
{
const
flattened
=
[]。
concat
(。。。
arr
);
return
flattened
。
some
(
item
=>
Array
。
isArray
(
item
))
?
flattenArray
(
flattened
)
:
flattened
}
const
array
=
[
1
,
[
2
,
‘大漠’
],
3
,
[[
‘blog’
,
‘1’
],
2
,
3
]]
const
flatArr
=
flattenArray
(
array
)
console
。
log
(
flatArr
)
>
Result
:
(
8
)
[
1
,
2
,
“大漠”
,
3
,
“blog”
,
“1”
,
2
,
3
]
也可以使用Generator 函式,使用yield*遞迴遍歷陣列,最後利用Generator 與 Iterator 介面的關係,生成拍平後新的函式。(Generator 函式就是遍歷器生成函式,因此可以把 Generator 賦值給物件的
Symbol。iterator
屬性,從而使得該物件具有 Iterator 介面。)
function
flatten
(
arr
)
{
function
*
gen
(
arr
)
{
if
(
Array
。
isArray
(
arr
))
{
for
(
const
item
of
arr
)
{
yield
*
gen
(
item
)
}
}
else
{
yield
arr
}
}
return
Array
。
from
(
gen
(
arr
))
}
let
arr
=
[[[
1
,
2
],
3
,
[
4
,
5
],
6
,
[
7
]],
8
]
console
。
log
(
flatten
(
arr
))
>
Result
:
(
8
)
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
Array。from
方法可以將兩類物件轉為真正的陣列:類似陣列的物件(array-like object)和可遍歷(iterable)的物件。因此直接傳入Generator,即可生成新的陣列。
Array。prototype。flat()
用於將巢狀的陣列“拉平”,變成一維的陣列。該方法返回一個新陣列,對原資料沒有影響。
[
1
,
2
,
[
3
,
4
]]。
flat
()
>
Result
:
(
4
)
[
1
,
2
,
3
,
4
]
上面程式碼中,原陣列的成員裡面有一個數組,
flat()
方法將子陣列的成員取出來,新增在原來的位置。
flat()
預設只會“拉平”一層,如果想要“拉平”多層的巢狀陣列,可以將
flat()
方法的引數寫成一個整數,表示想要拉平的層數,預設為1。
[1, 2, [3, [4, 5]]]。flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]]。flat(2)
// [1, 2, 3, 4, 5]
上面程式碼中,
flat()
的引數為2,表示要“拉平”兩層的巢狀陣列。
如果不管有多少層巢狀,都要轉成一維陣列,可以用
Infinity
關鍵字作為引數。
[1, [2, [3]]]。flat(Infinity)
// [1, 2, 3]
從陣列中獲取最大值和最小值
可以使用
Math。max
和
Math。min
取出陣列中的最大小值和最小值:
const
numbers
=
[
1
,
2
,
3
,
4
]
Math
。
max
(。。。
numbers
)
>
Result
:
4
Math
。
min
(。。。
numbers
)
>
Result
:
1
物件
使用...拓展運算符合並物件或陣列中的物件
同樣使用ES6的
。。。
運算子可以替代人工操作,合併物件或者合併陣列中的物件。
// 合併物件
const
obj1
=
{
name
:
‘name1’
,
url
:
‘w3c。com’
}
const
obj2
=
{
name
:
‘name2’
,
age
:
30
}
const
mergingObj
=
{。。。
obj1
,
。。。
obj2
}
>
Result
:
{
name
:
“name2”
,
url
:
“w3c。com”
,
age
:
30
}
// 合併陣列中的物件
const
array
=
[
{
name
:
‘David’
,
:
‘david@w3c。com’
},
{
name
:
‘Airen’
,
:
‘airen@w3c。com’
}
]
const
result
=
array
。
reduce
((
accumulator
,
item
)
=>
{
return
{
。。。
accumulator
,
[
item
。
name
]
:
item
。
}
},
{})
>
Result
:
{
David
:
“david@w3c。com”
,
Airen
:
“airen@w3c。com”
}
需要注意的時,用
。。。
拓展運算合併後的結果,是對原始物件的淺複製。原始物件為引用物件時,修改原始物件或合併後的物件,都會同時修改兩邊的結果。
有條件的新增物件屬性
不再需要根據一個條件建立兩個不同的物件,以使它具有特定的屬性。為此,使用
。。。
運算子是最簡單的。
const getUser = (emailIncluded) => {
return {
name: ‘David’,
blog: ‘w3c’,
。。。emailIncluded && {email: ‘david@w3c。com’}
}
}
const user = getUser(true)
console。log(user)
> Result: {name: “David”, blog: “w3c”, email: “david@w3c。com”}
const userWithoutEmail = getUser(false)
console。log(userWithoutEmail)
> Result: {name: “David”, blog: “w3c”}
判斷物件的資料型別
使用
Object。prototype。toString
配合閉包來實現物件資料型別的判斷:
const isType = type => target => `[object ${type}]` === Object。prototype。toString。call(target)
const isArray = isType(‘Array’)([1, 2, 3])
console。log(isArray)
> Result: true
或者:
const isType = type => target => `[object ${type}]` === Object。prototype。toString。call(target)
const isString = isType(‘String’)
const res = isString((‘1’))
console。log(res)
> Result: true
檢查某物件是否有某屬性
當你需要檢查某屬性是否存在於一個物件,你可能會這樣做:
var obj = {
name: ‘David’
};
if (obj。name) {
console。log(true) // > Result: true
}
這是可以的,但是你需要知道有兩種原生方法可以解決此類問題。
in
運算子 和
Object。hasOwnProperty
,任何繼承自
Object
的物件都可以使用這兩種方法。
var obj = {
name: ‘David’
};
obj。hasOwnProperty(‘name’); // > true
‘name’ in obj; // > true
obj。hasOwnProperty(‘valueOf’); // > false, valueOf 繼承自原型鏈
‘valueOf’ in obj; // > true
兩者檢查屬性的深度不同,換言之
hasOwnProperty
只在本身有此屬性時返回
true
,而
in
運算子不區分屬性來自於本身或繼承自原型鏈。
這是另一個例子:
var
myFunc
=
function
()
{
this
。
name
=
‘David’
;
};
myFunc
。
prototype
。
age
=
‘10 days’
;
var
user
=
new
myFunc
();
user
。
hasOwnProperty
(
‘name’
);
>
Result
:
true
user
。
hasOwnProperty
(
‘age’
);
>
Result
:
false
,
因為age來自於原型鏈
補充:現在,你也可以使用Reflect。has()來檢查。
Reflect。has
方法對應
name in obj
裡面的
in
運算子。
var obj = {
name: ‘David’
};
// 舊寫法
‘name’ in obj // true
// 新寫法
Reflect。has(obj, ‘name’) // true
如果
Reflect。has()
方法的第一個引數不是物件,將會報錯。
創造一個純物件
使用
Object。create(null)
可以建立一個純物件,它不會從
Object
類繼承任何方法(例如:建構函式、
toString()
等):
const
pureObject
=
Object
。
create
(
null
);
console
。
log
(
pureObject
);
//=> {}
console
。
log
(
pureObject
。
constructor
);
//=> undefined
console
。
log
(
pureObject
。
toString
);
//=> undefined
console
。
log
(
pureObject
。
hasOwnProperty
);
//=> undefined
資料型別轉換
JavaScript中資料型別有
Number
、
String
、
Boolean
、
Object
、
Array
和
Function
等,在實際使用時會碰到資料型別的轉換。在轉換資料型別時也有一些小技巧。
轉換為布林值
布林值除了
true
和
false
之外,JavaScript還可以將所有其他值視為“
真實的
”或“
虛假的
”。除非另有定義,JavaScript中除了
0
、
‘’
、
null
、
undefined
、
NaN
和
false
之外的值都是
真實的
。
我們可以很容易地在真和假之間使用
!
運算子進行切換,它也會將型別轉換為
Boolean
。比如:
const isTrue = !0;
const isFasle = !1;
const isFasle = !!0 // !0 => true,true的反即是false
console。log(isTrue)
> Result: true
console。log(typeof isTrue)
> Result: ‘boolean’
這種型別的轉換在條件語句中非常方便,比如將
!1
當作
false
。
轉換為字串
我們可以使用運算子
+
後緊跟一組空的引號
‘’
快速地將數字或布林值轉為字串:
const val = 1 + ‘’
const val2 = false + ‘’
console。log(val)
> Result: “1”
console。log(typeof val)
> Result: “string”
console。log(val2)
> Result: “false”
console。log(typeof val2)
> Result: “string”
轉換為數值
上面我們看到了,使用
+
緊跟一個空的字串
‘’
就可以將數值轉換為字串。相反的,使用加法運算子
+
可以快速實現相反的效果。
let int = ‘12’
int = +int
console。log(int)
> Result: 12
console。log(typeof int)
> Result: ‘number’
用同樣的方法可以將布林值轉換為數值:
console。log(+true)
> Return: 1
console。log(+false)
> Return: 0
在某些上下文中,
+
會被解釋為
連線運算子
,而不是
加法
運算子。當這種情況發生時,希望返回一個整數,而不是浮點數,那麼可以使用兩個波浪號
~~
。雙波浪號
~~
被稱為
按位不運算子
,它和
-n - 1
等價。例如,
~15 = -16
。這是因為
- (-n - 1) - 1 = n + 1 - 1 = n
。換句話說,
~ - 16 = 15
。
我們也可以使用
~~
將數字字串轉換成整數型:
const int = ~~‘15’
console。log(int)
> Result: 15
console。log(typeof int)
> Result: ‘number’
同樣的,
NOT
運算子也可以用於布林值:
~true = -2
,
~false = -1
。
浮點數轉換為整數
平常都會使用
Math。floor()
、
Math。ceil()
或
Math。round()
將浮點數轉換為整數。在JavaScript中還有一種更快的方法,即使用
|
(位或運算子)將浮點數截斷為整數。
console
。
log
(
23。9
|
0
);
>
Result
:
23
console
。
log
(
-
23。9
|
0
);
>
Result
:
-
23
|
的行為取決於處理的是正數還是負數,所以最好只在確定的情況下使用這個快捷方式。
如果
n
是正數,則
n | 0
有效地向下舍入。如果
n
是負數,它有效地四捨五入。更準確的說,該操作刪除小數點後的內容,將浮點數截斷為整數。還可以使用
~~
來獲得相同的舍入效果,如上所述,實際上任何位運算子都會強制浮點數為整數。這些特殊操作之所以有效,是因為一旦強制為整數,值就保持不變。
|
還可以用於從整數的末尾刪除任意數量的數字。這意味著我們不需要像下面這樣來轉換型別:
let str = “1553”;
Number(str。substring(0, str。length - 1));
> Result: 155
我們可以像下面這樣使用
|
運算子來替代:
console
。
log
(
1553
/
10
|
0
)
>
Result:
155
console
。
log
(
1553
/
100
|
0
)
>
Result:
15
console
。
log
(
1553
/
1000
|
0
)
>
Result:
1
使用
Math。trunc
方法去除一個數的小數部分,返回整數部分。
Math。trunc(4。1) // 4
Math。trunc(4。9) // 4
Math。trunc(-4。1) // -4
Math。trunc(-4。9) // -4
Math。trunc(-0。1234) // -0
對於非數值,
Math。trunc
內部使用
Number
方法將其先轉為數值。
Math。trunc(‘123。456’) // 123
Math。trunc(true) //1
Math。trunc(false) // 0
Math。trunc(null) // 0
對於空值和無法擷取整數的值,返回
NaN
。
Math。trunc(NaN); // NaN
Math。trunc(‘foo’); // NaN
Math。trunc(); // NaN
Math。trunc(undefined) // NaN
使用!!運算子轉換布林值
有時候我們需要對一個變數查檢其是否存在或者檢查值是否有一個有效值,如果存在就返回
true
值。為了做這樣的驗證,我們可以使用
!!
運算子來實現是非常的方便與簡單。對於變數可以使用
!!variable
做檢測,只要變數的值為:
0
、
null
、
“ ”
、
undefined
或者
NaN
都將返回的是
false
,反之返回的是
true
。比如下面的示例:
function
Account
(
cash
)
{
this
。
cash
=
cash
;
this
。
hasMoney
=
!!
cash
;
}
var
account
=
new
Account
(
100。50
);
console
。
log
(
account
。
cash
);
>
Result
:
100。50
console
。
log
(
account
。
hasMoney
);
>
Result
:
true
var
emptyAccount
=
new
Account
(
0
);
console
。
log
(
emptyAccount
。
cash
);
>
Result
:
0
console
。
log
(
emptyAccount
。
hasMoney
);
>
Result
:
false
在這個示例中,只要
account。cash
的值大於
0
,那麼
account。hasMoney
返回的值就是
true
。
還可以使用
!!
運算子將
truthy
或
falsy
值轉換為布林值:
!!
“”
// > false
!!
0
// > false
!!
null
// > false
!!
undefined
// > false
!!
NaN
// > false
!!
“hello”
// > true
!!
1
// > true
!!
{}
// > true
!!
[]
// > true
原文參考:
使用JavaScript的一些小技巧_JavaScript, JavaScript技巧 教程_w3cplus