JS每日一题


# 数组

# 两数之和

题目传送门:两数之和 (opens new window)

题意:在数组中挑两个数,使得target等于两数之和,输出两数的坐标。

方法一:
暴力枚举:

点击查看代码
var twoSum = function(nums, target) {
    for(var i=0;i<nums.length;i++){
        for(var j=i+1;j<nums.length;j++){
            if(nums[i]+nums[j]===target){
                return [i,j];
            }
        }
    }
    return [];
};

方法二:
开一个盒子
将每一个无法与盒子里的数匹配相加得到target的数放到盒子里面;
如果能够匹配,那就直接返回答案就行。

点击查看代码
var twoSum = function(nums, target) {
    let box = {};
    for(let i = 0;i < nums.length; i++)
    {
        if( box[ target - nums[i] ] >= 0){
             return [box[target-nums[i]],i];
        }
        else {
            box[nums[i]] = i;
        }
    }
};

方法三:
用Map来进行维护,思路同方法二

点击查看代码
var twoSum = function(nums, target) {
    let myMap = new Map();
    for(let i=0;i<nums.length;i++)
    {
        if(myMap.get(target-nums[i])>=0){
            return [i,myMap.get(target-nums[i])];
        }else{
            myMap.set(nums[i],i);
        }
    }
};

# 删除有序数组中的重复项

题目传送门:删除有序数组中的重复项
方法一:
运用splice方法,splice(i,j)表示从第i个位置开始,消去j个元素

点击查看代码
var removeDuplicates = function(nums) {
    for(var i=0;i<nums.length;i++)
    {
        if(nums[i]===nums[i+1]){
            nums.splice(i,1);
            i--;
        }
    }
    console.log(nums.length);
    console.log(nums);
};

方法二:
用双指针来写,fa往后面遍历,ch则表示找到几个不同的。

点击查看代码
// 104ms 46.8MB
var removeDuplicates = function(nums) {
    // 第二种方法是使用双指针来写的
    for(var fa = 0,ch=0;fa<nums.length;fa++){
        if(nums[fa]!==nums[ch]){
            ch++;
            nums[ch] = nums[fa];
        }
    }
    nums.splice(ch+1,nums.length-ch);
    console.log(ch);
    console.log(nums);
};

# 数的操作

# 整数反转

题目传送门:整数反转 (opens new window)

方法一:
直接求余法来写(效率会高一些)

点击查看代码
var reverse = function(x) {
    var max = Math.pow(2,31)-1;
    var min = Math.pow(-2,31);
    var ans = 0;
    var f=0;
    if(x<0){
        f=1;
        x=-x;
    }
    while(x>0)
    {
        var b = x % 10;
        ans = ans*10+b;
        // 注意这里和C++不一样,必须要减去b
        x = (x-b) / 10;
    }
    if(ans>max) return 0;
    if(ans<min) return 0;
    if(f===0) return ans;
    else return -ans;
};

方法二:
1.首先把整数的符号取出来
2.由于一个数无法分隔,所以把他变成字符串
3.进行反转
4.然后得到答案(最后要变成整数)

点击查看代码
var reverse = function(x) {
    var max = Math.pow(2,31)-1;
    var min = Math.pow(-2,31);
    var sign = Math.sign(x);

    var ans = x.toString().split("").reverse().join("");
    ans = sign * parseInt(ans);
    if(ans>max) return 0;
    if(ans<min) return 0;
    return ans;
};

# 回文数

题目传送门:回文数 (opens new window)
思路:整数反转简单变形
代码:

点击查看代码
var isPalindrome = function(x) {
    if(x<0) return false;
    var ans = 0;
    var m = x;
    while(x>0)
    {
        var b = x % 10;
        ans = ans*10+b;
        // 注意这里和C++不一样,必须要减去b
        x = (x-b) / 10;
    }
    if(ans===m){
        return true;
    }else{
        return false;
    }
};

# 链表

# 环形链表

  1. 环形链表I
    题目传送门:环形链表I (opens new window)

思路:链表是一个对象,是对象就可以挂载其他的属性,比如挂载一个flag来表示这个走过没有,如果走过了,那很明显,有环,为true;

