滴滴实习一面

1、对 node 的看法;

node是 JavaScript 的运行时,基于 V8 引擎实现,其架构如下:

2、用过 node 的哪些东西;

常用的node内置模块:path、fs、http、url、zlib、stream、events 等。

回答的时候最好结合业务和应用场景一起回答;

3、let、const、var 的区别

  1. var 是ES5的语法,var 声明的变量有如下特性

    • 具有变量提升;

    • 在手动初始化之前会被系统自动初始化为 undefined 或 “”;(不同系统的实现不同)

    • 可以被重复声明而变量的值不会丢失;

    • 在最外层声明或不声明的变量会被挂载到全局对象(window、global、self)上;

    • 声明变量在所在上下文环境中不可配置,非声明变量是可配置的;

    • 对应的作用域分为全局作用域和函数内作用域;

  2. let 和 const 是 ES6 的语法

    let:

    • 没有变量提升,要先声明再使用;

    • 在块级作用域内有效;

    • 在最外层声明时不会成为全局对象的属性;

    • 在同一作用域中使用let重复声明已经存在的变量(被其它任何关键字声明的变量)会报错;

    const:

    • 声明时要赋初值;

    • 使用const声明的标识符的值无法改变(是一个常量);

    • 没有变量提升,要先声明再使用;

    • 在块级作用域内有效;

    • 在最外层声明时不会成为全局对象的属性;

    • 在同一作用域中使用const重复声明已经存在的标识符(被其它任何关键字声明的标识符)会报错;

根据这个问题,我们总结一下 JS 中声明自定义标识符的方式:var、function、let、const、class、import;总的来说,ES6 的语法趋于让 JS 变成严格模式下的 JS;

4、手写一个 new;

// 手写 new let myNew = function(constructor,...props) {      let context = Object.create(constructor.prototype);      let result = constructor.apply(context,props);      return (typeof result === 'object' && result !== null) ? result : context;      }  // 自定义构造函数 function Person(name) {     this.name = name; }  // test1:使用 myNew 和自定义构造函数 let obj = myNew(Person,'daxia'); console.log(obj); // {name:'daxia}  // test2:使用 myNew 和 JS 内置构造函数 console.log(myNew(Set,[1,2,2,3]));  // 会有如下报错: // let result = constrouct.apply(context,props); // ^ // TypeError: Constructor Set requires 'new'

当通过我的自定义 myNew 使用 JS 内置的 Set 构造函数时会报错,报错的的原因是 ES6 规定了只能通过 new 来使用 Set ,如下(截图出处:ES6):

注:有一个属性 new.target 可以在函数内部用来判断这个函数是否是被 new 调用的;

