面试题总结

106 阅读6分钟

最近公司拆分,以及裁员,不小心部门连带我一起都了,所以无奈开始找工作,现在开始记录面试过的题目讲究的就是一个细节

8e13b212c8fcc3ced8f2325f9c45d688d43f20ab.jpg

javascript乱炖

1. == 号的转换

多的就不说了,查看相等(==) - JavaScript | MDN (mozilla.org)

要注意面试的最多的就是undefined == null,注意两点:

  1. 只有undefined == null的比较是true
  2. 有一端是undefined或者null,那另一段除了undefined或者null之外,都是false

2. 比较version之间的大小

说明:version1 > version2,就返回1version1 < version2就返回-1, 等于就返回0;

例如:

  1. 1.01.1 > 1.01 返回 1
  2. 1.01 == 1.01 返回 0
  3. 1.01 < 1.02 返回 -1
function compareVersion(version1:string ,version2:string) {
    let flag = 0;
    const processVersion1 = version1.split('.');
    const processVersion2 = version2.split('.');
    
    const maxVersion = processVersion1.length > processVersion2.length ? processVersion1 : processVersion2;
    
    for (let i = 0; i < maxVersion.length; i++) {
        const version1 = processVersion1[i] === undefined ? 0 : Number.parseInt(processVersion1[i]);
        const version2 = processVersion2[i] === undefined ? 0 : Number.parseInt(processVersion2[i]);
        
        if(version1 >  version2) {
          flag = 1;
          break;
        } else if(version1 < version2){
          flag = -1;
          break;
        }
    }
    
    return flag;
}

3. 手写Promise.all

这题比较简单,只要记住失败时,Promise.all直接变成rejected状态,并返回原因就行了。

Promise.myAll = promiseArray => {
  const result = [];
  let resolveFn;
  let rejectFn;

  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });

  promiseArray.forEach((promise, index) => {
    promise.then(
      value => {
        result[index] = value;

        if (
          result.filter(_ => _ !== undefined).length === promiseArray.length
        ) {
          resolveFn(result);
        }
      },
      reason => {
        rejectFn(reason);
      },
    );
  });

  return promise;
};

const a = Promise.myAll([Promise.reject(1), Promise.resolve(2)]);
const b = Promise.myAll([Promise.resolve(1), Promise.resolve(2)]);

setTimeout(() => {
  console.log(a);
});

setTimeout(() => {
  console.log(b);
});

4. 手写Promise.allSettled

Promise.all一样,只要记住allSettled返回value结构是怎么样的就行了

Promise.myAllSettled = promiseArray => {
  const result = [];
  let resolveFn;

  const promise = new Promise(resolve => {
    resolveFn = resolve;
  });

  promiseArray.forEach((promise, index) => {
    promise.then(
      value => {
        result[index] = { status: 'resolved', value };

        if (
          result.filter(_ => _ !== undefined).length === promiseArray.length
        ) {
          resolveFn(result);
        }
      },
      reason => {
        result[index] = { status: 'reject', reason };

        if (
          result.filter(_ => _ !== undefined).length === promiseArray.length
        ) {
          resolveFn(result);
        }
      },
    );
  });

  return promise;
};

const a = Promise.myAllSettled([Promise.reject(1), Promise.resolve(2)]);
const b = Promise.myAllSettled([Promise.resolve(1), Promise.resolve(2)]);

setTimeout(() => {
  console.log(a);
});

setTimeout(() => {
  console.log(b);
});

5. 什么是闭包,你都有哪些应用?

闭包就是函数携带其它函数环境内变量的一种形式

应用:写一个简单的useLock函数,用于等待函数执行完成,期间其它触发都会被取消,常用于滚动到底部时的数据加载

const useLock = (fn: (...args: any[]) => any) => {
  let isLock = false;

  return async (...args: any[]) => {
    if (isLock) return;

    isLock = true;
    await fn(...args);
    isLock = false;
  };
};

const lock = useLock(async () => {
  await new Promise(resolve => {
    setTimeout(() => {
      resolve(2);
    }, 1000);
  });

  console.log('end');
});

lock();
lock();
lock();
lock();
lock();
lock();

之前遇到个略微刻薄的面试官,原题是“什么是闭包,你都在哪里用到过闭包”,我以为只是让我解释一下闭包,并说明闭包在哪些情况下存在现在想想他说的应该是有哪些应用,由于我说的都是存在的场景,于是他非常没耐心的结束了面试🥺。实际上这才第二个问题。。。

6. 有一个盒子,宽高100px,里面的item,宽高20px,请实现如下布局

7.请用递归计算1到100的总和

function getTotal( value:number ) {
    if(value === 1) return 1;
    const result = value + getTotal(value - 1);
    return result
}

getTotal(100)

8.微信小程序写个dialog

9.gif

直接看代码 dialog

写一个changeName()达到一下效果

这题竟然没看最后的一行的结果,哭了。

const departmentList1 = [{name:'Bob'}, {name:'Develop'}, {name:'Alice'}]

const departmentList2 = changeName('Bob','Dialog',departmentList1);

console.log(departmentList2[0].name); // Dialog