点击查看代码
var hasCycle = function(head) {
    while(head){
        if(head.flag) return true;
        else{
            head.flag = true;
            head = head.next;
        }
    }
    return false;
};
  1. 环形链表II
    题目传送门:环形链表II (opens new window)

思路:这道题有两种做法,一种是上文中提到的flag标记法,第二种呢是快慢指针

快慢指针做法:
使用快慢指针法来做就很好做
假设:链表的长度为 a + b (环)
fast = 2 * slow & fast = slow + n * b
所以 slow = n * b
当 fast 和 slow 碰面的时候,只需要让slow再走a个步子就可以了。

点击查看代码
var detectCycle = function(head) {
    let slow = head;
    let fast = head;
    while(true){
        if(fast === null || fast.next === null){
            return null;
        }
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast){
            break;
        }
    }
    let newHead = head;
    while(newHead !== slow){
        newHead = newHead.next;
        slow = slow.next;
    }
    return slow;
};

# 字符串

# 最长公共前缀

题目传送门:最长公共前缀 (opens new window)
方法一:
思路:
1.直接遍历数组的所有项,求所有项中个项的最小值。
2.然后暴力枚举,成立就留下,不成立就走。
代码:

点击查看代码
var longestCommonPrefix = function(strs) {
    var s = '';
    var len=300;
    for(var i=0;i<strs.length;i++){
        if(strs[i].length<len) len = strs[i].length;
    }
    var tot = 0;
    for(var i=0;i<=len-1;i++){
        f=1;
        for(var j=0;j<strs.length-1;j++){
            if(strs[j][i]===strs[j+1][i]);
            else f=0;
        }
        if(f===1&&tot===i) {
            s += strs[0][i];
            tot++;
        }
    }
    return s;
};

方法二:
思路:
1.首先得到第一个,然后对每个进行遍历,每次都更新ans的值
2.特判啥都没有的时候直接返回为空。
3.用了substr

// 表示a为obj从i到 j - 1
var a = obj.substr(i,j)

代码:

点击查看代码
var longestCommonPrefix = function(strs) {
    if(strs.length===0) return "";
    var ans = strs[0];
    for(let i=1;i < strs.length;i++){
        let j = 0;
        for(;j<ans.length && j<strs[i].length;j++){
            if(ans[j]!=strs[i][j]) break;
        }
        ans = ans.substr(0,j);
    }
    return ans;
};

# 外星语言是否排序

题目传送门:最长公共前缀 (opens new window)

好用的函数

  1. 复制数组 -> [...arr]
  2. 将数字转化为ascii码的形式 => String.fromCharCode()
  3. 将ascii码转化为数字 => str.charCodeAt()
    思路: 题目不难,需要转换,然后排序比较,如果是转化成数字,则需要考虑大于10的情况,根本不好处理,看一下它给出字典序的范围在0-26,果断用26个字母表的顺循,然后排个序一比较就好了。
点击查看代码
var isAlienSorted = function(words, order) {
    let comPare = []
    for(let i=0;i<words.length;i++){
        let ddd = ""
        for(let j=0;j<words[i].length;j++){
            ddd += String.fromCharCode(order.indexOf(words[i][j]) + 97)
        }
        comPare.push(ddd)
    }
    let newCom = [...comPare]
    newCom.sort()
    for(let i=0;i<newCom.length;i++){
        if(newCom[i]!==comPare[i]){
            return false;
        }
    }
    return true
};

# 二叉树的三种遍历模式

思路:

(1)当你可以使用DFS即递归的时候,你会不自觉的使用栈的思路,
只不过没有必要专门去建一个栈,只需要用递归的思路放进去循环就好了。
(2)当你无法用DFS即递归的思路去解决这个问题的时候,
不妨想一下,能不能用DFS的本质,即栈的思路去解决这个问题!

“二叉树有两种做法,其一为递归,也就是DFS的思路,第二为迭代,也就是栈的思路”

# 前序遍历

root/root.left/root.right

  1. 前序遍历是"root->root.left->root.right"
  2. 递归实现
