JS中常见的编程题

202 阅读14分钟

1.实现一个简单的模板

实现一个render(template,context)方法,将template中的占位符用context填充

示例

var template = '{{name}}很帅,今年{{age}}岁'
var context = {name:'Tom',age:17};

//输入 template  context
// 输出  Tom很帅,今年17岁

如下:

①先试用正则匹配到所有的{{name}},{{age}}

②利用str.splace(RegExp,function),其中第二个参数的函数返回值将替换掉一个参数匹配的结果;

var template = '{{name}}很帅,今年{{age}}岁'
var context = { name: 'Tom', age: 17 };

function render(template, context){
    return template.replace(/{{(.*?)}}/g,(x,y)=>{
        return context[y];
    })
}

let s =render(template, context);
console.dir(s)

2.将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组

var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];

第一种:ES6中Array.prototype.flat

/*
- new Set 去重 	
- arr.flat扁平化
- sort排序
*/
let x = Array.from(new Set(arr.flat(Infinity))).sort((a, b) => a - b);


let x = Array.from(new Set(arr.toString().split(','))).sort((a,b)=>a-b).map(x=>Number(x));
console.log(x)   //=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

第二种:JSON.stringify

/*
+ JSON.stringify(arr) => 把原数组转换成字符串形式的;
+ replace(/(\[|\])/g,'') =>替换 字符串中的[]
*/

arr = JSON.stringify(arr).replace(/(\[|\])/g,'').split(',').map(item=>{
            return Number(item);
        });  

第三种 : some

//find和some的区别:some返回的是boolean,find找到符合规则的,返回当前这一项,没找到符合规则的,返回undefined
//=>Array.isArray([val]):检测某个值是否为数组类型(挺准的)
=>基于数组的some方法进行判断检测:验证数组中的某一项有没有符合函数中提供的规则的
while (arr.some(item => Array.isArray(item))) {
    	arr = [].concat(...arr);
    }

第四种 : 递归处理

~ function () {
	function myFlat() {
		let result = [],
			_this = this;
		//=>循环ARR中的每一项,把不是数组的存储到新数组中
		let fn = (arr) => {
			for (let i = 0 i < arr.length; i++) {
				let item = arr[i];
				if (Array.isArray(item)) {
					fn(item);
					continue;
				}
				result.push(item);
			}
		};
		fn(_this);
		return result;
	}
	Array.prototype.myFlat = myFlat;
}();
arr = arr.myFlat();

3.如何实现一个 new?

  1. 创建一个空对象,它的__proto__指向构造函数原型;

  2. 使其this指向新创建的对象;

  3. return若为非基本类型值,则返回这个值,否则返回新创建的对象;

/*补充一个知识点:
	=>Object.create([AA对象]):创建一个空对象obj,并且让空对象obj作为AA对象所属构造函数的实例(obj.__proto__=AA)
*/

function _new(Fn,...arg){
    let obj = Object.create(Fn.prototype);
    let result = Fn.call(obj,...arg);
    return typeOf result==='object'? result : obj;
}
let sanmao = _new(Dog, '三毛');	

4.合并数组并重新排序

let ary1 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'];
let ary2 = ['A', 'B', 'C', 'D']; 

//=>合并后的数组为:['A1', 'A2', 'A', 'B1', 'B2', 'B', 'C1', 'C2', 'C', 'D1', 'D2', 'D'];

第一种

拼接数组,并且利用localeCompare进行排序

ary2 = ary2.map(item=>item+'z');
arr=ary1.concat(ary2).sort((a,b)=>a.localeCompare(b)).map(item=>item.replace('z',''));

第二种

 // 判断ary1是否包括ary2每一项,>如果包含就记录一下当前这一项的索引位置(后面还有包含的会重新记录这个值)
// 把当前ITEM2这一项插入到ARY1中N的后面
let n;
for (let i = 0; i < ary2.length; i++) {
    let item2 = ary2[i];
    for (let k = 0; k < ary1.length; k++) {
        let item1 = ary1[k];
        if (item1.includes(item2)) {
            n = k;
        }
    }
    ary1.splice(n + 1, 0, item2);
}
console.log(ary1);

5.改造下面的代码,使之输出0 - 9,写出你能想到的所有解法

