JS常用

55 阅读4分钟

类型判断

基本数据类型

JavaScript基本数据类型有6种:

  • undefined
  • null
  • boolean
  • number
  • string
  • symbol

其中symbol基本数据类型是ES6新增的。它类似于内建对象类,并不是构造函数,因为通过Symbol类生成symbol类型值时不需要new关键字:

const symbol = Symbol()

且每次生成的值都是唯一的:

const symbol1 = Symbol('juejin')
const symbol2 = Symbol('juejin')
console.log(symbol1 == symbol2)  // false

引用数据类型

引用数据类型有3种:

  • object
  • array
  • function

类型判断

主要介绍三种类型判断方法。

typeof

用typeof来判断数据类型,是有很多局限性的。

null属于基本数据类型,但是我们可以测试下用typeof来判断它:

console.log(typeof null) // object

基本类型返回的结果居然成了object引用类型。这应该算是JavaScript设计的一个缺陷了。

还有一点,typeof无法判断数组这种具体的引用类型。

console.log(typeof [1,2,3]) // object

所以:从上面两点来看,typeof返回object时,其实并非一定真的是对象,也可能是null或数组。

instanceof

instanceof是一个运算符,用于检测构造函数的prototype属性是否出现在某个实例对象上的原型链上。

语法是Object instanceof constructor

JavaScript中对象本质上都是原型链模式,即使ES6新增了new关键字来生成新的对象,其实仍是这样。

function Play (like) {
  this.like = like
}
const play = new Play('like')
console.log(play instanceof Play) // true
console.log(play instanceof Object) // true

之所以第二个表达式也是输出true,是因为Object是对象的顶层构造函数,任何对象的instanceof操作都是true。

我们再来验证下typeof刚不足之处。

console.log(null instanceof Object) // false
console.log([] instanceof Object) // true

可以看出,null的执行结果是合理的。而数组仍然是属于对象的一个大类。

但用instanceof是可以验证是否是数组的,只要我们来判断值是否在数据构造函数的原型链上即可。

console.log([] instanceof Array) // true
Object.prototype.toString.call()

每个继承Object的都存在toString方法,如果toString方法没有重写的话,会统一返回[Object type],其中type为值的类型。但当值为非Object类型,则返回的是内容字符串。这就需要我们使用call或apply方法来改变toString的执行上下文。

Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call(null) // [object Null]

数组去重

常用的方法提供3种:

  • indexOf
  • Set
  • Object键值判断

indexOf

用法:

在数组中查找给定元素的第1个下标值,接收2个参数:第1个是给定元素,第2个是开始查找的位置,默认从0开始,如果未找到,则返回-1

[1,2,3,4,5].indexOf(3) // 2
[1,2,3,4,5].indexOf(3, 3) // -1

用法知道了,如何去重呢?

现在给一个数组[2,3,5,12,6,3,8],很明显,数组存在2个3是重复的,那我们用indexOf来去重。

const arr = [2,3,5,12,6,3,8]
let newArr = []
for (let i = 0; i < arr.length; i++) {
  if (newArr.indexOf(arr[i]) === -1) {
    newArr.push(arr[i])
  }
}
console.log(newArr) // [2, 3, 5, 12, 6, 8]

Set

Set是ES6新增的数据结构,里面的元素都不是重复的,并且不会进行隐式转化,就像数字1和字符串'1'对Set来说是两个元素。直接用Set来去重就很简单了。

const arr = [2,3,5,12,6,3,8]
let newArr = []
let set = new Set(arr)
for (let item of set.values()) {
  newArr.push(item)
}
console.log(newArr) // [2, 3, 5, 12, 6, 8]

Object键值判断

这个方法的核心就是通过判断对象的键值是否已经存在,如果存在的话,则说明这个元素已存在,不再需要往对象中加入新的键值了。还是以刚才的数组为例:

const arr = [2,3,5,12,6,3,8]
let newArr = []
let obj = {}
for (let i = 0; i < arr.length; i++) {
  if (!obj[arr[i]]) {
    obj[arr[i]] = true
  }
}
newArr = Object.keys(obj)
console.log(newArr) // [2, 3, 5, 12, 6, 8]

总结

很显然,三种方法都能实现数组的去重操作,但从效率来考量的话,indexOf方法不要遍历数组,并且对每个元素都要执行indexOf查找操作,效率不如set和对象键值判断。

Set作为ES6的新增语法,用起来更简洁,那对于数组去重,优先使用Set来实现。虽然对于数据量不大的数组来说,效率可能差别不大,但如果是海量的数据去重,那时间复杂度就是必须要考虑到的。