JS小知识

71 阅读5分钟

1.求余与求模的区别

求余公式:x rem y => x-fix(x/y)*y

注:求余是向0取整

eg: -5%2 => -5 - (-2)*2

求余公式:x rem y => x-floor(x/y)*y 注:求余是向下取整

eg: -5%2 => -5 - (-3)*2

2.堆栈### 区别和特点

栈(stack):

存放基础数据类型的值和基础数据类型(string,number,boolean,null(是对象类型,但是存在栈中,因为大小可控),undfined)、引用数据类型的地址指针。

同样的值数据共享,如果两个变量值一样,可以一起指向那个值。

系统自动分配,大小相同;系统自动释放。

先进后出(FILO)

内存较小,读取速度快。

栈内存中的变量不会与其他栈内存的变量名冲突,我们也叫作作用域。

堆(heap):

存放引用数据类型object,array,function)。

动态分配内存,内存大小不固定。不会自动释放内存。

数据结构是一种无序的树状结构。

容量比较大,读取速度稍慢。

不允许js直接访问堆内存,按引用访问。

3.垃圾回收机制(标记清除、引用计数)

栈:变量基本上用完就回收了。局部变量在函数执行完成后销毁。全局变量在页面退出是销毁。

堆:堆内存中的对象不会随方法的结束销毁,就算方法结束了,这个对象也可能会被其他引用变量引用(参数传递)。创建对象是为了反复利用,(因为对象的创建成本通常较大),这个对象将被保存到运行时数据区(也就是堆内存)。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。每种浏览器的javascript解释引擎有不同的自动回收方式,但一个基本的原则是:如果栈中不存在对堆中某个对象的引用,那么就认为该对象已经不再需要,在垃圾回收时就会清除该对象占用的内存空间。在不需要某对象时应该将对对象的引用注释掉,以利于垃圾回收,这样就可以提高程序的性能。释放对对象的应用最常用的方法就是为其赋值为null。

4.排序方式

a.快速排序: 将未排序的数据的第一个数据作为对比基准,在除了已排序和基准数据以外的数据里找到最小的数据,将该数据和基准数据进行交换。

	// 选择排序
    const choseArr = [5,2,1,3,6,8,4,5,7,0,15];
    for (let i = 0; i < choseArr.length-1; i++) {
      let minIndex = i; //用于存储最小值的下标,排序刚开始时,假设最小值的下标就是选中的基准数据下标
      for (let j = i+1; j < choseArr.length; j++) {
        if (choseArr[j] < choseArr[minIndex]) {
          minIndex = j;
        }
      }
      [choseArr[i],choseArr[minIndex]] = [choseArr[minIndex],choseArr[i]]
    }
    console.log(choseArr,'----------------------选择排序');
    // [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 15] '----------------------选择排序'

b.快速排序: 取数组的中间值为基准数据,把数组中剩余的小于基准数据的数据放在基准数据的左边的新数组中,大于的放在右边的新数组中,再分别将这两个新数组按照原数组取中间值,划分左右新数组的方法进行递归,最后即可得到排序好的数组。

	// 快速排序
    const quickArr = [5,2,1,3,6,8,4,5,7,0,15];
    function quickFun(params) {
    	//当进行递归的数组的长度小于等于 1 的时候直接返回该数组
      if (params.length <= 1) {
        return params;
      }
      let middleIndex = Math.floor(params.length / 2); //获取基准数据的下标
      let middleItem = params.splice(middleIndex,1)[0]; //截取基准数据
      let leftArr = [];
      let rightArr = [];
      for (let k = 0; k < params.length; k++) {
        if (params[k] > middleItem) {
          rightArr.push(params[k]);
        }else{
          leftArr.push(params[k]);
        }
      }
      return quickFun(leftArr).concat(middleItem,quickFun(rightArr)); //将左边数组,基准数据和右边数组进行拼接成一个完整的数组
    }
    const quickAns = quickFun(quickArr);
    console.log(quickAns,'----------------------快速排序');
    // [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 15] '----------------------快速排序'

c.冒泡排序: 数组中的数据前后两两进行对比,如果后面一个数据小于前面一个则进行交换。

	// 冒泡排序
    const popArr = [5,2,1,3,6,8,4,5,7,0,15];
    // 因为是前后两两排序,所以只需要数组长度-1 次遍历即可
    for (let g = 0; g < popArr.length-1; g++) {
      for (let h = 0; h < popArr.length-1; h++) {
        if (popArr[h] > popArr[h+1]) {
          [popArr[h],popArr[h+1]] = [popArr[h+1],popArr[h]];
        }
      }
    }
    console.log(popArr,'----------------------冒泡排序');
    // [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 15] '----------------------冒泡排序'

d.插入排序: 以数组的第一个数据为基准,想象成一个只有一个数据的数组,将剩下的数据依次插入基准数据所在的数组中合适的位置。

	// 插入排序
    const pickArr = [5,2,1,3,6,8,4,5,7,0,15];
    function pickFun(params){
      let preIndex = 0; // 进行大小对比的基准数据的下标
      let current = 0; // 进行大小对比的当前选中的剩余数量值
      for (let g = 1; g < params.length; g++) {
        preIndex = g - 1; // 进行基准数据赋值
        current = params[g]; // 获取当前进行对比的剩余数量值
        while(preIndex >= 0 && params[preIndex] > current){
          params[preIndex+1] = params[preIndex];
          preIndex--;
        }
        params[preIndex+1] = current;
      }
      return params;
    }
    const pickAns = pickFun(pickArr);
    console.log(pickAns,'----------------------插入排序');
    // [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 15] '----------------------插入排序'

e.希尔排序: 基于插入排序进行的优化,先将整个数组按照数组长度的一半进行分组使用插入排序,完成后,再将整个数组按照数组长度的1/4进行分组使用插入排序,重复以上步骤,直到分组长度为1为止。

	// 希尔排序
    const hillArr = [5,2,1,3,6,8,4,5,7,0,15];
    function hillFun(arr){
      //第一层循环,确定间隔数
      // 这里的 gap 相当于插入排序中的 1 ,所以在第二层循环中 preIndex = i-gap; 相当于插入排序中的 preIndex = g - 1;
      for(let gap = parseInt(arr.length/2); gap > 0 ; gap = parseInt(gap/2)){
        //第二层循环,使用插入排序
        for(let i = gap ; i < arr.length ; i++){
          let preIndex = i-gap;
          let current = arr[i]
          while(preIndex >=0 && current < arr[preIndex]){
              arr[preIndex + gap] = arr[preIndex];
              preIndex -= gap;
          }
          arr[preIndex+gap] = current
        }
      }
      return arr;
    }
    const hillAns = hillFun(hillArr);
    console.log(hillAns,'----------------------希尔排序');
    // [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 15] '----------------------希尔排序'