for (var i = 0; i< 10; i++){
	setTimeout(() => {
		console.log(i);
    }, 1000)
}

1.利用let块级作用域

for (let i = 0; i< 10; i++){
	setTimeout(() => {
		console.log(i);
    }, 1000)
}

2.利用闭包保存机制

for (var i = 0; i < 10; i++) {
    (function (i) {
        setTimeout(() => {
            console.log(i);
        }, 1000)
    })(i)
}
//或着这种写法
for (var i = 0; i < 10; i++) {
   setTimeout((i => () => console.log(i))(i), 1000);
}



//setTimeout第三个参数,会作为回调函数的第一个参数传入
for (var i = 0; i < 10; i++) {
        setTimeout(i => {
            console.log(i);
        }, 1000,i)
}

3.bind

=>可以基于bind的预先处理机制:在循环的时候就把每次执行函数需要输出的结果,预先传给函数即可

var fn = function (i) {
	console.log(i);
};
for (var i = 0; i < 10; i++) {
	setTimeout(fn.bind(null, i), 1000);
}

6.使用迭代的方式实现 flatten 函数。

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

7.下面代码中 a 在什么情况下会打印 1?

var a = ?;
if(a == 1 && a == 2 && a == 3){
 	console.log(1);
}

复习下 ==

== 相对相等,如果左右两边数据类型不一样,则先转换为相同的数据类型,然后在进行比较

    1. {}=={} 两个对象进行比较,比较的是堆内存的地址
    1. null==undefined 相等的 / null===undefined 不相等
    1. NaN==NaN 不相等 NaN和谁都不相等
    1. [12]=="12" 对象和字符串比较,是把对象toString()转换为字符串后再进行比较的
    1. 剩余所有情况在进行比较的时候,都是转换为数字(前提数据类型不一样)
  •  对象转数字:先转换为字符串,然后再转换为数字
    
  •  字符串转数字:只要出现一个非数字字符,结果就是NaN
    
  •  布尔转数字:true->1  false->0
    
  •  null转数字0
    
  •  undefined转数字NaN
    
=======第一种========
// =>对象和数字比较:先把对象.toString()变为字符串,然后再转换为数字
a.toString(); //=>此时调取的就不再是Object.prototype.toString了,调取的是自己私有的

var a = {
     n: 0,
     toString() {
         return ++this.n;
    }
}

=========第二种========
//=>shift:删除数组第一项,把删除的内容返回,原有数组改变
// 调取toString === a.shift;
let a = [1, 2, 3];
a.toString = a.shift;


=========第三种=========
// ES6中新增加的一些方法
// Object.defineProperty属性,执行window.a的时候,会先执行get这个函数,所以在get这个函数编写代码即可;
 Object.defineProperty(window, 'a', {
            get: function () {
                //=>this:window.a => undefined;
                this.value ? this.value++ : this.value = 1;
                return this.value;
            }
        });

8:实现一个 sleep 函数

比如 sleep(1000) 意味着等待1000毫秒,可从 Promise、Generator、Async/Await 等角度实现

9.实现 (5).add(3).minus(2) ,使其输出结果为:6

例: 5 + 3 - 2,结果为 6

// 每次方法执行完,都要返回NUMBER这个类的实例,这样才可以继续调取NUMBER类原型中的方法(链式写法);

(function () {
    function check(n) {
        n = Number(n);
        return isNaN(n) ? 0 : n;
    }

    function add(n) {
        n = check(n);
        return this + n;
    }
    function minus(n) {
        check(n)
        return this - n;
    }

    ['add', 'minus'].forEach(item => {
        Number.prototype[item] = eval(item);
    })
})()
let res = (5).add(3).minus(2);
console.log(res);  //  => 6 

10.冒泡排序如何实现,时间复杂度是多少, 还可以如何改进?

function bubbleSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                const temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    console.log(arr);
}

// 改进冒泡排序
function bubbleSort1(arr) {
    let i = arr.length - 1;

    while (i > 0) {
        let pos = 0;
        for (let j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
                pos = j;
                const temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        i = pos;
    }
    console.log(arr);
}

11.某公司 1 到 12 月份的销售额存在一个对象里面

如下:{1:222, 2:123, 5:888},请把数据处理为如下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null]。

