1、json下划线key转驼峰命名
解题核心:
1、正则表达式,/_(\w)/g
2、replace方法
实现:
function convert(jsonObj){
let jsonStr = JSON.stringify(jsonObj);
// 核心正则表达,字符串的replace方法
let formatStr = jsonStr.replace(/_(\w)/g, (all, letter,index,str)=>{
return letter.toUpperCase();
});
return JSON.parse(formatStr)
}
console(convert([{'de_fff_dd':{'n_ff_dd':'222'}},{'ab_cd_ef':'1111'}]))
2、最简便的list数据转树形结构方法
function arrayToTree (arrlist,pid){
let result = [];
let arr = arrlist;
arr.forEach((item,index)=>{
if(item.parentId === pid){
// 递归调用该方法
if(arrayToTree(arr,item.id).length>0){
arr[index].children = arrayToTree(arr,item.id)
}
result.push(arr[index])
}
})
return result;
}
var list = [
{ name: '根目录1' , id: 1, parentId: 0 },
{ name: '根目录2' , id: 2, parentId: 0 },
{ name: '目录1-1' , id: 3, parentId: 1 },
{ name: '目录1-2' , id: 4, parentId: 1 },
{ name: '目录2-1' , id: 5, parentId: 2 },
{ name: '目录1-2-1' , id: 6, parentId: 4 }
];
console.log(arrayToTree(list,0));
3、至少三种排序
var arr=[3,5,7,2,1,8]
// 冒泡排序,大的沉底,双重循环,外层循环从结束到开始,内层循环从开始到外层节点。交换在内层循环
function bubbleSort(arr){
if(arr ===null || arr.length===0 ){
return []
}
let len = arr.length;
for(let i =len; i>=0; i--){
for(let j=0;j<=i;j++){
if(arr[j]>arr[j+1]){
warp(arr,j,j+1)
}
}
}
return arr
}
function warp(arr,i,j){
let temp = arr[i]
arr[i] = arr[j];
arr[j] = temp;
return arr
}
//bubbleSort(arr)
// 选择排序, 查找最小的放到最前面,内层循环找出最小书index,交换在外层循环
function selectSort(arr){
if(arr===null && arr.length===0){
return []
}
let len = arr.length
for(let i=0;i<len-1;i++){
let minIndex = i;
for(let j=i+1;j<len;j++){
minIndex = arr[j]<arr[minIndex]?j:minIndex
}
warp(arr,i,minIndex)
}
return arr
}
// selectSort(arr)
// 插入排序 ,外层循环定插入范围,内层循环在范围内冒泡排序
function insertSort(arr){
if(arr=== null ||arr.length===0 ){
return []
}
for(let i=1;i<arr.length;i++){
for(let j=i-1;j>=0;j--){
if(arr[j]>arr[j+1]){
warp(arr,j,j+1)
}
}
}
return arr
}
insertSort(arr)
4、防抖与节流
防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
function debounce(fn,delay){
let timer = null
return function (){
clearTimeout(timer)
timer=setTimeout(()=>{
//使用apply解决两个问题
//①不知道以后需要防抖的函数到底有多少个参数,用arguments来接受。
//②如何将arguments传回给需要防抖的函数。
fn.apply(this,arguments)
},delay)
}
}
function print (name){
console.log('我是',name)
}
debounce(print,2000)('jake') // 2秒以后打印 我是jake
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。
// 节流,定时器
function throttleTimer(fn,wait){
let flag=true;
return ()=>{
if(!flag)return
setTimeout(()=>{
flag = false;
fn.apply(this,arguments)
},wait)
}
}
// 节流 时间戳
function throttle(fn,delay){
let start = Date.now()
return function(){
let now = Date.now()
if(now-start>=delay){
fn.apply(this,arguments)
start=Date.now()
}
}
}
5、"abc123 ,def456",反转字母,其他位置不变。
原生方法:
- 取出字符串中字母部分,拆成数组,翻转
拼接回原先的字符串
var a="abc123 ,def456";
//用split将a拆成数组b,b=[['a','b','c','1','2','3',' '],['d','e','f','4','5','6']]
var b= a.split(',').map((item)=>{return item.split(''); });
var result=[];
b.forEach((item)=>{ for (var i = 0; i < item.length; i++) { if (!isNaN(Number(item[i]))) { result.push(item.splice(0,i).reverse().concat(item).join('')); break } } }) //最终得到的result数组中包含两项,cba123 ,fed456,用','进行拼接。得到最终结果。只针对这个或这种类型的字符串,如果存在字母前面有特殊字符,操作会跟麻烦,
还是推荐用正则处理:
var result = a.replace(/([a-zA-Z]+)/g,str => str.split('').reverse().join(''))
6、数组字符出现的次数
let arr1=['a','b','c','a','d','a']
// 字符出现次数,出现次数最多字符
function count(arr,word){
let obj = {}
arr.forEach((item)=>{
if(obj[item]!==undefined){
obj[item]+=1
}else{
obj[item]=1
}
})
console.log(obj)
}
count(arr1)
6、数组扁平化
方法一:递归
var arr3 = [1,[2,3],[2,[1,3]],[[2,4],[2,8]]]
function flaten(arr){
let result = [];
arr.forEach((item)=>{
if(Array.isArray(item)){
result = result.concat(flaten(item))
}else{
result.push(item)
}
})
return result
}
console.log(flaten(arr3))
方法二:reduce递归
function flatenReduce (arr){
return arr.reduce((res,item)=>{
return res.concat(Array.isArray(item)?flatenReduce(item):item)
},[])
}
console.log(flatenReduce(arr3))
7、深拷贝
1、乞丐版
let obj = {a:1,b:2,c:3}
let newObj = JSON.stringify(obj)
let target = JSON.parse(newObj)
为什么说它是乞丐版的呢?
那是因为 使用JSON.stringify()以及JSON.parse()它是不可以拷贝 undefined , function, RegExp 等等类型的
2、Object.assign
var obj1 = {
a: 1,
b: 2,
c: 3
}
var obj2 = Object.assign({}, obj1);
obj2.b = 5;
console.log(obj1.b); // 2
console.log(obj2.b); // 5
可以看到对于一层对象来说是没有任何问题的,但是如果对象的属性对应的是其它的引用类型的话,还是只拷贝了引用,修改的话还是会有问题
3、递归拷贝
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if(target===null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if(target.constructor===RegExp){
result = target;
}else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}
8、手写promise
// 1、 promise是个类,构造函数接收一个函数,函数有两个参数,参数也都是函数
// 2、 传入的函数中执行resolve表示成功,执行reject表示失败,传入的值会传给then方法的回调函数
// 3、 promise返回then方法,该方法有两个参数,一个是执行成功的回调函数,一个是执行失败的回调函数,
// then方法需要在resolve或者reject执行完成后执行,并且then方法中的值是作为ressolve或reject的参数
// 4、promise支持链式调用,then返回new promise
class myPromise {
static pendding = 'pendding';
static fulfilled = 'fulfilled';
static rejected = 'rejected';
constructor(executor) {
this.status = myPromise.pendding; // 初始状态为pendding
this.value = undefined; // 储存 resolve 即操作成功返回的值
this.reason = undefined; // 储存 reject 即操作失败返回的值
// 用于存储then中传入的参数,定义为数组是因为promise的then会被调用多次
this.callbacks = [];
// 绑定this防止执行时this的指向改变
executor(this._resolve.bind(this), this._reject.bind(this));
}
// onFulfilled 成功的回调函数
// onRejected 失败的回调函数
then(onFulfilled, onRejected) {
// 将需要执行的回调函数储存起来
// this.callbacks.push({
// onFulfilled,
// onRejected,
// });
// 返回一个新 promise
return new myPromise((nextOnFulfilled, nextOnRejected) => {
// 这里之所以把下一个Promsie的resolve函数和reject函数也存在callback中
// 是为了将onFulfilled的执行结果通过nextResolve传入到下一个Promise作为它的value值
this._handler({
onFulfilled,
onRejected,
nextOnFulfilled,
nextOnRejected,
});
})
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally){
return this.then(onFinally, onFinally);
}
_resolve(value) {
if (value instanceof myPromise) {
value.then(
this._resolve.bind(this),
this._reject.bind(this),
);
return;
}
this.value = value;
this.status = myPromise.fulfilled;// 设置状态为成功
// 通知事件执行
this.callbacks.forEach((cb) => this._handler(cb));
}
_reject(reason) {
if (reason instanceof myPromise) {
reason.then(
this._resolve.bind(this),
this._reject.bind(this),
);
return;
}
this.reason = reason;
this.status = myPromise.rejected; // 设置状态为失败
this.callbacks.forEach((cb) => this._handler(cb));
}
_handler(callback) {
const { onFulfilled, onRejected, nextOnFulfilled, nextOnRejected } = callback;
if (this.status === myPromise.pendding) {
this.callbacks.push(callback);
return;
}
if (this.status === myPromise.fulfilled) {
// 传入储存的值
// 未传入 onFulfilled 时,将 undefined 传入
const nextValue = onFulfilled ? onFulfilled(this.value) : this.value;
nextOnFulfilled(nextValue);
return;
}
if (this.status === myPromise.rejected) {
// 传入储存的错误信息
const nextReason = onRejected ? onRejected(this.reason) : this.reason;
nextOnRejected(nextReason);
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。