function splitMoney(num){
const arr = num.toString().split('.');
const numarr = arr[0].split('');
const reverseNum = numarr.reverse();
for(let i =3,len = reverseNum.length ;i<len;i+=3){
reverseNum.splice(i,0,',');
i++;
}
const result = revereNum.join('').reverse()+arr[1];
console.log(result);
}
1,{[()]}
一个字符串,该字符串只可能包含:‘[,],{,},(,)',其中的几个,判断该字符串是否符合以下规则:
左括号必须使用相同类型右括号闭合
必须以正确顺序闭合
例如:输入 {() } :true
输入([)]:false
输入([): false
function judge(str){
//思路,将字符串中所有括号的左边push到数组,然后遇到括号右边的就和数组最后一个对比,如果符合就从数组里pop出去。
const arr=[];
const len = str.length;
if(len%2!==0)return false;
for(let i = 0;i<len;i++){
const end = arr.length;
switch(s[i]){
case '(':
arr.push('(');
break;
case '[':
arr.push('[');
break;
case '{':
arr.push('{');
break;
case ')':
if(arr[end-1] === '(')arr.pop();
break;
case ']':
if(arr[end-1] === '[')arr.pop();
break;
case '}':
if(arr[end-1] === '{')arr.pop();
break;
}
}
if(arr.length>0)return false
else{ return true }
}
2,字符串反转
使用数组的reverse方法,实现字符串反转?(也可以用来判断回文字符:mamam,redivider)
function reverseStr(str){
return str.split('').reverse().join('');
}
2.1 字符串反转(不用reverse)
function reverseStr(str){
const len = str.length;
for(let i=0,j=len-1;i<j;i++,j--){
[str[i],str[j]] = [str[j],str[i]]
}
return str;
}
3,判断一个单链表是否存在闭环?
思想:快指针,慢指针
function ListNode(list){
this.value = val;
this.next = null
}
function hasCycle(head){
var slow = head;
var fast = head;
while(slow.next != null || fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow === fast){
return true
}
return false
}
}
4,sum(1,2,3) = sum(1)(2)(3)
实现一个sum函数,使得sum(1,2)==sum(1)(2)
首先实现sum(1,2)
function sum(){
if(arguments.length>0){
arguments.map(item=>{
result+=item
}
};
return result
}
然后实现sum(1)(2)
function sum(a){
return function(b){
return a+b
}
}
实现sum(1)(2)(3)
function sum(a){
const s = function(b){
return sum(a+b)
}
s.toString = function(){ return a };
return s
}
二者结合
function sum(a){
const len = arguments.length;
var value = 0;
if(len>1){
for(var i=0;i<arguments.length;i++){
value+=arguments[i];
}
return value;
}
else {
var s = function(b){
return sum(a+b);
}
s.toString = function(){
return a;
}
return s;
}
}
4.1附加题 实现sum(1)(2)(3)()
function add(num,preSum){
var result = preSum || 0;
return num?function(nextNum){
result += num;
return add(nextNum,result)
}:result;
}
5,分离单调递增数组连续区间
给定一个单调递增的数组,比如[1,2,3,5,6,7,11,12],输出连续区间,得[1,2,3], [5,6,7], [11,12]
function source(arr){
let i;
let a ;
let result = [];
arr.forEach(function(v){
if(v == i){
a.push(v);
i++;
return
}
let a = [v];
i = v+1;
result.push(a);
})
return result
}
6,数组去重
不使用Set,将数组去重?
function set(arr){
var result = [];
var obj = {};
arr.map(item=>{
if(!obj[item]){
obj[item] = true;
result.push(item)
}
}
return result;
}
7,统计字符串中出现次数最多的字母?
function maxstr(str){
var obj = {};
const arr = str.split('');
var max = 0;
arr.map(item=>{
if(obj[item]){
obj[item]++
}else{
obj[item] = 1;
}
})
var sub;
for(let key in obj){
if(obj[key]>max){
max = obj[key];
sub = key;
}
}
return sub
}
maxstr("aaabbbbcccc")
8,冒泡排序?
[3,5,6,1,7,2] 排为 [1,2,3,5,6,7]
function sort(arr){
let len = arr.length;
for(let i = 0;i<len;i++){
for(let j = i;j<len;j++){
if(arr[i]>arr[j]){
const item = arr[i];
arr[i] = arr[j];
arr[j] = item;
}
}
}
console.log(arr);
}
9,判断一个数是否为素数(质数)?
素数的意思是这个数除了1和自己,没有其他的因子了。比如2,3,5,7,11,13,17,19,23,29,31,37........
分析这些数字之间相差(2,4,6),所以只要不仅除不尽2,也除不尽3,以及(3+2,3+4,3+6....)的数字,它就是素数,然后它的被除数最大应该是它的平方根
function isPrime(num){
if(num===2||num===3)return true;
if(num%2===0)return false;
const sqrt = Math.sqrt(num);
var divider = 3;
while(divider<sqrt){
if(num%divider === 0){
return false
}else{
divider+=2
}
}
return true
}
}
10,斐波那契数列
function febonacci(num){
if(num===0)return 0;
if(num ==1||num==2)return 1;
else{
return febonacci(num-2)+febonacci(num-1)
}
}
11,快速排序
function quicksort(arr){
const len = arr.length;
if(len<2)return arr;
const mid = Math.floor(len/2);
const left = [];
const right = [];
var pivot = arr.splice(mid, 1)[0];
arr.map(item=>{
if(item<pivot){
left.push(item)
}else{
right.push(item)
}
})
const leftResult = quicksort(left);
const righResult = quicksort(right);
return leftResult.concat([pivot],righResult)
}
12,合并已经排过序的两个数组?
function merge(a,b){
var i = 0;
var j = 0;
var af = a[0];
var bf = b[0];
var result = [];
while(af||bf){
if(af<bf||!bf){
result.push(af);
af = a[++i];
}else{
result.push(bf);
bf = b[++j];
}
}
return result;
}
13,实现深拷贝deepclone
function deepclone(obj){
if(typeof obj === "object"){
var result = Array.isArray(obj)?[]:{};
for(let item in obj){
result[item] = deepclone(obj[item]);
}
}else{
return obj
}
}
14,数组转化为树?
这题有点问题啊~,pid:0,但是没有id:0的节点
将[
{id: 1, pid: 0 , name:"上海"},
{id: 2, pid: 1 , name:"苏州"},
{id: 3, pid: 1 , name:"安徽"},
{id: 4, pid: 0 , name:"杭州"}
]
转化为:
[
{ id: 1,
pid: 0,
name: "上海",
children:[
{id: 2, pid:1, name:"苏州"},
{id: 3, pid:1, name:"安徽"}
],
},
{ id:4,
pid: 0,
name:"杭州",
}
]
思路:先转化成这样
{
0: [ {id: 1, pid: 0 , name:"上海"},{id: 4, pid: 0 , name:"杭州"}],
1: [{id: 2, pid: 1 , name:"苏州"},{id: 3, pid: 1 , name:"安徽"}]
}
再把原来的arr里插入chidren
[
{ id: 1,
pid: 0,
name: "上海",
children: [{id: 2, pid: 1 , name:"苏州"},{id: 3, pid: 1 , name:"安徽"}] //map.get(1)
},
{id: 2, pid: 1 , name:"苏州"},
{id: 3, pid: 1 , name:"安徽"},
{id: 4, pid: 0 , name:"杭州"}
]
function arrToTree(arr){
let map = new Map();
arr.forEach(item => {
if(!map.has(item.pid)){
map.set(item.pid, [item])
}else {
let arr1 = map.get(item.pid);
arr1.push(item)
}
})
arr.forEach(item => {
if(map.has(item.id)){
item.children = map.get(item.id);
}
})
return map.get(0);
}
15,大数相加
两个很大的数字相加,超出计算机允许的长度,可以用字符串表示,例如:
bigNum("111111111","999999999999") 返回的结果也是字符串
function bigNum(num1,num2){
while(num1.length<num2.length){num1 = '0'+num1;}
while(num1.length>num2.length){num2 = '0'+num2;}
let len = num1.length;
let result = '';
let carray = 0;
let mid = 0;
for(let i = len-1;i>=0;i--){
mid = Number(num1[i])+Number(num2[i])+carray;
carray = mid>9?1:0;
let wei = mid%10;
result = wei+result;
}
return carray?('1'+result):result
}
16,数组扁平化
//通用的
function flat(arr){
let result = [];
arr.map(item=>{
if(!Array.isArray(item)){
result.push(item)
}else{
const pin = flat(item);
result = result.concat(pin);
}
})
return result;
}
//元素类型是字符串['1','2','3'],可以这样
function flatArray(arr){
return arr.toString().split(',');
}
17,千位分隔符
将123345.56元,分割为123,345.56
function splitMoney(num){
const arr = num.toString().split('.');
const reverseNum = arr[0].split('').reverse();
let res = [];
let len = reverseNum.length;
for(let i =0;i<len;i++){
if(i%3===0&&i!==0){
res.push(',');
}
res.push(reverseNum[i]);
}
if(arr[1]){
arr[1]='.'+arr[1];
}
const result = res.reverse().join('')+arr[1];
console.log(result);
}
18,找到数组中所有重复的元素的个数?
比如:[1,11,1,2,3,3,4,5],重复的元素有两个:1和3,所以返回2;
function ag(arr){
const obj = {};
arr.map(item=>{
obj[item] = obj[item]|| 0;
obj[item]++
})
var len = 0;
for(let it in obj){
if(obj[it]>1){
len++
}
}
console.log(len)
}
19,找到数组中和为n的两个数的下标?
例如[1,3,5,6] ,target = 8,则返回下标:1,2
function twoSum(arr,target){
const len = arr.length;
var hashMap = {};
for(let i = 0;i<len;i++){
if(hashMap[target-arr[i]]!==undefined){
console.log(hashMap[target-arr[i]],i)
}
hashMap[arr[i]]=i
}
}
20,区间合并
比如: [[1,3],[2,6],[8,10],[15,18]] 合并为 [[1,6],[8,10],[15,18]]
因为区间 [1,3] 和 [2,6] 重叠, 所以将它们合并为 [1,6]
function mergeArr(arr){
arr = arr.sort((a,b)=>{
a[0]-b[0]
});
let result = [arr[0]];
let j = result.length-1;
let mid;
for(let i = 0;i<arr.length;i++,j = result.length-1){
if(result[j][1]>arr[i][0]){
if(result[j][1]>arr[i][1]){
mid = [result[j][0],result[j][1]]
}else{
mid = [result[j][0],arr[i][1]]
}
result.pop();
result.push(mid)
}else{
result.push(arr[i]);
}
}
return result;
}
21,手写bind函数
22,手写call函数
核心思想:谁调用函数,函数的this就指向谁。
本来是window.fn(),现在修改为obj.fn(),那么fn的this就指向obj了。
不过call函数内部无法预知哪个函数将要调用自己,所以obj.fn = this,obj.fn()
Function.prototype.calls=function(obj){
obj.fn = this;
const arg= [...arguments].slice(1);
obj.fn(arg)
delete obj.fn
}
23,求最后一个单词的长度
比如:“hello world",返回 5
function lastLong(str){
str = str.trim(); //去除字符串中首尾的空格
const arr= str.split(" ");
return arr[arr.length-1].length;
}
24,实现lodash.get()函数
比如一个对象:{ 'a': [{ 'b': { 'c': 3 } }] },正常调用应该是
if(a.b&&a.b.c){ console.log(a.b.c)}
但是使用lodash.get可以直接调用:_.get(a.b.c) //3
function deepGet(object, path, defaultValue) {
return
(!Array.isArray(path) ? path.replace(/\[/g, '.').replace(/\]/g, '').split('.') : path)
.reduce((o, k) => (o || {})[k], object) || defaultValue;
}
25,手撸promise
class Promise{
constructor(){
this.status = "pending";
this.value = undefined;
this.err = undefined;
}
resolve(data){
this.status = "resolve"
this.value = data
}
reject(err){
this.status = "reject"
this.err = err
}
then(fn){
fn(this.value);
}
catch(fn){
fn(this.err);
}
}
26,手撸Promise.all
问题1:封装一个promise,假设5S内没有返回值就丢弃这个结果
问题2:封装一个promise,解决promise.all可以返回所有的结果,而不是一个出错丢弃所有
Promise.all = function(promises){
const i = 0;
let arr = [];
let processPromise=function(data,i){
arr[i] = data;
if(++i==promises.length){
resolve(arr);
}
}
promises.map((item,i)=>{
item.then((data)=>{
processPromise(data)
},reject)
})
}
问题1:
const a = new Promise((resolve,reject)=>{
const data = $.ajax(
url:'',
success(data){
resolve(data)
}
)
setTimeout(function(){
if(!data){
reject("失败")
}
},5000)
})
27,继承
//原型链继承
function A(){}
function B(){}
B.prototype = new A();
B.prototype.constructor = B
//构造函数继承
function A(){}
function B(val){
A.call(this,val)
}
//组合继承
function A(){}
function B(val){
A.call(this,val)
}
B.prototype = new A();
B.prototype.constructor = B
//寄生组合继承
function A(){}
function B(val){
A.call(this,val)
}
B.prototype = Object.create(A.prototype)
28,实现promise.all
所有请求全部成功则调用then函数,否则调用catch,并且catch的是第一个请求错误的接口
Promise._all = (arr) => {
return new Promise((resolve, reject) => {
if (!arr.length) resolve([])
if (typeof arr[Symbol.iterator] !== 'function' || arr == null) {
throw new TypeError('arr is not iterable')
}
let len = arr.length
let count = 0;
let result = []
arr.forEach((item, index) => {
Promise.resolve(item).then((res) => {
++count
result[index] = res
if (count === len) resolve(result)
}).catch(reject)
})
})
}
// 如果一个对象有Symbol.iterator属性,并且这个属性的类型是function,那么这个对象就是可迭代的,
// 什么叫做可迭代:可以使用for...of循环,可以使用Array.from转为数组
// 有哪些可迭代对象:
29,json2dom 实现render函数
function _render(json) {
if (typeof json === 'number') {
json = String(json)
}
if (typeof json === 'string') {
return document.createTextNode(json)
}
const { tag, attrs, children } = json
const dom = document.createElement(tag)
Object.keys(attrs).forEach(key => {
dom.setAttribute(key, attrs[key])
})
children.forEach(child => {
dom.appendChildren(_render(child))
})
return dom
}
30,树形结构转列表
function tree2list(treeArr) {
const res = []
treeArr.forEach(item => {
let { children } = item
delete item.children
res.push(item)
if (children && children.length) res.push(...tree2list(children))
})
return res
}
31,列表转树形结构
// 思路解析:只需要遍历一次list表,每次都更新hashMap的属性值,由于children和hashMap属于地址引用的关系,所以更新hashMap顺便更新了children
// res = [
// {id:1,name:'hi',pid:0,children:[]}
// ]
// hashMap = {
// 1: {id:1,name:'hi',pid:0,children:[]},
// 2: {id:2,name:'hi',pid:1,children:[]},
// }
function list2tree(listArr) {
const res = []
const hashMap = {}
for (let i = 0; i < listArr.length; i++) {
const id = listArr[i].id
const pid = listArr[i].pid
// 创建新的hashMap属性
if (!hashMap[id]) {
hashMap[id] = { ...listArr[i], children: [] }
} else {
hashmap[id] = { ...arr[i], children: hashmap[id].children }
}
// 把根元素push到list
if (pid === 0) res.push(hashMap[id])
// 更新hashMap的children
if (hashMap[pid]) {
hashMap[pid].children.push(hashMap[id])
} else {
hashmap[pid] = { children: [] }
}
}
return res
}
32,实现flat数组拍平无deep
Array.prototype._flat = function () {
const arr = this
let res = []
arr.forEach(item => {
if (!Array.isArray(item)) {
res.push(item)
}else{
let newArr = item._flat()
res = res.concat(newArr)
}
})
return res
}
33,实现flat数组拍平带deep
Array.prototype._flat = function(deep){
const arr = this // this指向调用它的对象
let res = []
deep--
arr.forEach(item=>{
if(!Array.isArray(item) || deep<1){
res.push(item)
}else{
let newArr = item._flat(deep)
res = res.concat(newArr)
}
})
return res
}
34,实现instanceof
(用于判断变量是否属于数组,或者某个类的实例化对象)
// [1,2] instanceof Array
// const a = new Number(3)
// a instanceof Number ///true
function _instanceof(a,b){
if(!left)return false
return a.__proto__ === b.prototype || _instanceof(a.__proto__,b)
}
// 实例化对象.__proto__ === 构造函数.prototype
35,实现call
// 函数.call(this指向对象,参数1,参数2...),立即执行
// 函数.apply(this指向对象,[参数1,参数2...]),立即执行函数
// 函数.bind(this指向对象,参数1,参数2...)
// const obj = {
// name:'hi',
// getName:()=>{
// console.log(this.name)
// }
// }
Function.prototype._call = (obj,...param)=>{
obj = (obj===undefined || obj===null)?window:obj
obj.fn = this
const res = obj.fn(...param)
delete obj.fn
return res
}
36,实现apply
Function.prototype._apply = (obj,param)=>{
obj = (obj === undefined || obj === null)?window:obj
obj._fn = this
const res = obj._fn(...param)
delete obj._fn
return res
}
37,实现bind
Function.prototype._bind = (obj,param1)=>{
obj = (obj === undefined || obj === null)?window:obj
obj._fn = this
return function(param2){
const res = obj._fn(...[...param1,...param2])
delete obj._fn
return res
}
}
38,实现map
Array.prototype.map = (fn)=>{
const obj = this
let res =[]
for(var i=0;i<this.length;i++){
res.push(fn(obj[i],i,obj))
}
return res
}
39,实现lodash.get
function get(obj,attr){
const attrArr = attr.split('.')
let res=obj
attrArr.forEach(item=>{
res = res[item]
})
return res
}
40,实现Pick(TS)
type Pick<T,P extends keyof T>={
[K in P]:T[K]
}
41,实现Omit
type Exclude<T, U> = T extends U ? never : T; // 去除T中的U属性
type Omit<T,P extends keyof any> = Pick<T, Exclude<keyof T,P>>