let obj = { 1: 222, 2: 123, 5: 888 };

=======第一种======    
const result = Array.from({ length: 12 }).map((_, index) => obj[index + 1] || null);

// =>或着
let ary = new Array(12).fill(null).map((item,index) => {
            return obj[index+1] || item;
        });

console.log(ary)  //  [222, 123, null, null, 888, null, null, null, null, null, null, null];


========第二种========
let obj = {
    1: 222,
    2: 123,
    5: 888
};
obj.length = 13;

let ary = Array.from(obj).slice(1).map(item => {
    return typeof item === "undefined" ? null : item;
})
console.log(ary) //  [222, 123, null, null, 888, null, null, null, null, null, null, null];

=======第三种 =====
let obj = {
            1: 222,
            2: 123,
            5: 888
        };
// =>Object.keys(obj):获取obj中所有的属性名,以数组的方式返回

let arr = Object.keys(obj);
console.log(arr);   //["1", "2", "5"]

let ary = new Array(12).fill(null);
arr.forEach(item =>{
    ary[item - 1] = obj[item];
})
console.log(ary)  //  [222, 123, null, null, 888, null, null, null, null, null, null, null]

12.要求设计 LazyMan 类,实现以下功能

LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

如下

class LazyManClass {
    constructor(name) {
        this.taskList = [];
        this.name = name;
        console.log(`Hi I am ${this.name}`);
        setTimeout(() => {
            this.next();
        }, 0);
    }
    eat (name) {
        var that = this;
        var fn = (function (n) {
            return function () {
                console.log(`I am eating ${n}`)
                that.next();
            }
        })(name);
        this.taskList.push(fn);
        return this;
    }
    sleepFirst (time) {
        var that = this;
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000);  
            }
        })(time);
        this.taskList.unshift(fn);
        return this;
    }
    sleep (time) {
        var that = this
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000); 
            }
        })(time);
        this.taskList.push(fn);
        return this;
    }
    next () {
        var fn = this.taskList.shift();
        fn && fn();
    }
}
function LazyMan(name) {
    return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');

13.给定两个数组,写一个方法来计算它们的交集。

例如:

let nums1 = [12, 23, 34, 23, 45, 34,24, 25, 46, 35]; let nums2 = [10, 35, 24, 23, 36, 47, 56]; //=> 输出结果: [23, 24, 35]

// 第一种使用new Set 的has
// + has(value):判断集合中是否存在 value

let set1 = [12, 23, 34, 23, 45, 34, 25, 46, 35]
let set2 = new Set([10, 35, 24, 23, 36, 47, 56]);


let intersect = Array.from(new Set([...set1].filter(value => set2.has(value))))

=======第二种======
let arr = [];

nums1.forEach((item, index) => {
    let n = nums2.indexOf(item);
    if (n >= 0) {
        arr.push(item);
        nums1.splice(index, 1);
        nums1.splice(n, 1);
    }
});
console.log(arr);

==========第三种==========
let arr = [];

for (let i = 0; i < nums1.length; i++) {
    let item1 = nums1[i];
    for (let k = 0; k < nums2.length; k++) {
        let item2 = nums2[k];
        if (item1 === item2) {
            arr.push(item1);
            break;
        }
    }
}
console.log(arr);

14.随机生成一个长度为 10 的整数类型的数组,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],将其排列成一个新数组,要求新数组形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]


15.如何把一个字符串的大小写取反(大写变小写小写变大写),例如 ’AbC' 变成 'aBc'

let str = 'JinTianTIanQiHenhao';
str = str.replace(/[a-zA-Z]/g, content => {
    //content:每一次正则匹配到的结果;
    // 验证是否大写字母,统一转换成大写,再跟之前的字母对比,如果一样,说明之前也是大写;
    // 在ASCII 表中找到大写字母的取值范围进行判断(65-90);
    return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();
});
console.log(str)  // =>'jINtIANtiANqIhENHAO'

16.实现一个字符串匹配算法,从字符串 S 中,查找是否存在字符串 T,若存在返回所在位置,不存在返回-1!(如果不能基于indexOf/includes等内置的方法,你会如何处理呢?)

