下面整理了一些js开发常用的小技巧以及一些细节,它们你可能知道也可能不知道或者忘记,没事就当做一次整理了,后面会补充的;没有顺序之分,可以跳着看,会持续补充~~~
一,数值型
求数字数组最小值
let list = [1,2,3]
let min = Math.min(...list) // 1
数值精度问题
所有利用IEEE754
标准的64
位双精度浮点数存储数值型的语言都有这个问题(如:Python),会出现:
console.log(0.1 + 0.2) // 0.30000000000000004
console.log(0.7 + 0.1) // 0.7999999999999999
// ......
原因可以看这个:www.lizenghai.com/archives/35…
可以这样解决
parseFloat((0.1 + 0.2).toFixed(1)) // 0.3
parseFloat((0.7 + 0.1).toFixed(1)) // 0.8
获取当前时间戳
由于+
单元运算符会发生往数字型的类型转换,所以可以这样获取时间戳
+new Date()
/*
此外还有:
new Date() * 1
new Date().getTime()
Date.now()
*/
二,字符型
字符串倒序
字符串倒序就是把字符串倒着排序,可以用下列方法.split('').reverse().join('')
let str = 'abc'
let revStr = str.split('').reverse().join('')
console.log(revStr) // cba
三,数值,字符,布尔
由于这三者都存在字面量,且有自己的数据类型,不像正则的字面量属于对象型,所以它们有些特别要注意的地方
构造函数
它们都有自己的构造函数,且这些构造函数构造的实例都属于对象
typeof new Number(1) // "object"
typeof new String('hello') // "object"
typeof new Boolean(true) // "object"
想要查看它们的字面量的值需要使用valueOf
方法
new Number(1).valueOf() // 1
new String('hello').valueOf() // hello
new Boolean(true).valueOf() // true
四,数组
创建定长的空数组
可能有人认为直接用new Array()
,但是这样创建出来并不是你想的那样是几个undefined
或者null
,如:
let emptyList = new Array(3)
console.log(emptyList)
这个打印出来啥呢?在不同浏览器是不同的,
- 谷歌
[empty × 3]
- 火狐
Array(3) [ undefined, undefined, undefined ]
不要相信火狐显示的那样,其实里面只有length:3
没有那三个undefined
。
我们得用.fill()
方法才可以达到目的
let emptyList1 = new Array(3).fill()
console.log(emptyList1)
// [undefined, undefined, undefined]
// or
let emptyList2 = new Array(3).fill(null)
console.log(emptyList2)
// [null, null, null]
或者
let emptyList = Array.apply(null, { length:3 })
console.log(emptyList)
// [undefined, undefined, undefined]
或者
let emptyList = Array.from({ length:3 })
console.log(emptyList)
// [undefined, undefined, undefined]
捣乱数组顺序
let arr = [1,2,3,4,5]
Array.prototype.shuffle = function() {
this.sort(function () {
return Math.random() - 0.5
})
}
arr.shuffle()
console.log(arr) // [4, 1, 2, 3, 5]
边遍历数组,边增加数组
下面这个做法用for
不行,
let arr = [1,1]
for(let i in arr) {
arr.push(1)
}
// 结果 arr = [1, 1, 1, 1]
并不会无限制地遍历下去,需要这样的操作需要用while
let arr = [1,1]
while(arr.length < 10){ // 让arr的长度为10就跳出
arr.push(1)
}
// 结果 arr = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
数组拼接
let ls1 = [1,2]
let ls2 = [3,4]
// 第一种
let ls3 = ls1.concat(ls2)
// 第二种
let ls4 = [...ls1, ...ls2]
数组降维
let arr = [[1,2],[3,4]]
// 1
function flatten1(arr) {
return [].concat.apply([], arr)
}
// 2
function flatten2(arr) {
return arr.flat()
}
伪数组转真数组
如下所示的,就是一个伪数组
var arrLike = {
length:2,
0:'foo',
1: 'bar'
}
它不能调用Array.prototype
上面的方法,需要为其转化为真数组
1,用ES6的Array.from
var arrLike = {
length:2,
0:'foo',
1: 'bar'
}
var arr = Array.from(arrLike) // ["foo", "bar"]
2,Array.prototype.slice.call
var arrLike = {
length:2,
0:'foo',
1: 'bar'
}
var arr = Array.prototype.slice.call(arrLike) // ["foo", "bar"]
数组浅拷贝
先看下这个例子:
let ls1 = [1,2,3]
let ls2 = ls1
let ls3 = [1,2,3]
console.log(ls2 === ls1) // true
console.log(ls3 === ls1) // false
console.log(ls3 === ls2) // false
这是由于ls2
是ls1
的浅拷贝,拷贝的是变量,而不是值,ls1
和ls2
都指向同一块堆内存,所以为true
,而ls3
新开了一块堆内存,所以和另外两个比都为false
;
了解了什么是浅拷贝之后,接下看看怎么方便地进行深拷贝
1,利用slice()
方法
let ls1 = [1,2,3]
let ls2 = ls1.slice()
console.log(ls2 === ls1) // false
2,利用Array.from
方法
let ls1 = [1,2,3]
let ls2 = Array.from(ls1)
console.log(ls2 === ls1) // false
3,利用map()
方法
let ls1 = [1,2,3]
let ls2 = ls1.map(i=>i)
console.log(ls2 === ls1) // false
4,利用filter()
方法
let ls1 = [1,2,3]
let ls2 = ls1.filter(_=>true)
console.log(ls2 === ls1) // false
5,利用values()
方法
let ls1 = [1,2,3]
let ls2 = [...ls1.values()]
console.log(ls2 === ls1) // false
6,利用Symbol.iterator
方法
let ls1 = [1,2,3]
let ls2 = [...ls1[Symbol.iterator]()]
console.log(ls2 === ls1) // false
注意以上这些方法拷贝的只是最外层的数组,如果数组里面有数组或者对象,那些是不会被深拷贝的,所以这些方法只适用于简单的数组
查找对象在数组里的index
利用findIndex
方法
let arr = [
{
name: '小明'
},
{
name: '小红'
}
]
let index = arr.findIndex(item => {
return item.name === '小明'
})
// index 为 0
判斷某個值是否在數組裏面
注意:不能使用in
關鍵字來判斷,例如:
let arr = ['a', 'b', 'c']
console.log( 'b' in arr ) // false
console.log(0 in arr) // true
in
判斷的是索引有沒有在數組裏
计算对象数组里面某个属性的合计
let carts = [{ num:1 }, { num:2 }]
let total = carts.reduce((s, o) => s+o.num, 0) // 3
五,对象
对象浅拷贝
1,用Object.assign()
let obj1 = { key:'value' }
let obj2 = Object.assign({}, obj1)
console.log(obj1 === obj2) // false
但注意不能像下面这样用
let obj1 = { key:'value' }
let obj2 = Object.assign(obj1, {})
console.log(obj1 === obj2) // true
2,通过解构赋值
let obj1 = { key: 'value' }
let obj2 = { ...obj1 }
console.log(obj1 === obj2) // false
以上方法只针对简单的对象,如果对象里面嵌套对象,函数,或者数组,则不行
对象深拷贝
1,用JSON.parse(JSON.stringify())
let obj1 = { key:'value' }
let obj2 = JSON.parse(JSON.stringify(obj1))
console.log(obj1 === obj2) // false
美化对象的输出
我们平时在开发的时候,常常需要输出我们的数据,数据如果是一些比较复杂的对象的话,输出是木有换行的看起来不舒服,可以用下面这个方法美化输出
console.log(JSON.stringify(obj, null, " "))
// or
console.log(JSON.stringify(obj, null, " "))
获取对象的所有键
Reflect.ownKeys()
这里说的对象的概念是JS里最本质的对象,就是包括数组,函数,正则等等;我们想获取对象上面的所有属性时,不可以用Object.keys()
, 因为这东西对于数组,函数,正则这些是拿不到上面的key的;
Object.keys([]) // []
Object.keys(()=>{}) // []
Object.keys(/hello/) // []
// 都是[]说明没有拿到key
可以利用Reflect.ownKeys()
这个方法来获取对象的所有键组成的一个数组,和Object.keys()
不同的是,这个方法会把Symbol
属性也给获取到,并且对于数组,函数,正则都可以拿到
Reflect.ownKeys([]) // ["length"]
Reflect.ownKeys(()=>{}) // ["length", "name"]
Reflect.ownKeys(/hello/) // ["lastIndex"]
六,函数
在函数里使用参数数组
在函数里想获取参数数组,之前是在函数里使用arguments
,这种做法获取的是一个假数组,而且不被推荐,我们可以使用ES6的解构来代替
function fun(...arg) {
console.log(arg)
}
fun(1,2,3) // [1,2,3]
获取函数形参个数
function fn(a,b,c) {};
fn.length // 3
七,其他
判断js的数据类型
function getType(x){
return Object.prototype.toString.call(x).slice(8,-1)
}
基本上可以把所有构造函数都打印出来
判断某个变量是不是某个类型
这个判断看起来不那么精准,其实不是这样的
({}) instanceof Object //true
[] instanceof Array // true
/.*/ instanceof RegExp // true
new Date() instanceof Date // true
(function(){}) instanceof Function // true
注意,他们其实都是属于对象
[] instanceof Object // true
/.*/ instanceof Object // true
new Date() instanceof Object // true
(function(){}) instanceof Object // true
再注意
'hello' instanceof Object // false
'hello' instanceof String // false
new String('hello') instanceof String // true
new String('hello') instanceof Object // true
Number,Boolean也是如此
出现以上的原因是因为
instanceof
是以原型链来判断的,原型链只会出现在对象里,所以不是对象的Number
,String
,Boolean
的字面量在instanceof Object
时都为false
两个变量交换赋值
let a = 2
let b = 3
[a,b] = [b,a]
console.log(a,b) // 3 2
随机验证码
1,四位数字
Math.random().toString().slice(2,6)
// or
(Math.random() * 9999).toFixed()
// or
Math.random().toFixed(4).slice(-4)
2,四位数字加字母
Math.random().toString(16).slice(2,6).toUpperCase()