console.log(departmentList2[1].name); // Develop

console.log(departmentList2[2].name); // Alice

console.log(departmentList1[0].name); // Bob

const changeName = (name,value,arr)=>{
  const newArr = [...arr];
  const targetIndex = newArr.findIndex(_=>_.name === name)
  newArr[targetIndex] = {...newArr[targetIndex] ,name: value};
  return newArr;
}

数组打平

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

  const flatArray = arr => {
    function getArray(arr = [], see = []) {
      return arr.reduce((pre, current) => {
        if (Array.isArray(current)) {
          getArray(current, see);
        } else {
          pre.push(current);
        }
        return pre;
      }, see);
    }
    return [...getArray(arr).values()];
  };

  console.log(flatArray(arr));
  1. flat

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

  console.log(arr.flat(Number.POSITIVE_INFINITY));

算最大公共长度字符串

例子: 给出一个数组['flight','flior', 'flmor'],计算最大公共字符串为fl

function getCommon(arr){
   const firstString = arr[0];
   const otherStringArray = arr.slice(1);
   let common = '';
   
   for(let i = 0; i < firstString.length; i++) {
      let flag = true;
      
       for(let b of otherStringArray) {
            if(b[i] === firstString[i]) {
                break;
            } else {
              flag = false;
              break;
            }
       }
      if(flag) {
         common += firstString[i]  
      }
   }
   
   return common;
}

阿里外包算法一

/**
 * 简单实现一个queryString,具有parse和stringify的能力,
 * parse,用于把一个URL查询字符串解析成一个键值对的集合。
 * 输入:查询字符串 'foo=bar&abc=xyz&abc=123'
 * 输出:一个键值对的对象
 * {
 *   foo: 'bar',
 *   abc: ['xyz', '123'],
 * }
 */

function parse(input = 'foo=bar&abc=xyz&abc=123') {
  const queryStringArr = input.split('&').map(_ => _.split('='));

  const result = {};

  queryStringArr.forEach(_ => {
    const prop = _[0];
    const value = _[1];

    if (prop in result) {
      if (Array.isArray(value)) {
        result[prop].push(value);
      } else {
        result[prop] = [result[prop]].concat(value);
      }
    } else {
      result[prop] = value;
    }
  });

  return result;
}

webpack

plugin和loader有什么区别

chatgpt的回答

Webpack 中的插件(Plugin)和加载器(Loader)是两个不同的概念,它们分别用于不同的任务,主要区别如下:

  1. 功能和作用:

    • Loader:加载器用于转换非 JavaScript 文件(例如,CSS、图片、字体等)成模块,以便可以在 JavaScript 中引入。它们主要处理模块的加载和转换。
    • Plugin:插件用于执行一些特定的任务,如代码压缩、文件拷贝、环境变量注入、生成 HTML 文件等。插件可以扩展 Webpack 的功能,但它们通常不会处理模块的转换。
  2. 配置位置:

    • Loader:Loader 配置通常位于 module.rules 中,用于指定文件类型和相应的加载器。
    • Plugin:Plugin 配置位于 plugins 中,用于指定需要执行的插件。
  3. 使用场景:

    • Loader:主要用于处理模块的加载和转换,例如将 Sass 文件转换为 CSS,将图片文件转换为 base64 字符串,或将 TypeScript 转换为 JavaScript。
    • Plugin:主要用于执行各种构建任务,如生成 HTML 文件、拷贝静态资源、代码分离、压缩、代码分析、环境变量注入等。
  4. 执行时机:

    • Loader:在模块加载过程中执行,用于将非 JavaScript 模块转换为可导入的 JavaScript 模块。
    • Plugin:在 Webpack 构建过程的不同阶段执行,例如在编译、输出文件、压缩、热模块替换等各个阶段。

总之,Loader 主要用于处理模块级别的任务,将非 JavaScript 文件转换为 JavaScript 模块,而插件用于执行更高级别的构建任务,扩展和增强 Webpack 的功能。它们在 Webpack 配置中各自发挥着不同的作用。

总结一句话

loader主要用于解析处理资源,而plugin主要是用来加强webpack的功能。

typescript

type和interface有什么区别

实际上如果只用于标明类型的话,type基本可以实现interface的所有功能

继承(泛化)

interface

interface a { name: string; }
interface b extends a { sex: string; }

type

type a = { name: string; }
type b = a & { sex: string; }

标明函数类型以及函数重载

interface

interface a {
  (): void; // 普通调用
  (a: string): void; // 重载

  new(): Date; // 构造函数
}

type

type a = {
  (): void; //普通调用
  (a: string): void; //重载

  new(): Date; // 构造函数
}

// 或者这样写构造函数
type a = new () => Date;

但是interface强大的地方就在于,它可以扩展全局对象,当然这也与interface合并特性有关。也是和type的主要区别

举个例子

给全局Date对象加个format

interface Date {
  format(template: string): string
} 

image.png

当然如果你想给Date构造函数添加一个format

interface DateConstructor {
  format(template: string): string
}

image.png

在线看

当然interface作为接口的话,那还有一个特性就是implements之后,必须被实现。这也是和type的一个区别。

持续更新中。。。