/*
S: 查找S中T是否存在
pramas: [T] =>需要查找的字符串内容;
return:存在返回其索引,不存在返回-1;
*/
// 循环原始字符串中每一项,让每一项从当前位置向后截取 T.length个字符,
// 然后和T进行比较,如果不一样继续循环;如果一样返回当前索引即可;
// THIS:S =>原字符串;
// pramas: [T]=> 需查找的字符串;
// return: 匹配完整字符串开始的索引;
~function () {
   	function myIndexOf(T) {
        let lenT = T.length,
            lenS = S.length,
            res = -1;
        if (lenS < lenT) return null;
        for (let i = 0; i < lenS - lenT; i++) {
            if(this.substr(i, lenT) === T){
                res = i;
                break;  // 为了避免出现多个符合,找最后一个,让其找到一个就结束;
            };               
        };
        return res;
    };
    String.prototype.myIndexOf = myIndexOf;
}();

let S = 'jingerzitiantianqihenhao',
    T = 'tian';
let res = S.myIndexOf(T);
console.log(res);
 =========第二种=========
**使用正则匹配**

~function () {
    function myIndexOf(T) {
        let reg = new RegExp(T),
            res = reg.exec(this);
        return res === null ? -1 : res.index;
    }
    String.prototype.myIndexOf = myIndexOf;
}();

let S = 'jingerzitianqihenhao',
    T = 'tian';
let res = S.myIndexOf(T);
console.log(res);

17.给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

/* 
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数
输入: [1, 2, 3, 4, 5, 6, 7] 和 k = 3
输出: [5, 6, 7, 1, 2, 3, 4]
解释:
向右旋转 1 步: [7, 1, 2, 3, 4, 5, 6]
向右旋转 2 步: [6, 7, 1, 2, 3, 4, 5]
向右旋转 3 步: [5, 6, 7, 1, 2, 3, 4]

输入: [-1, -100, 3, 99] 和 k = 2
输出: [3, 99, -1, -100]
解释: 
向右旋转 1 步: [99, -1, -100, 3]
[3, 99, -1, -100] 
*/

==== 第一种========
    
let arr = [1, 2, 3, 4, 5, 6, 7];
function change(k) {
    if (k < 0 && k === this.length) return;
    if (k > this.length) return k = k % this.length;
    return this.slice(-k).concat(this.slice(0, this.length - k));
    // return [...this.splice(this.length-k),...this];
}
Array.prototype.change = change;

let ary = arr.change(3);
console.log(ary);

=========第二种========
function change(k) {
            //=>参数处理
            if (k < 0 || k === 0 || k === this.length) return this;
            if (k > this.length) k = k % this.length;

            // for (let i = 0; i < k; i++) {
            //     this.unshift(this.pop());
            // }
            new Array(k).fill('').forEach(() => this.unshift(this.pop()));
            return this;
        }
Array.prototype.change = change;
let ary = arr.change(3);
console.log(ary);   // [5, 6, 7, 1, 2, 3, 4]

18.打印出 1 - 10000 之间的所有对称数


19.给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数
function zeroMove(arr) {
    let len = arr.length;
    let j = 0;
    for (let i = 0; i < len; i++) {
        if (arr[i] === 0) {
            arr.push(0);
            arr.splice(i, 1);
            i--;
            j++;
        }
    }
    return arr;
}

let x = zeroMove([0, 1, 0, 3, 12]);

20.请实现一个 add 函数,满足以下功能

add(1); // 1
add(1)(2); // 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6


function currying(fn, length) {
	length = length || fn.length;
	return function (...args) {
		if (args.length >= length) {
			return fn(...args);
		}
		return currying(fn.bind(null, ...args), length - args.length);
	}
}


let add = currying((...arg) => eval(arg.join('+')), 5);

console.log(add(1, 2, 3, 4, 5));
console.log(add(1, 2)(3, 4, 5));
console.log(add(1, 2)(3, 4)(5));
console.log(add(1, 2)(3)(4)(5));
console.log(add(1)(2)(3)(4)(5));

21.两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

简单直接

let nums = [2, 7, 11, 15], target = 15

function twoSum(nums, target) {
    for (let i = 0; i < nums.length; i++) {
        for (let k = 0; k < nums.length; k++) {
            if (i !== k && nums[i] + nums[k] === target) {
                return [i, k];
            }
        }
    }
    return '沒有找到哦~';
}