点击查看代码
var preorderTraversal = function(root) {
    if(!root) return [];
    const res = [];
    function D(root,num = []){
        if(!root) return;
        num.push(root.val);
        D(root.left,num)
        D(root.right,num)
    }
    D(root,res);
    return res;
};
  1. 迭代实现

迭代的思路是基于栈的,比如先序是“根左右”,那我们就先把根存入答案数组,然后把右边的节点入栈,再把左边的节点入栈,这样就可以保证第二个进去的是左值,从而保证了顺序。

点击查看代码
var preorderTraversal = function(root) {
    if(!root) return [];
    const res = [];
    const stack = [];
    stack.push(root);
    while(stack.length){
        let cur = stack.pop();
        res.push(cur.val);
        if(cur.right) stack.push(cur.right);
        if(cur.left) stack.push(cur.left);
    }
    return res;
};

# 中序遍历

root/root.left/root.right

  1. 中序遍历是"root.left->root->root.right"
  2. 递归实现
点击查看代码
var preorderTraversal = function(root) {
    if(!root) return [];
    const res = [];
    function D(root,num = []){
        if(!root) return;
        D(root.left,num)
        num.push(root.val);
        D(root.right,num)
    }
    D(root,res);
    return res;
};
  1. 因为root放在中间,所以实现思路与另外两种还是有很大的不同的。每次到达一个节点,都需要遍历到左边的尽头,然后再向右走。
点击查看代码
var inorderTraversal = function(root) {
    const res = [];
    const stack = [];
    cur = root;
    while(cur||stack.length){
        while(cur){
            stack.push(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        res.push(cur.val);
        cur = cur.right;
    }
    return res;
};

# 后序遍历

root/root.left/root.right

  1. 后序遍历是"root.left->root.right->root"
  2. 递归实现
点击查看代码
var preorderTraversal = function(root) {
    if(!root) return [];
    const res = [];
    function D(root,num = []){
        if(!root) return;
        D(root.left,num)
        D(root.right,num)
        num.push(root.val);
    }
    D(root,res);
    return res;
};
  1. 后序遍历的思路和前序遍历的思路非常类似,因为先序遍历的思路是根左右,而后序遍历的思路是左右根,所以只需要把根放到最后并且改变一下push的顺序就好了。
点击查看代码
var postorderTraversal = function(root) {
    if(!root) return [];
    const res = [];
    const stack = [];
    stack.push(root);
    while(stack.length){
        let cur = stack.pop();
        res.unshift(cur.val);
        if(cur.left) stack.push(cur.left);
        if(cur.right) stack.push(cur.right);
    }
    return res;
};

# 剑指Offer系列刷题

Day1

# 用两个栈实现队列

题目传送门:用两个栈实现队列 (opens new window)
分析:
实现一个队列,有两个功能:
1.从队尾添加元素
2.从队头删除元素
对于第一个要求,直接用stack里面的push就可以了
对于第二个要求,我们需要把第一个栈里的元素一个个拿到第二个栈里面去,这样原本的倒序就变成了顺序,就很好拿了。
图例:

image 代码:

点击查看代码
var CQueue = function() {
    stack1 = [];
    stack2 = [];
};
//栈就是先进后出
//队列则是两边都是通的
/** 
 * @param {number} value
 * @return {void}
 */
CQueue.prototype.appendTail = function(value) {
    stack1.push(value);
};

/**
 * @return {number}
 */
CQueue.prototype.deleteHead = function() {
    if(stack2.length===0){
        while(stack1.length){
           stack2.push(stack1.pop());
        }
    }
    if(stack2.length===0) return -1;
    else return stack2.pop();
};

/**
 * Your CQueue object will be instantiated and called as such:
 * var obj = new CQueue()
 * obj.appendTail(value)
 * var param_2 = obj.deleteHead()
 */

# 包含min函数的栈

题目传送门:包含min函数的栈 (opens new window)
分析:
正常实现一个栈就可以了,先进后出
问题主要是min如何实现
方法一:
我直接暴力了一发,对于每一次求min,都在整个栈中遍历找到最小的。

点击查看代码
/** 240ms 47.8MB
 * initialize your data structure here.
 */
//
var MinStack = function() {
    let mmm = 0x3f3f3f3f3f3f;
    let s = [];
    var idx=0;

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    s[idx] = x;
    idx = idx + 1;
    // if(x<mmm) mmm = x;
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    s[--idx] = null;

};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return s[idx-1];
};

/**
 * @return {number}
 */
MinStack.prototype.min = function() {
    mmm = 0x3f3f3f3f3f3f3f;
    for(var i = 0;i<idx;i++){
        if(mmm>s[i]) mmm = s[i];
    }
    return mmm;
};
};