5、Promise 的用法,方法

  1. Promise 对象 有三个状态:pending、fulfilled、rejected

  2. 构造函数 Promise 的用法

    let p = new Promise((resolve,reject) => {     // 执行 resolve(),将 Promise 实例对象的状态变为 fulfilled     // 或则     // 执行 reject(),将 Promise 实例对象的状态变为 rejected })
  3. Promise 对象具有的方法

    • Promise.prototype.then()

      处理状态变为 fulfilled 的 Promise 对象的放回值;

    • Promise.prototype.catch()

      处理状态变为 rejected 的 Promise 对象的放回值;

    • Promise.prototype.finally()

      用于指定不管 Promise 对象最后状态如何,都会执行的操作。

    • Promise.prototype.all()

      传入一个由 Promise 对象组成的可迭代对象,所有 Promise 对象并发执行;

      所有 Promise 执行完后返回结果,只要有其中一个返回错误,Promise.prototype.all() 就返回错误;

    • Promise.prototype.race()

      传入一个由 Promise 对象组成的可迭代对象,所有 Promise 对象并发执行;

      返回先完成的Promise,后面的Promise不再返回;速度快的Promise对象出错时,会返回错误,但依旧会返回后面的其它Promise对象,成功返回后不再返回;

    • Promise.prototype.allSettled()

      接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束;

    • Promise.prototype.any()

      接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。

      只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

    • Promise.prototype.resolve()

      返回 fulfilled 状态的 Promise 实例;

    • Promise.prototype.reject()

      返回 rejected 状态的 Promise 实例;

    • Promise.prototype.try()

      包装任务,使同步任务和异步任务都可以用Promise来处理,使之有共同的错误处理机制;

6、Map 和 普通对象怎么转换

Map 和 普通对象 都是存储键值对的数据结构,不同的是普通对象的键只能是 String 类型 和 Symbol 类型,而 Map 的键可以是任何其它数据类型;

并且 Map 是可迭代对象,可以被 for ... of、yield* 等消费,而普通对象不是可迭代对象;

  1. Map 转 普通对象

    当 Map 的键只有 String 类型和 Symbol 类型时,转换方法可以是:

    function mapToObject(map) {  let obj = {};     for(let [key,value] of map) {         obj[key] = value;     }     return obj; } let map = new Map([['name','daxia'],['age',18]]); let obj1 = mapToObject(map); console.log(obj1);  // 或者  let obj2 = Object.fromEntries(map); console.log(obj2);

    当 map 中的键有其他类型时,要分情况考虑,如果用上面的方法键会被转换为字符串;

  2. 普通对象 转 Map

    let obj = {     name:'daxia',     age:18 } let map = new Map(Object.entries(obj));  console.log(map);

7、数组去重

1、先排序,再使用双指针一次遍历去重;
function delArrayReapet(arr) {     // 使用 sort 排序     arr.sort((a,b) => {          return a-b;     })     // 使用 双指针 去重     let i = 0,         j = 0;     let len = arr.length;     while(j < len) {          if(arr[i] === arr[j]) {             j++;         }else {             arr[++i] = arr[j]          }     }      // 改变数组长度,将重复元素都删除     arr.length = i + 1;      return arr; }
2、使用 indexOf 方法来判断某个元素是否有重复,并使用 splice 方法删除重复元素;
function delArrayReapet(arr) { // 在原数组的基础上修改          for(let i = 0;i < arr.length;) { // 注意 arr.length 是变化的;         let index = arr.indexOf(arr[i],i+1); // 得到数组中当前元素的后面的元素中相同的元素的索引         if(index !== -1) {             arr.splice(index,1); // 删除对应索引的元素         }else {             i++;         }              }      return arr; }

同样的,我们也可以使用 lastIndexOf 来得到重复元素的索引,然后使用 splice 方法删除重复元素,这里就不再写出相应代码;

3、利用 Set 不能有重复元素的特性
function delArrayReapet(arr) {       let newArr; = [...new Set(arr)];     // h     // let newArr = Array.from(new Set(arr));          return newArr;  }

更加详细的数组去重方法的介绍请看这里:

8、koa 的洋葱模型

koa的中间件(一个函数)的组织方式是以洋葱模型进行的,这类似于函数递归调用,逐层深入,然后逐层返回;

1、洋葱模式如下经典图:

2、koa中间件的使用:
const Koa = require('koa');  const app = new Koa();  // 自定义两个中间件 async function middleware1(ctx,next) {     console.log('1-1');     await next(); // 执行下一个中间件     console.log('1-2'); }  async function middleware2(ctx,next) {     console.log('2-1');     await next(); // 执行下一个中间件     console.log('2-'); }  app.use(middleware1); app.use(middleware2);  app.listen(3000);
3、实现洋葱模型简要代码

Koa 洋葱模型的主要代码实现在 koa-compose 这个模块中,简化代码如下,其依靠 函数的嵌套调用 和 Promise.resolve() 来实现;

const [fn1, fn2, fn3] = stack; const fnMiddleware = function(context){     return Promise.resolve(       fn1(context, function next(){         return Promise.resolve(           fn2(context, function next(){               return Promise.resolve(                   fn3(context, function next(){                     return Promise.resolve();                   })               )           })         )     })  ); }; 

#滴滴实习##学习路径#
全部评论
蟹蟹大佬,大佬真的强!
点赞 回复
分享
发布于 2022-01-12 15:07
我天,感觉好难啊。是日常实习吗
点赞 回复
分享
发布于 2022-02-02 23:35
秋招专场
校招火热招聘中
官网直投
请问你简历是写了熟悉node吗?
点赞 回复
分享
发布于 2022-03-31 13:16

相关推荐

5 20 评论
分享
牛客网
牛客企业服务