console.log(twoSum(nums, target))

22.在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符合URL网址的格式

=>首先我们需要了解URL的格式
1.协议://  http/https/ftp
2.域名
    www.sina.cn
    sina.cn
    kbs.sports.qq.com
    kbs.sports.qq.com.cn
3.请求路径
    /
    /index.html
    /stu/index.html
    /stu/
4.问号传参
    ?xxx=xxx&xxx=xxx
5.哈希值
// #xxx
*/

let str = "https://www.sina.com.cn";
let reg = /^(?:(http|https|ftp):\/\/)?((?:[\w-]+\.)+[a-z0-9]+)((?:\/[^/?#]*)+)?(\?[^#]+)?(#.+)?$/i;
console.log(reg.exec(str));

23.实现 convert 方法,把原始 list 转换成树形结构,要求尽可能降低时间复杂度

以下数据结构中,id 代表部门编号,name 是部门名称,parentId 是父部门编号,为 0 代表一级部门,现在要求实现一个 convert 方法,把原始 list 转换成树形结构,parentId 为多少就挂载在该 id 的属性 children 数组下,结构如下:

// 原始 list 如下
let list =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];
const result = convert(list, ...);
 
// 转换后的结果如下
let result = [
    {
      id: 1,
      name: '部门A',
      parentId: 0,
      children: [
        {
          id: 3,
          name: '部门C',
          parentId: 1,
          children: [
            {
              id: 6,
              name: '部门F',
              parentId: 3
            }, {
              id: 16,
              name: '部门L',
              parentId: 3
            }
          ]
        },
        {
          id: 4,
          name: '部门D',
          parentId: 1,
          children: [
            {
              id: 8,
              name: '部门H',
              parentId: 4
            }
          ]
        }
      ]
    },
  ···
];

使用reduce

function covert(list) {
    const res = [];
    const map = list.reduce((res, v) => (res[v.id] = v, res), {})
    for (let item of list) {
        if (item.parentId === 0) {
            res.push(item);
            continue;
        }
        if (item.parentId in map) {
            let parent = map[item.parentId];
            parent.children = parent.children || [];
            parent.children.push(item);
        }
    };
    return res;
}
console.log(covert(list));

24.实现模糊搜索结果的关键词高亮显示

1594458655056

25.用 JavaScript 写一个函数,输入 int 型,返回整数逆序后的字符串。

如:输入整型 1234,返回字符串“4321”。要求必须使用递归函数调用,不能用全局变量,输入函数必须只有一个参数传入,必须返回字符串。


26.请写出一个函数,完成以下功能输入

输入 1,2,3,5,7,8,10
输出 1~3,5,7~8,10

let num = [1, 2, 3, 5, 7, 8, 10];

/*
* 每一项+1,是否与后一项相同,若不相同,则返回范围值(说明已经不连续了);
* 把不连续值,继续赋值,重新进行对比;
*/ 
function str(mum) {
    var result = [],
        temp = num[0];
    num.forEach((item, index) => {
        if (item + 1 !== num[index + 1]) {
            if (temp !== item) {
                result.push(`{temp}~${item}`)
            } else {
                result.push(`${item}`);
            }
        };
        temp = num[index + 1];
    })
}
str(num);

27.

var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

// 转换成:
var output = {
    a: {
        b: {
            c: {
                dd:
                    'abcdd'
            }
        },
        d:{
            xx:'adxx'
        },
        e:'ae'
    }
}

28.找出字符串中连续出现最多的字符和个数

let str = "jintiantianqihaodehenneshibushi";


=====第一种====
+ 循环str,并且把str每项作为属性存入obj,默认属性值为1;
+ 循环中判断str中的每一项中是否为undefined,非undefined,说明已经存在原基础上累加;

let obj = {};
[].forEach.call(str, char => {
    if (typeof obj[char] !== "undefined") {
        obj[char]++;
        return;
    }
    obj[char] = 1;
});
let max = 1,
    res = [];
for (let key in obj) {
    let item = obj[key];
    item > max ? max = item : null;
}
for (let key in obj) {
    let item = obj[key];
    if (item === max) {
        res.push(key);
    }
}
console.log(`出现次数最多的字符是:${res},出现了${max}次`);

============第二种=============
+ 基于localeCompare对字符串进行排序;
+ 利用正则匹配多个字符,并借用length进行排序
str = str.split('').sort((a, b) => a.localeCompare(b)).join('');  //=>"aaabdeeehhhhiiiiiijnnnnnoqssttu"

let reg = /([a-zA-Z])\1+/g;
let ary = str.match(reg);  //=> ["aaa", "eee", "hhhh", "iiiiii", "nnnnn", "ss", "tt"]
ary.sort((a, b) => b.length - a.length);  //=>["iiiiii", "nnnnn", "hhhh", "aaa", "eee", "ss", "tt"]
let max = ary[0].length,
    res = [ary[0].substr(0, 1)];

// 考虑可能会存在多个length一样的
for (let i = 1; i < ary.length; i++) {
    let item = ary[i];
    if (item.length < max) {
        break;
    }
    res.push(item.substr(0, 1));
}
console.log(`出现次数最多的字符是:${res},出现了${max}次`);


========第三种=======
let max = 0,
    res = [],
    flag = false;
str = str.split('').sort((a, b) => a.localeCompare(b)).join('');

for (let i = str.length; i > 0; i--) {
	let reg = new RegExp("([a-zA-Z])\\1{" + (i - 1) + "}", "g");
	str.replace(reg, (content, $1) => {
		res.push($1);
		max = i;
		flag = true;
	});
	if (flag) break;
}
console.log(`出现次数最多的字符:${res},出现了${max}次`);

29.获取数组中的最大值和最小值

let ary = [12, 24, 13, 8, 35, 15];

=======sort========
ary.sort(function (a, b) {
	return a - b;
});
let min = ary[0];
let max = ary[ary.length - 1];
console.log(min, max)


=====Math.max/Math.min===
=>Math.max/min要求我们传递的数据是一项项传递进来,获取一堆数中的最大最小,而不是获取一个数组中的最大最小
let min = Math.min(...ary);

======假设法=========
let max = ary[0];
for (let i = 1; i < ary.length; i++) {
	let item = ary[i];
	item > max ? max = item : null;
} 
console.log(max); //=>35

30. 时间字符串的格式化处理

~ function () {
	/*
	 * formatTime:时间字符串的格式化处理
	 *   @params
	 *     templete:[string] 我们最后期望获取日期格式的模板
	 *     模板规则:{0}->年  {1~5}->月日时分秒
	 *   @return
	 *     [string]格式化后的时间字符串
	 *  by LYR on 2019/08/13
	 */
	function formatTime(templete = "{0}年{1}月{2}日 {3}时{4}分{5}秒") {
		let timeAry = this.match(/\d+/g);
		return templete.replace(/\{(\d+)\}/g, (...[, $1]) => {
			let time = timeAry[$1] || "00";
			return time.length < 2 ? "0" + time : time;
		});
	}

	/* 扩展到内置类String.prototype上 */
	["formatTime"].forEach(item => {
		String.prototype[item] = eval(item);
	});
}();

let time = "2019-8-13 16:51:3";
console.log(time.formatTime());
console.log(time.formatTime("{0}年{1}月{2}日"));
console.log(time.formatTime("{1}-{2} {3}:{4}"));
time = "2019/8/13";
console.log(time.formatTime());
console.log(time.formatTime("{0}年{1}月{2}日"));
console.log(time.formatTime("{1}-{2} {3}:{4}"));

31. 获取URL地址问号和面的参数信息(可能也包含HASH值)

/* 
* queryURLParams:获取URL地址问号和面的参数信息(可能也包含HASH值)
*   @params
*   @return
*     [object]把所有问号参数信息以键值对的方式存储起来并且返回
* by LYR on 2019/01/01
*/

function queryURLParams() {
	let obj = {};
	this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => obj[$1] = $2);
	this.replace(/#([^?=&#]+)/g, (...[, $1]) => obj['HASH'] = $1);
	return obj;
}

/* 扩展到内置类String.prototype上 */
["formatTime", "queryURLParams"].forEach(item => {
	String.prototype[item] = eval(item);
});
}();
let url = "http://www.lalala.cn/?lx=1&from=wx#video";
console.log(url.queryURLParams());
//=>{lx:1,from:'wx',HASH:'video'}

32. 千分符

/* 
* millimeter:实现大数字的千分符处理
*   @params
*   @return
*     [string]千分符后的字符串
* by LYR on 2019/08/13
*/
function millimeter() {
	return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => content + ',');
}
	
	/* 扩展到内置类String.prototype上 */
	["formatTime", "queryURLParams", "millimeter"].forEach(item => {
		String.prototype[item] = eval(item);
	});
}();