/**
 * Your MinStack object will be instantiated and called as such:
 * var obj = new MinStack()
 * obj.push(x)
 * obj.pop()
 * var param_3 = obj.top()
 * var param_4 = obj.min()
 */

方法二:
创建另一个栈,专门存最小值,在每一次入栈的时候,都向里面存入栈的最小值。

点击查看代码
// 92ms 49.2MB
/**
 * initialize your data structure here.
 */
var MinStack = function() {
    let mmm = 0x3f3f3f3f3f3f;
    let s = []; 
    let minS = [];
    var idx=0;
    var ddd=0;

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    s[idx] = x;
    idx = idx + 1;
    if(mmm>x){
        minS[ddd]=x;
        ddd = ddd + 1;
        mmm = x;
    }else{
        minS[ddd]=mmm;
        ddd = ddd + 1;
    }
    // if(x<mmm) mmm = x;
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    s[--idx] = null;
    ddd = ddd-1;
    if(ddd>=1) mmm = minS[ddd-1];
    else mmm = 0x3f3f3f3f3f3f;
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return s[idx-1];
};

/**
 * @return {number}
 */
MinStack.prototype.min = function() {
   return minS[ddd-1];
};
};


/**
 * Your MinStack object will be instantiated and called as such:
 * var obj = new MinStack()
 * obj.push(x)
 * obj.pop()
 * var param_3 = obj.top()
 * var param_4 = obj.min()
 */

Day2

# 从尾到头打印链表

题目传送门:从尾到头打印链表 (opens new window) 方法一:
由于我们需要从尾到头打印链表,我们可以首先反着把链表存下来,然后再打印。

点击查看代码
//Ryker 26ms 43.1MB
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {number[]}
 */
var reversePrint = function(head) {
    let listn = [];
    while(head!=null)
    {
        listn.push(head.val);
        head = head.next;
    }
    return listn.reverse();
};

当然,还可以这样写-->

点击查看代码
//Ryker 64ms 43.3MB
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {number[]}
 */
var reversePrint = function(head) {
    let listn = [];
    while(head!=null)
    {
        listn.push(head.val);
        head = head.next;
    }
    let res = [];
    var temp = listn.pop();
    while(temp!=null){
        res.push(temp);
        temp = listn.pop();
    }
    return res;
};

方法二:
可以不断调用递归函数,先输出第一个,然后再逐个倒序输出。

See More
//Ryker 56ms 44.2MB
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {number[]}
 */
var reversePrint = function(head,arr = []) {
    if(head!=null){
        if(head.next!=null){
            reversePrint(head.next,arr);
        }
        arr.push(head.val);
    }
    return arr;
};

# 反转链表

题目传送门:反转链表 (opens new window) 方法:
直接双指针一个表示前,一个表示后
pre更是一个索引,这个数据结构还不是很熟悉。

点击查看代码
//Ryker 60ms 42.9MB
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let perv = null;
    let curr = head;
    while(curr){
        //后一个指向前一个
        const next = curr.next;
        curr.next = perv;
        perv = curr;
        curr = next;
    }
    return perv;
};

# 复杂链表的复制

题目传送门:复杂链表的复制 (opens new window)
思路:这题一开始不会做,没啥思路,看了题解之后才有想法。
1.所谓复杂链表的复制,首先你得复制一个链表,根据原来链表的长度来得到节点的数量
2.进阶的部分就是有一个random,这个肯定不能在同一次循环中来搞,因为有可能random指向的是后面并未创建的节点。
3.综上,需要两个循环,第一个用来创建一个新的链表,第二个用来赋random的值。

