第一次面试的过程中,面试官提问我有关Array类型的常见API,当时大脑一懵,没说出几个,深感自己的基础薄弱,又恰巧近期在刷leetcode,在刷题的过程中经常要使用到Array中的api,因此想着系统的整理一下JS里面的应用类型,后期在遇到leetcode的题目时,将其记录在博客相应的位置中。
JS中包含两种不同的数据类型:基本类型值和引用类型值
- 基本类型值有:Undefined、Null、Boolean、Number和String
- 引用类型:Object类型、Array类型、Data类型、RegExp类型、Function类型、基本包装类型、单体内置对象
有关两种数据类型,在之前的第四章《变量、作用域和内存》中提到了两种不同类型的不同。但是本篇博客主要还是总结引用类型的相关知识和常见api,以及自己在项目或leetcode中遇到的问题的总结记录。本着边学习边记录的原则,文章会慢慢的将自己遇到的问题一点一点的记录。
引用类型
引用类型值是保存在内存中的对象。与其他语言不同,JS不允许直接访问内存中的位置。在操作对象的时,实际上是在操作对象的引用而不是实际的对象。
1. Object 类型
有关object类型,从最基本的object的实例创建的两种方法和访问对象的属性,到进阶的面向对象的程序设计需要我们理解原型、原型链等知识。牵扯的东西较多,本身就可以写一篇博客,因此在本篇文章里不再赘述,详情可见我的另外一篇博客Object类型和面向对象的程序设计
2. Array 类型
Array类型是写这篇文章,学习了两个月的前端,在人生第一面中被Array常见的API给问倒了,让我深感自己的前端学习之路还很长,也更加坚定了我夯实自己基础的决心,那么就从这篇文章开始吧!!!
2.1 创建数组
在JS中,数组的每一项可以保存任何类型的数据,也就是说我可以再数组的第一个位置保存字符串,第二个位置保存数值。提到一个类型,首先要想到如何去创建,就如同Object有两种方式创建,一种是使用new操作符,另一种是字面量表示法。这一点上Array和Object是一样的,Array也可以用这两种方法进行创建。
//使用new操作符
var colors = new Array(20)
var colors = new Array("red","blue","green")
//使用字面向量法
var colors = ["red","blue","green"]
var colors = [] //创建一个空数组
除了创建以外,还有数组的调用,我们可以通过下标进行相应的调用。
var colors = ["red","blue","green"]
alert(colors[0]) //显示第一项
colors[2] = "black" //修改第三项
colors[3] = "brown" //新增第四项
2.2 数组的属性——length
数组的length属性返回的是数组的长度,十分注意的一点是length属性不是只读的。
var colors = ["red","blue","green"]
colors.length = 2
alert(colors[2]) //undefined
2.3 检测数组
- instanceof运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
value instanceof Array进行判断,value是数组的话会返回true,否则返回false。
在此区分一下typeof和instanceof
1.typeof的判断范围
未定义的值 --------------- undefined
布尔值 --------------- boolean
字符串 --------------- string
数值 --------------- number
对象或者null --------------- object
函数 --------------- function
- Array.isArray()
Array.isArray(value)进行判断,value是数组的话会返回true,否则返回false。
2.4 转换方法
- valueOf() 返回数组本身
var colors = ["red","blue","green"]
alert(colors.valueOf()) //red,blue,green
- toString() 返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串
var colors = ["red","blue","green"]
alert(colors.toString()) //red,blue,green
alert(colors) //red,blue,green 这里其实alert在后台调用了toString()方法
-
toLocaleString()
toLocaleString()方法返回的值与前面两种方法一直,不同的是,为了取得每一项的值,调用的是每一项的toLocaleString()方法而不是toString()方法。 -
join() 使用不同的分隔符来构建字符串
var colors = ["red","blue","green"]
alert(colors.join("||")) //red||blue||green
这里我的解法是使用一个数组存储s替换空格后的值,再使用join()方法输出字符串。
/**
* @param {string} s
* @return {string}
*/
var replaceSpace = function(s) {
res = []
for (let i = 0; i < s.length; i++) {
if(s[i] === ' '){
res.push('%20')
} else {
res.push(s[i])
}
}
//join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
return res.join('')
};
2.5 栈方法和队列方法
- 栈是一种LIFO(后进先出)的数据结构
- push()方法,接受任意数量的参数,把他们逐个添加到数组的末尾,并返回修改后的数组长度
- pop()方法,移除数组末尾最后一项,减少数组的length值,返回移除的项
- 队列是一种FIFO(先进先出)的数据结构
- push()方法,接受任意数量的参数,把他们逐个添加到数组的末尾,并返回修改后的数组长度
- shift()方法,移除数组中的第一项,同时将数组的长度减一,返回移除项
- unshift()方法,再数组的前端依次添加参数值,返回新数组的长度
剑指offer 09.用两个栈实现队列
队列是先进先出,所以考虑用两个数组来实现,stack1用于将新增的数压入队列的尾部,stack2用于弹出队列的第一项。因为只能使用pop(),所以可以将stack1中的末尾依次弹出,并加入stack2,这样就可以满足stack2弹出的顺序和队列弹出的顺序一致。每次执行弹出操作前先检查stack2中是否为空,若不为空可以直接弹出stack2的顶项,即弹出了队列的第一项。若队列为空,再将stack1中的末项依次弹出并加入stack2,再进行弹出,若stack1中也为空,说明没有项存在数组中,返回-1。
var CQueue = function() {
this.stack1 = []
this.stack2 = []
};
/**
* @param {number} value
* @return {void}
*/
CQueue.prototype.appendTail = function(value) {
this.stack1.push(value)
};
/**
* @return {number}
*/
CQueue.prototype.deleteHead = function() {
if(this.stack2.length) return this.stack2.pop()
while (this.stack1.length) {
this.stack2.push(this.stack1.pop())
}
return this.stack2.pop() || -1
};
2.6 重排序方法
- reverse()方法,反转数组的顺序
- sort()方法,按升序排列数组项——最小值位于最前面,较大值位于最后面。
sort()会调用每个每个数组的toString()方法,然后比较字符串,以确定如何排序。
var values = [0, 1, 5, 10, 15];
values.sort();
alert(values) //0,1,10,15,5
sort()函数可以接受一个比较函数作为参数,以便我们决定哪个数在前面
- 如果第一个参数位于第二个之前,返回负数
- 如果两个参数相等,返回0
- 如果第一个参数位于第二个参数后面,返回正数
function compare(value1,value2) {
return value1 - value2 //升序
}
function compare(value1,value2) {
return value2 - value1 //降序
}
value.sort(compare)
2.7 操作方法
- concat()
- slice()
- splice()
2.8 位置方法
- indexOf()
- lastIndexOf()
2.9 迭代方法
- every()
- filter()
- forEach()
- map()
- some()
2.10 归并方法
- reduce()
- reduceRight()
3. Date 类型
4. RegExp 类型
5. Function 类型
6. 基本包装类型
6.1 Boolean 类型
6.2 Number 类型
6.3 String 类型
7. ES6 新增类型
7.1 Set 类型
此处总结参考为爱心太软JavaScript Set 集合博客
Set类型是一种有序列表,其中含有一些相互独立的非重复值。
- size属性:返回Set 集合的成员总数。
- add(value) 方法:添加某个值,返回 Set 集合本身。
- delete(value)方法:删除某个值,返回一个布尔值,表示删除是否成功。
- has(value) 方法:返回一个布尔值,表示该值是否为Set的成员。
- clear() 方法:清除所有成员,没有返回值。
注意:
1、Set 集合不会添加重复的成员。
2、Set 构造函数可以接受所有可迭代对象作为参数。
这里我们采用双指针的解法,因为我的想法是依次从一个字符串开始计算最长的无重复子串,当从第n个到第n+1个时,第n个的无重复长度必然是第n+1个的无重复长度减一,我们只需要在上次的最后一个字符串继续向后扫描即可,所以可以采用双指针的方法。我们还需要使用一种数据结构来判断是否有重复的字符,常用的数据结构为哈希集合,在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。
var lengthOfLongestSubstring = function(s) {
var set = new Set()
var max = 0
var j = 0
for (let i=0; i<s.length; i++) {
if (i > 0) {
// 左指针右移
set.delete(s[i-1])
}
//当右指针没有到顶,且没在set中遇到相同的字符串时一直给计数器+1
while (j<s.length && !set.has(s[j])) {
set.add(s[j])
j++
}
if (max < j-i) {
max = j - i
}
}
return max
};
7.2 Map类型
此处参考爱笑的小宇宙的js Map对象的用法博客
- clear()方法:从映射中移除所有元素。
- delete()方法:从映射中移除指定的元素。
- forEach()方法:对映射中的每个元素执行指定操作。
- get()方法:返回映射中的指定元素。
- has()方法:如果映射包含指定元素,则返回 true。
- set()方法:添加一个新建元素到映射。
- toString()方法:返回映射的字符串表示形式。
- valueOf()方法:返回指定对象的原始值。
最开始我想到的解法是使用暴力法,但是看了题解后思考到了可以采用哈希表的结构降低时间复杂度,因此了解了Map引用类。我们可以使用Map的下标代表我们已经变量过的数,使用set方法将其在数组中的下标存储进map,使用has方法进行判断是否存在该数,如果找到了符合条件的数可以使用get方法得到下标,因为存储进去的下标肯定处于前方,所以我们将其放在返回数组的前面。
var twoSum = function(nums, target) {
var map = new Map()
for(let i=0; i<nums.length; i++) {
if(map.has(target-nums[i])) {
return [map.get(target-nums[i]), i]
} else {
map.set(nums[i],i)
}
}
}