let num = "15628954"; //=>"15,628,954" 千分符
console.log(num.millimeter());
num = "112345678256874"; //=>"12,345,678,256,874"
console.log(num.millimeter());

// 把字符串倒过来加
/* num = num.split('').reverse().join('');
for (let i = 2; i < num.length - 1; i += 4) {
	let prev = num.substring(0, i + 1),
		next = num.substring(i + 1);
	num = prev + "," + next;
}
num = num.split('').reverse().join('');
console.log(num); */

33. indexOf

let indexOf = (S, T) => {
  if (S.length < T.length) return -1;
  for (let i = 0; i < S.length - T.length ; i++) {
      if (S.substr(i, T.length) === T) return i;
  }
  return -1;
};

34. 编写一条正则,用来验证此规则:一个6~16位的字符串,必须同时包含有大小写字母和数字

let reg = /(?!^[a-zA-Z]+$)(?!^[A-Z0-9]+$)(?!^[a-z0-9]+$)^[a-zA-Z0-9]{6,16}$/;

35. 完成如下需求

/* 实现一个$attr(name,value)遍历
 * 属性为name
 * 值为value的元素集合
 * 
 * 例如下面示例:
 */
<div id="AA" class="box clearfix"></div>
<div myIn="1"></div>
<div class="content box"></div>
<div name="BB"></div>
<div></div>
<div id="AA"></div>
<div myIn="1" class="clearfix"></div>
<div class="box"></div>
<div class="box banner"></div>
<div myIn="2"></div>
<div name="BB"></div>