点击查看代码
/**
// Ryker 56ms 43MB
 * // Definition for a Node.
 * function Node(val, next, random) {
 *    this.val = val;
 *    this.next = next;
 *    this.random = random;
 * };
 */

/**
 * @param {Node} head
 * @return {Node}
 */
const copyRandomList = head => {
    //首先判断是不是空
    if(!head) return null
    //如果不为空,则需要两个循环,一个先构建好链表,另一个往后面走。
    let map = new Map(),node = new Node(),tem = node,cur = head
    while(cur){
        //给tem赋值
        tem.val = cur.val;
        //如果说还有节点,那就创建节点
        tem.next = cur.next ? new Node():null;
        map.set(cur,tem);
        //往后遍历
        tem = tem.next;
        cur = cur.next;
    }
    tem = node
    while(head){
        tem.random = head.random ? map.get(head.random) : null;
        //往后遍历
        tem = tem.next;
        head = head.next;
    }
    return node
};

Day3

# 替换空格

题目传送门:替换空格 (opens new window)
考察点:
两个函数:join()与splice()
splice():splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组
join():join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

点击查看代码
/**
Ryker 52ms 40.6MB
 * @param {string} s
 * @return {string}
 */
var replaceSpace = function(s) {
    s=s.split(' ').join('%20')
    return s
};

# 左旋转字符串

题目传送门:左旋转字符串 (opens new window)
方法一:
先遍历后面的,再遍历前面的

点击查看代码
/**
 * @param {string} s
 * @param {number} n
 * @return {string}
 */
var reverseLeftWords = function(s, n) {
    let a = [];
    var tot = 0;
    for(var i=n;i<s.length;i++){
        a[tot++] = s[i] 
    }
    for(var i=0;i<n;i++){
        a[tot++] = s[i]
    }
    a = a.join('');
    return a
};

中间部分改改也行

点击查看代码
/**
Ryker 68ms 44.2MB
 * @param {string} s
 * @param {number} n
 * @return {string}
 */
var reverseLeftWords = function(s, n) {
    let a = [];
    for(var i=n;i<s.length;i++){
        a.push(s[i])
    }
    for(var i=0;i<n;i++){
        a.push(s[i])
    }
    a = a.join('');
    return a
};

方法二:
把字符串延长一倍,然后从n开始截取一个长为s.length的字符串

点击查看代码
/**
 * @param {string} s
 * @param {number} n
 * @return {string}
 */
var reverseLeftWords = function(s, n) {
    const len = s.length;
    const k = n % len;
    const double = `${s}${s}`;
    return double.slice(k, k + len);
   
};

Day4

# 数组中的重复数字

题目传送门:数组中的重复数字 (opens new window)
思路:
难度不大,直接sort,sort之后再枚举比较一次。
O(n)的时间复杂度。

点击查看代码
//Ryker 64ms 46.9MB
var findRepeatNumber = function(nums) {
    /*
    下面的两种sort写法都可以
    */
    // nums.sort(function(a,b){
    //     return a-b;
    // });
    nums.sort((a, b) => a - b);
    for(var i=0;i<nums.length;i++){
        if(nums[i]===nums[i+1]){
            return nums[i];
        }
    }
    return 0;
};

# 在排序数组中查找数字I

题目传送门:在排序数组中查找数字I (opens new window)
思路:
way1:暴力枚举

点击查看代码
var search = function(nums, target) {
    var cnt=0;
    for(var i=0;i<nums.length;i++){
        if(nums[i]===target) cnt++;
    }
    return cnt;
};

way2:二分查找
注意:JS中是浮点数,所以二分的时候要注意parseInt()一下,不然就wa了。

点击查看代码(有缺陷)
var search = function(nums, target) {
    var l = 0,r = nums.length;
    var cnt=0;
    while(l<=r){
        var mid = parseInt((l + r) / 2);
        if(nums[mid]>=target) r = mid - 1;
        else l = mid + 1;
    }
    var minn=0;
    if(l>r) minn = r;
    else minn = l;
    for(var i=minn;i<nums.length;i++){
        if(nums[i]===target) cnt++;
        //还是有缺陷,我是找到这个之后再枚举,但是不能限制那个区间。
        // else break;
    }
    return cnt;
};

