# 笔试题

1. 实现数组扁平化
  1. 偶然发现了yield*的用法,天才级别的扁平化方式
  function* iterTree(tree){
      if(Array.isArray(tree)){
          for(let i = 0 ;i<tree.length;i++){
              yield* iterTree(tree[i]);
          }
      }else{
          yield tree;
      }
  }
 let arr1 = [1, 2, ['a', 'b', ['中', '文', [1, 2, 3, [11, 21, 31]]]], 3];
for (const x of iterTree(tree)) {
      console.log(x);
  }
  1. 利用Array.some方法判断数组中是否还存在数组,es6展开运算符连接数组
function iterTree2(arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
    }
    return arr;
}
console.log(iterTree2(arr1));
  1. 利用array数组的reduce属性,reduce回调函数有四个参数,reduce(( previousValue,currentValue,currentIndex,array)=>{},initial)

    提供了initial的值的时候,previousValue为initial的大小,currentValue为数组的第一个元素值 没有提供initial的值的时候,preciousValue为数组第一个元素的值,currentValue为第二个元素的值,此后每执行一次,previousValue

function iterTree3(arr) {
    var newArr = arr.reduce((prev, current) => {
         return prev.concat(Array.isArray(current) ? iterTree3(current) : current)
    }, []);
    return newArr;
}
console.log(iterTree3(arr1));
  1. es6中的flat函数也可以实现数组的扁平化
let arr1 = [1,2,['a','b',['中','文',[1,2,3,[11,21,31]]]],3];
 console.log( arr1.flat( Infinity ) ); 
2. 实现千分位
  1. 最最便捷的实现方式:toLocaleString()
// 注:只针对数字格式有效!
let num = 1234567890;
num.toLocaleString(); // "1,234,567,890"
  1. 正则匹配
// 正则匹配方法一
let num = 1234567890;
let reg = /\d{1,3}(?=(\d{3})+$)/g;   
String(num).replace(reg, '$&,'); //"1,234,567,890"

// 正则匹配方法二
let num = 1234567890;
let reg = /\B(?=(\d{3})+$)/g;   
String(num).replace(reg, ','); //"1,234,567,890"

// 或

const thousands = (str) => {
    // 提取整数、小数部分
    let nums = str.match(/\d+/g)
    // 利用零宽度正预测先行断言,匹配千分位
    let newStr = nums[0].replace(/\d{1,3}(?=(\d{3})+$)/g, val => {
        return val + ','
    })
    return newStr + (nums[1] ? '.' + nums[1] : '')
}
console.log(thousands('1123343412')) // 1,123,343,412
console.log(thousands('12123343412.')) // 12,123,343,412
console.log(thousands('123123343412.23')) // 123,123,343,412.23
console.log(thousands('123123343412.0923843')) // 123,123,343,412.0923843
  1. for循环
// for循环方法一
function format(num){  
  num = String(num);//数字转字符串  
  let str = '';//字符串累加  
  for (let i = num.length- 1, j = 1; i >= 0; i--, j++){  
      if (j%3 == 0 && i != 0){ //每隔三位加逗号,过滤正好在第一个数字的情况  
          str += num[i] + ','; //加千分位逗号  
          continue;  
      }  
      str += num[i]; //倒着累加数字
  }  
  return str.split('').reverse().join(""); //字符串=>数组=>反转=>字符串  
} 
let num = 1234567890;
format(num); //"1,234,567,890"

// for循环方法二
function format(num){  
  num = String(num);//数字转字符串
  let str = '';//字符串累加
  for (let i = num.length- 1, j = 1; i >= 0; i--, j++){  
      if (j%3 == 0 && i != 0){ //每隔三位加逗号,过滤正好在第一个数字的情况
          str = ',' + num[i] + str; //加千分位逗号
		 continue; 
      }  
      str = num[i] + str; //累加数字
  }  
  return str;
}
let num = 1234567890; 
format(num); //"1,234,567,890"
  1. slice+while循环
function format(num) {
  let arr = [],
      str = String(num),
      count = str.length;

  while (count >= 3) {
    arr.unshift(str.slice(count - 3, count));
    count -= 3;
  }

  // 如果是不是3的倍数就另外追加到上去
  if(str.length % 3) arr.unshift(str.slice(0, str.length % 3));

  return arr.toString();
}
let num = 1234567890; 
format(num); //"1,234,567,890"
  1. reduce
function format(num) {
  var str = num+'';
  return str.split("").reverse().reduce((prev, next, index) => {
    return ((index % 3) ? next : (next + ',')) + prev;
  })
}
let num = 1234567890; 
format(num); //"1,234,567,890"

当然也存在很多类似的写法

3. 平级父子结构树型化(tree)
var data = [
{ id: 1, name: "办公管理", pid: 0 },
{ id: 2, name: "请假申请", pid: 1 },
{ id: 3, name: "出差申请", pid: 1 },
{ id: 4, name: "请假记录", pid: 2 },
{ id: 5, name: "系统设置", pid: 0 },
{ id: 6, name: "权限管理", pid: 5 },
{ id: 7, name: "用户角色", pid: 6 },
{ id: 8, name: "菜单设置", pid: 6 },
];
var data = [
	{id: 1, name: "办公管理", pid: 0 ,
		children:[
			{ id: 2, name: "请假申请", pid: 1,
				hildren:[
					{ id: 4, name: "请假记录", pid: 2 },
				],
			},
			{ id: 3, name: "出差申请", pid: 1},
		]
    },
	{id: 5, name: "系统设置", pid: 0 ,
		children:[
			{ id: 6, name: "权限管理", pid: 5,
				hildren:[
					{ id: 7, name: "用户角色", pid: 6 },
					{ id: 8, name: "菜单设置", pid: 6 },
				]
			},
		]
	},
];
// js转换为上面数据集
function toTree(data) {
    // 删除 所有 children,以防止多次调用
    data.forEach(function (item) {
        delete item.children;
    });

    // 将数据存储为 以 id 为 KEY 的 map 索引数据列
    var map = {};
    data.forEach(function (item) {
        map[item.id] = item;
    });
    // console.log(map);
    var val = [];
    data.forEach(function (item) {
        // 以当前遍历项,的pid,去map对象中找到索引的id
        var parent = map[item.pid];
        // 好绕啊,如果找到索引,那么说明此项不在顶级当中,那么需要把此项添加到,他对应的父级中
        if (parent) {
            (parent.children || ( parent.children = [] )).push(item);
        } else {
            //如果没有在map中找到对应的索引ID,那么直接把 当前的item添加到 val结果集中,作为顶级
            val.push(item);
        }
    });
    return val;
}
console.log(toTree(data))
4. 手写new
// 创建一个新对象
// 将构造函数中的this指向该对象
// 执行构造函数代码(给新对象添加属性和方法)
// 返回者着新对象
function _new(){
    var obj = new Object(); // 创建空对象
    var func = [].shift.apply(arguments);
    obj.__proto__ = func.prototype; // 空对象原型链指向构造函数原型
    var ret = func.apply(obj,arguments);    //取得构造函数的返回值
    return typeof ret=="object"? ret : obj; //如果返回值是一个对象就返回该对象,否则返回构造函数的一个实例对象
}
5. 手写冒泡排序
// 1.	使用冒泡排序算法将数组var a = ['B','A','E','C','D'];排序为var a=['A','B','C','D','E'];请使用javascript写出全过程。
function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {        //相邻元素两两对比
                var temp = arr[j+1];        //元素交换
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}