function $attr(property, value) {
    let ele = document.getElementsByTagName('*'), // 获取到元素集合的类数组;
        arr = [];
    ele = Array.from(ele);
    ele.forEach(item => {
        let itemValue = item.getAttribute(property);
        // 因为Class比较特殊,可以有多个名字,可能多个类名中包含其中的,
        // 但是整体类名不会检测出来,所以需要特殊处理;
        if (property === 'class') {
            new RegExp("\\b" + value + "\\b").test(itemValue) ? arr.push(item) : null;
        };
        if (itemValue === value) {
            arr.push(item);
        };
    });
    return arr;
};

let ary = $attr('class', 'box'); //=>获取页面中所有class为box的元素
console.log(ary)

36. 数组重组 (将name值相同的合并,并去除age的属性)

// 数组重组  (将name值相同的合并,并去除age的属性)
let ary = [
    {name:1,age:2,number:1,son:'son1'},
    {name:2,age:23,number:2,son:'son2'},
    {name:2,age:22,number:3,son:'son3'},
    {name:1,age:12,number:4,son:'son4'},
    {name:1,age:42,number:5,son:'son5'}
]
fn(ary) // 结果为
[
  {
    "name":1,
    "list":[{"number":1,"son":"son1"},{"number":4,"son":"son4"},{"number":5,"son":"son5"}]
  },
  {
    "name":2,
    "list":[{"number":2,"son":"son2"},{"number":3,"son":"son3"}]
  }
]

如下:
function fn(ary){
    let arr = [];
    ary.forEach(item=>{
        let bol = arr.some(val=>{
            if(val.name===item.name){
                let obj = {};
                Object.keys(item).forEach(v=>{
                    if(v!='name'&&v!='age'){
                        obj[v] = item[v]
                    }
                })
                val.list.push(obj);
                return true
            }
        })
        if(!bol){
            let obj = {};
            Object.keys(item).forEach(v=>{
                if(v!='name'&&v!='age'){
                    obj[v] = item[v]
                }
            })
            arr.push({name:item.name,list:[obj]});
        }
    })
    return arr;
}
fn(ary)