# 0-n-1中缺失的数字

题目传送门:0-n-1中缺失的数字 (opens new window)
way1数组逐个进行比对:

See More
//Ryker 68ms 43.3MB
var missingNumber = function(nums) {
    var n = nums.length;
    let s = 0,
        num = 0;
    for(var i=0;i<=n;i++){
        if(num != nums[s]){
            return num
        }
        num++;
        s++
    }
};

way2用整数来减去其他项,得到未处理的项数

See More
// Ryker 72ms 43.1MB
var missingNumber = function(nums) {
    //way1:数组求和得到当前需要的值
    var s = 0;
    for(var i=0;i<nums.length;i++){
        s += nums[i]
    }
    var sum = nums.length *(nums.length + 1) / 2;
    return sum - s;
};

Day5

# 旋转数组的最小数字

题目传送门:旋转数组的最小数字 (opens new window)
思路:
二分!但又不是单纯的二分。
由于前面是重复的项,后面是递增的一个数组,所以如果说num[mid]大于num[right],那么不正常,必然交界点在右边,如果说num[mid]小于num[right],那么正常,必然交界在左边。
注意:"parseInt()",是实数的二分!

点击查看代码
 //Ryker 72ms 43.2MB
var minArray = function(numbers) {
    var l = 0 , r = numbers.length - 1;
    while(l < r){
        var mid = parseInt((r + l) / 2)
        if(numbers[mid]>numbers[r]){
            l = mid + 1;
        }
        else if(numbers[mid]<numbers[l]){
            r = mid;
        }
        else{
            r --;
        }
    }
    return numbers[l];
};

# 第一个只出现的一次的字符

题目传送门:第一个只出现的一次的字符 (opens new window)
思路:
如果说第一次出现这个字符和最后一次出现这个字符位置一样,那么就可以了!

点击查看代码
var firstUniqChar = function(s) {
    for(let x of s){
        if(s.indexOf(x) === s.lastIndexOf(x)) return x
    }
    return ' '
};

# 常用函数

# Array.prototype.splice()

# 描述

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

# 1.插入与修改

// 其实插入就是删除0个元素,而修改就是删了之后插入(小声
const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// 在索引为1的位置插入Feb,March右移
// 其实是在索引为1的位置删除0个元素(插入Feb
console.log(months);
//结果: Array ["Jan", "Feb", "March", "April", "June"]

months.splice(4, 1, 'May');
// 在索引为四的位置替换一个元素,替换为'May'
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "May"]

# 2.删除

//1. 从索引为3的位置删除一个元素
var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];
var removed = myFish.splice(3, 1);

// 运算后的 myFish: ["angel", "clown", "drum", "sturgeon"]
// 被删除的元素: ["mandarin"]

// 2.用lenth来表示删除的位置
var myFish = ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon'];
var removed = myFish.splice(myFish.length - 3, 2);

// 运算后的 myFish: ["parrot", "anemone", "sturgeon"]
// 被删除的元素: ["blue", "trumpet"]

// 3.从索引开始删除所有元素
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(2);

// 运算后的 myFish: ["angel", "clown"]
// 被删除的元素: ["mandarin", "sturgeon"]

# 3.既删除又插入

var myFish = ['angel', 'clown', 'trumpet', 'sturgeon'];
var removed = myFish.splice(0, 2, 'parrot', 'anemone', 'blue');

// 运算后的 myFish: ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
// 被删除的元素: ["angel", "clown"]

# 4.从负号索引开始删除

// 从右往左,索引依次是-1,-2,-3,-4.....
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(-2, 1);

// 运算后的 myFish: ["angel", "clown", "sturgeon"]
// 被删除的元素: ["mandarin"]

# Map

# Array.prototype.join()

介绍:
join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

# String.prototype.split()

介绍:
split() 方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。
用法:

# Array.prototype.sort()