2023年一位大三学生的一些中大厂的面试题分享(包含干货分享)

2,447 阅读9分钟

前言

本人双非大三在读,最近凭借着一些好运,拿了同程旅行,脉脉,云鲸智能,公交云的offer。

最后当然还是选择打算去同程了,因为谁叫它是暑期实习呢,其他的日常实习学校不放人,也是没有办法。然后现在我就想把我最近碰到的一些面试题分享给有需要的友友们,希望大家也能尽早找到满意的实习offer!

滴滴

开年第一场没想到竟然是滴滴的面试

image.png

题目一:主要考察的就是闭包的知识,这里还需要和面试官聊聊什么是闭包,以及闭包的副作用。

题目二:就是考察的词法作用域的知识,这里面的内容可以参考我的这篇文章

🐟 🐟包教包会——作用域链+闭包 - 掘金 (juejin.cn)

image.png 这里也是很基础的问题,就是考察箭头函数中的this指向问题

image.png 这题的结果很简单,自然同时打印666666 6个6了

扩展,如果按顺序打印怎么办

    1. let取代var
    for (let i = 1; i <= 5; i++) {
        setTimeout(function () {
            console.log(i);
        }, 0)
    }  // 1 2 3 4 5
    
    1. 自执行函数
    for (var i = 1; i <= 5; i++) {
        (function (i) {
            setTimeout(function () {
                console.log(i);
         }, 0)
    })(i)
    }
    

    在每次循环中,使用立即执行函数(IIFE)创建一个新的作用域,将循环变量i作为参数传递给它

4.看代码写输出 image.png 这类题目自然也是不难,具体讲解也可以看看我的这篇文章

⭐⭐从一道经典题来弄懂Eventloop(搞不懂算我输) - 掘金 (juejin.cn)

5. 实现一个函数find(obj, str),满足:

var obj = {a:{b:{c:1}}};

find(obj,'a.b.c') //1

find(obj,'a.d.c') //undefined

image.png

这里面试官还问了我align-item与align-content的区别

image.png 这里考察的就是css权重计算了

- 权重计算规则
    1. 第一优先级:!important 会覆盖页面内任何位置的元素样式
    2. 内联样式,如style:"color:green",权值为1000
    3. ID选择器,如#app,权值为0100
    4. 类、伪类、属性选择器,如.foo, :first-child, div[class="foo"],权值为0010
    5. 标签、伪元素选择器,如div::first-line,权值为0001
    6. 通配符、子类选择器、兄弟选择器,如*, >, +,权值为0000
    7. 继承的样式没有权值 

9. 用promise如何实现异步加载图片,说下大概思路

1. 创建一个Promise对象,该对象包含一个异步操作,例如加载图片。
2. 在异步操作中,使用Image对象加载图片,并监听其onload和onerror事件。
3. 如果图片加载成功,调用resolve方法,并将Image对象作为参数传递给resolve方法。
4. 如果图片加载失败,调用reject方法,并将错误信息作为参数传递给reject方法。
5. 在使用异步操作时,调用Promise对象的then方法,如果图片加载成功,则在then方法中获取Image对象并使用它;如果图片加载失败,则在catch方法中处理错误。

示例代码如下:

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = function() {
      resolve(img);
    };
    img.onerror = function() {
      reject(`Failed to load image from ${url}`);
    };
    img.src = url;
  });
}

loadImage('https://example.com/image.jpg')
  .then(img => {
    console.log('Image loaded:', img);
    // 使用加载成功的图片
  })
  .catch(error => {
    console.error(error);
    // 处理加载失败的情况
  });

小结:

滴滴的面试题还是比较经典的,只可惜当时自己八股文和一些js基本概念题掌握的还是不牢,这里面最多也就答出了一半左右,毫无疑问,一面就凉凉了。

云鲸智能

这是一家位于深圳的中厂,据我了解是做扫地机器人的公司。

1. 介绍react hook

这里之前面试的时候已经被讲烂了,大部分就是

- React Hooks的几个常用钩子
    1. useState() 状态钩子
    2. useContext() 共享状态钩子
    3. useReducer() action钩子
    4. useEffect() 副作用钩子
    5. useCallback() 缓存了函数自身
    6. useMemo() 缓存了函数的返回值

2. setState 何时重新渲染

这里更准确的应该是问,useState中的第二个返回值何时渲染或者useState的副作用是什么?

使用 useState 时,大概的过程是,第一次渲染 react 会创建一个对应的 state(如下 count),和一个更新值的方法(如下 useState)。当点击 Click me 按钮调用 setCount,通知 react 更新对应的 state 即更新 count,更新完后,react 调用函数组件进行第二次渲染。

  • 关于useStatesetState的更新特点 但是 useState 有一点值得注意,就是当调用改变 state 的函数dispatch,在本次函数执行上下文中,是获取不到最新的 state 值的,把上述demo 如下这么改:

    function App() {
    const [count, setCount] = useState(0);
    
    const handleClick = () => {
      setCount(2);
      func(); // 点击后打印 0
    };
    
    const func = () => {
      console.log(count);
    };
    
    return (
      <div className="App">
        <button onClick={handleClick}>点击</button>
      </div>
      );
    }
    

因为在react合成事件中改变状态是异步的,出于减少render次数,react会收集所有状态变更,然后比对优化,最后做一次变更,在代码中可以看出,func的调用和setCount在同一个宏任务中,这是react还没有render,所以直接使用count获取的肯定是上一次闭包里的值0

3. jwt鉴权

开始问了项目的细节

这里也可以看我的这篇文章

❤️❤️包教包会——Cookie、Session、Token、JWT - 掘金 (juejin.cn)

4. 垃圾回收机制

垃圾回收策略一般分为手动回收自动回收,java python JavaScript等高级预言为了减轻程序员负担和出错概率采用了自动回收策略。

JavaScript的原始类型数据和引用数据是分别存储在中的,由于栈和堆分配空间大小差异,垃圾回收方式也不一样。

中分配空间通过ESP(记录当前执行状态的指针)的向下移动销毁保存在栈中数据;

中垃圾回收主要通过副垃圾回收器(新生代)和主垃圾回收器(老生代)负责的

新生代区域:存放的是生存时间短的对象 老生代: 存放的生存时间久的对象

副垃圾回收器,主要负责新生代的垃圾回收 主垃圾回收器,主要负责老生代的垃圾回收

副垃圾回收器采用scavenge算法将区域分为对象区域空闲区域,通过两个区域的反转让新生代区域无限使用下去。

    新加入的对象都会存放到对象区域,当对象区域快被写满时,就需要执行一次垃圾清理操作。
    在垃圾回收过程中,首先要对对象区域中的垃圾做标记;标记完成之后,就进入垃圾清理阶段,
    副垃圾回收器会把这些存活的对象复制到空闲区域中,同时它还会把这些对象有序地排列起来,
    所以这个复制过程,也就相当于完成了内存整理操作,复制后空闲区域就没有内存碎片了。

主垃圾回收器采用标记-清除标记-整理进行空间回收的。

新生代的晋升策略(两次未清除的),大对象直接分配在老生代。

无论是主副垃圾回收器的策略都是标记-清除-整理三个大的步骤。

5. ts有哪些了解

这里可以多讲一些ts中的类型,如果实在不知道的话,也可以聊一聊typeinterface,然后这里面试官肯定会问你它们两者的区别,要记得反客为主,带一波面试官的节奏~

这里介绍一下typeinterface的区别

  1. 定义基本类型别名:

    type 可以定义基本类型别名, 但是interface无法定义,如:

    type userName = string
    type stuNo = number
    
  2. interface 可以声明合并

    interface test {
        name: string
    }
    interface test {
        age: number
    }
    
    
  3. interface 可以使用extends关键字

    interface 支持 extends 和 implements 关键字:interface 可以使用 extends 关键字继承另一个接口,并且可以使用 implements 关键字来实现一个接口。但是,type 不支持这两种关键字。

type: 主要用来给其他类型起别名,常用来简化复杂的类型定义,或者为某些类型定义别名,便于代码的阅读和维护。

interface:用来定义类的形状或对象的形状,用来对对象的类型进行描述,例如属性方法

6.说一下http缓存

  • HTTP 缓存分为两种,一种是强缓存,另一种是协商缓存。主要作用是加快资源获取速度,提升用户体验,减少网络传输,缓解服务端压力。

强缓存

  1. 当初次请求时,浏览器会向服务器发起请求,服务器接收到浏览器的请求后,返回资源并返回一个响应头中的 Cache-Control 给客户端,该 Cache-Control 一般设置缓存的最大过期时间。
  2. 再次请求时,此时浏览器已经接收到 Cache-control 的值,那么这个时候浏览器再次发送请求时,它会先检查它的 Cache-control 是否过期,如果没有过期则直接从本地缓存中拉取资源,返回到客户端,而无需再经过服务器。

协商缓存

  1. 客户端第一次向服务器发出请求,则服务器返回资源和相对应的资源标识给浏览器。该资源标识就是对当前所返回资源的一种唯一标识,可以是 Etag 或者是 Last-Modified
  2. 之后如果浏览器再次发送请求时,浏览器就会带上这个资源标识。此时,服务端就会通过这个资源标识,可以判断出浏览器的资源跟服务端此时的资源是否一致,如果一致,则返回 304,即表示 Not Found 资源未修改。如果判断结果为不一致,则返回 200,并返回资源以及新的资源标识。至此就结束了协商缓存的过程。
  • Last-Modified
  1. 当浏览器第一次发送请求时,服务器返回资源并返回一个 Last-Modified 的响应头给浏览器。这个 Last-Modified 的值给到浏览器之后,浏览器会通过 If-Modified-Since 的字段来保存 Last-Modified 的值,且 If-Modified-Since 保存在请求头当中。

  2. 之后当浏览器再次发送请求时,请求头会带着 If-Modified-Since 的值去找服务器,服务器此刻就会匹配浏览器发过来的 If-Modified-Since 是否和自己最后一次修改的 Last-Modified 的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回 200,并返回资源和新的 Last-Modified 的值。

  • Etag

    1. 当浏览器第一次发送请求时,服务器返回资源并返回一个 Etag 的值给浏览器。这个 Etag 的值给到浏览器之后,浏览器会通过 If-None-Match 的字段来保存 Etag 的值,且 If-None-Match 保存在请求头当中。

    2. 之后当浏览器再次发送请求时,请求头会带着 If-None-Match 的值去找服务器,服务器此刻就会匹配浏览器发过来的 If-None-Match 是否和自己最后一次修改的 Etag 的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回 200 ,并返回资源和新的 Etag 的值。

7.Etag 和 last-modified的区别

Last-Modified是通过最后一次修改时间来判断资源是否发生改变

Etag是用hash内容对比判断是否资源发生改变

8.懒加载原理

懒加载的实现过程是,当用户滚动到页面中的某个区域时,该区域内的资源才会被加载。这样可以减少页面的加载时间,提高用户体验。在前端开发中,通常使用JavaScript来实现懒加载。

9. egg.js了解多少

10.React.Memo了解吗

正好撞到我之前写的文章上去了

🔥 你真的了解React.memo吗? - 掘金 (juejin.cn)

小结: 这家公司挺好的,当时是真的特别想去,因为两个面试官都比较有趣,想着能学到不少的东西吧。

公交云

1.箭头函数和普通函数的区别

  1. this 指向不同

    对于普通函数来说,内部的 this 指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的 this 对象,内部的 this 就是定义时上层作用域中的 this

    也就是说,箭头函数内部的 this 指向是固定的,相比之下,普通函数的 this 指向是可变的。

    var name = '图图'
    var person = {
        name: 'tt',
        say: function() {
            console.log('say:',this.name)
        },
        say2: () => {
            console.log('say2:',this.name)
        }
    }
    person.say() // say: tt
    person.say2() // say2: 图图
    

这里第一个 say 定义的是一个普通函数,并且它是作为对象 person 的方法来进行调用的,所以它的 this 指向的就是 person,所以它应该会输出 say: tt

而第二个 say2 定义的是一个箭头函数,我们知道箭头函数本身没有 this,它的 this 永远指向它定义时所在的上层作用域,所以 say2 的 this 应该指向的是全局 window,所以它会输出 say2:图图

  1. 箭头函数没有原型 prototype
let fn = name => {
    console.log(name)
}
let fn2 = function(name) {
    console.log(name)
}
console.log(fn.prototype) // undefined
console.dir(fn2.prototype) // {constructor: ƒ}
  1. 箭头函数不能当成一个构造函数
    let fn = name => {
    console.log(name)
    }

    const f = new fn('nanjiu')
  1. 箭头函数没有自己的 arguments
  let fn = name => {
      console.log(arguments)
  }
  let fn2 = function(name) {
      console.log(arguments)
  }
  fn2() // Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
  fn()  // 报错 Uncaught ReferenceError: arguments is not defined

2.Mao和Object的区别

  • 构造方式不同

    JavaScript 中创建 Object 最简单的方法是通过字面量。
          const smbObj = {
          1: 'ShowMeBug',
          2: 'ShowMeMoney'  
          };
    
      Map 则是通过内置构造函数 Map 创建。
      const smbMap = new Map([
      [1, 'ShowMeBug'],
      [2, 'ShowMeMoney']
      ]);
    
  • 对象中的键是字符串,映射中的键可以是任意类型

      Object 是键值对的集合,但键只能是字符串。而 Map 的键可以是任意类型。
      比如,如果用数字作 Object 的键,则该数字将转换为字符串。
      因为键已经被转换成字符串,所以无论我们是获取数字 1 还是字符串 '1' 的值时,得到的结果都一样。
      
          console.log(smbObj[1]);
          //'ShowMeBug'
          console.log(smbObj['1']);
          //'ShowMeBug'Map 的键可以为任意类型,数字 1 的键和字符串 '1' 的键并不一样。
          console.log(smbMap[1]);
          //'ShowMeBug'
          console.log(smbMap['1']);
          //undefined
    

    无论是对象还是映射,键都是唯一的。对象中不能有两个相同键的属性,映射中也不能有两个相同键的条目。

3. let const var 的区别

这个也已经背烂了

4.get 和 post区别

1. get用来获取数据,post用来提交数据
2. get参数有长度限制,而post无限制
3. get请求的数据会附加在url中,以 " ? "分割url和传输数据,多个参数用 "&"连接
   而post请求会把请求的数据放在http请求体中
   

5. event loop,宏任务和微任务

又是这类题目。。。

6. 跨域

Jsonp(JSON with Padding) 是 json 的一种‘使用模式’,可以跨域的获取到数据。 原理:

利用 script标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP 请求一定需要对方的服务器做支持才可以。

  - 准备带有 padding 的请求 url,得到一个字符串 dataStr
  - 构造 script
  - js 代码使用 document.createElement 创建一个 script 标签,
  - 在函数作用域中外界如何访问到?使用 window

缺陷: 只能用get进行请求,不能用post 浏览器默认加载资源的方式就是get请求

cors

Http请求头:
Origin: http://api.bob.com (发送的源)

反应:
Access-Control-Allow-Origin: * (允许所有跨域)
```
module.exports = async (ctx,next) => {
// 设置响应头
// 允许访问跨域服务的白名单 *允许所有
ctx.set('Access-Control-Allow-Origin','*');
ctx.set('Access-Control-Allow-Headers','Content-Type');
ctx.set('Access-Control-Allow-Methods','GET,POST,OPTIONS');
// OPTIONS 获取资源允许访问的方式
// 其实在正式跨域之前浏览器会根据需要发起一次预检也就是option请求用来让服务端返回允许的方法
await(next())

}
``` 

设置*的缺陷:

任何前端都能访问,会遭受网络攻击,比如大量请求

缺陷:

复杂请求的时候得先预检(option)再发请求

优点: 在后端设置

websocket

Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。

WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

Node中间件代理(两次跨域)

实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。

代理服务器,需要做以下几个步骤:

  1. 接受客户端请求

  2. 将请求 转发给服务器。

  3. 拿到服务器 响应 数据。

  4. 将响应转发给客户端。

  - 前端代理
```
  "proxy":{
"/api": {
  "target": "http://172.19.5.35:9536",
  "ws": true
  },

"/apc": {
  "target": "http://179.19.5.35:9536",
  "ws": true
  }
},
```
  • 缺点 增加了网络请求

iframe + postMessage

这里是使用3300端口父页面向内嵌子页面3301端口发送消息

//a.html
<!-- 使用iframe,src指向3301端口 -->
<iframe src="http://127.0.0.1:3301/b.html" id="frame" onload="load()"></iframe>
<script>
const data = {
name : '某车',
like:  '前端'
}
const load = function(){
//负责发布消息
let frame = document.getElementById('frame'); 
const targetWindow = frame.contentWindow;//得到目标窗口的引用
targetWindow.postMessage(data, 'http://127.0.0.1:3301'); //发送新消息
//也监听信息
window.onmessage = function(event) {
  console.log(event.data)
}
}
</script>

iframe 标签用于在 HTML 文档中嵌入另一个 HTML 文档,它可以显示来自不同网站的内容。

postMessage() 方法是 HTML5 中提供的一种跨文档通信的API,用于在两个窗口之间传递消息。它接收两个参数:第一个参数是要发送的消息,可以是字符串、数字、对象等;第二个参数指定接收消息的窗口的源和目标窗口的 URL。

7.数据类型

8. 复杂数据类型和简单数据类型的区别

9.闭包

10. 原型链的理解

11. 你的前端学习路线是什么样的?

12. 你为什么选择写博客?

这里我觉得我答的还OK,就是往自己为什么要写博客的初心,乐于分享同时巩固自己的成果。最后还可以把费曼学习法介绍一下。

总结: 这家公司给我的感觉一般般吧,记得当时面试官和我说话的语气不是那么有人情味,或者说就像是简单无聊的一问一答模式,全程严肃。

脉脉

一面

1. 力扣 最长不重复的子串

当时自己是真写不出,于是为了日后拿下类似这种中大厂的实现offer,三月份的时候开始认认真真刷算法去了。

2. 补齐代码

    class EventEmitter {
        constructor() {
        }
        on() {
        }
        once() {        
        }
        emit() {
        }
        off() {
        }
    }
    
    // 运行示例
    let event = new EventEmitter();
    
    event.on('say',function(str) {
        console.log(str);
    });
    
    event.once('say', function(str) {
        console.log('这是once:' + str)
    })
    
    event.emit('say','visa');
    event.emit('say','visa222');
    event.emit('say','visa333');

这其实就是经典的手写发布订阅了

可以参考一下我的这篇文章

🚀手撕大厂常见手写题——发布订阅者模式 - 掘金 (juejin.cn)

3. 什么是跨域,然后处理跨域?

又遇到了

4.讲一下eventloop

5.讲一下执行结果

console.log(1);

setTimeout(() => {
    console.log(2);
}, 0);

new Promise((resolve) => {
    console.log(3);
    resolve()
}).then(() => {
    console.log(4);
    Promise.resolve().then(() => console.log(5))
})

6. React中设置key的作用,能否用索引取代key呢?

可以参考这篇文章

cloud.tencent.com/developer/a…

总的来说就是:

要看情况,一般做数据展示的时候可以

index做key,将列表数据倒转,index传入的key值还是一样的,此时react比较key=0时,发现只需要更新子节点的值就可以

当我们传入id作为index的时候,点击reverse后,此时的key变成了3,2,1,根据react的diff算法,react还是能分辨出只需要移动子节点即可完成更新,因此input也随之变化。

7.fiber机制了解吗?

Fiber 可以理解为是一个执行单元,也可以理解为是一种数据结构

每个 Fiber 对应一个 React 元素,每个 Fiber 都有 3 个属性:child(第一个子节点)、sibling(兄弟节点)、return(父级节点)。

什么是一个执行单元?

Fiber 可以理解为一个执行单元,每次执行完一个执行单元,react 就会检查现在还剩多少时间,如果没有时间则将控制权让出去。

流程如下

首先 React 向浏览器在一帧中如果还有空闲时间,会去判断是否存在待执行任务,不存在就直接将控制权交给浏览器,如果存在就会执行对应的任务,执行完成后会判断是否还有时间,有时间且有待执行任务则会继续执行下一个任务,否则就会将控制权交给浏览器。

Fiber 可以被理解为划分一个个更小的执行单元,它是把一个大任务拆分为了很多个小块任务,一个小块任务的执行必须是一次完成的,不能出现暂停,但是一个小块任务执行完后可以移交控制权给浏览器去响应用户,从而不用像之前一样要等那个大任务一直执行完成再去响应用户。

8. React中hooks为什么不能用if判断

可能会导致 hooks 的执行顺序发生改变,因为 React Hooks 内部是通过 hooks 的调用顺序来区分是哪个 hook

useState 为例,在 react 内部,每个组件(Fiber)的 hooks 都是以链表的形式存在 memoizeState。 update 阶段,每次调用 useState,链表就会执行 next 向后移动一步。如果将 useState 写在条件判断中,假设条件判断不成立,没有执行里面的 useState 方法,会导致接下来所有的 useState 的取值出现偏移,从而导致异常发生。

9.React为什么渐渐不用生命周期了?

函数式组件相比于类组件有很多优点,比如更简洁、更易于测试、更容易优化等。此外,React还引入了新的API,比如useEffect和useContext,使得函数式组件更加灵活和强大,可以处理许多类组件需要使用生命周期函数才能完成的任务。

还可以结合函数式编程的优点来回答

二面

1.算法

给定一个有序(非降序)数组A,可能含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1。

     array =[1,2,3,5,6,7,7,10]
     target  = 7,return  5
     target = 8,  return -1

大概说一下两种方法

一种就是最简单的暴力搜索

另外一种就是二分查找

2.如果这个数组没有序,无序,那么怎么查找呢

这里面试官可能就是要求自己对排序算法的掌握程度,比如场景的冒泡,插入,选择,快速排序这些的了解

3. 用react写一个组件,用它获取后端的一个姓名

这里是真的不太会了

4. 介绍一下react useEffect

5.知道useState的副作用吗?

其实就是useState延迟更新的特性

6. 什么是副作用?

  • 常见的副作用
    1. 数据请求ajax发送
    2. 手动修改dom
    3. localstorage操作

7.怎么解释useState中你刚刚说的副作用?

8.讲一下你的项目,或者说一下你的亮点,优点?

小结:

这家公司的题目比之前的公司也就是涉及到了一些基础的算法和手写,也还不算太难的。

同程旅行

一面

我还是很记忆犹新的,一上来面试官就说,这次考察的内容涉及到C语言,数据结构,以及一些其他语言的特性。当时我就有一点点慌,感觉这次的题目要够呛了。

1. 面向对象的特点

  1. 封装性:将对象的属性和方法进行封装,使其内部状态对外部不可见,只能通过特定的接口访问。

  2. 继承性:通过继承,子类可以继承父类的属性和方法,同时可以添加自己的属性和方法。

  3. 多态性:同一种行为在不同的对象中有不同的表现形式,即同一个方法可以在不同的对象上产生不同的效果。

这里不仅要我讲出它的特性,还要求我解释一下每个特性的定义。

2.c语言中的数组与js中数组的区别

这里更多的是考察C语言中数组的特点

  1. 数组中的元素在内存中是连续存储的,可以通过下标来访问和修改数组中的元素。
  2. 数组的大小是固定的,一旦定义了数组的大小,就不能再改变大小。
  3. 数组可以作为函数参数传递,函数中可以直接访问和修改数组中的元素。
  4. 数组的下标从0开始,最大下标为数组大小减1。
  5. 数组可以用来存储各种类型的数据,包括整型、浮点型、字符型、结构体等。

3. 一个Person类,这个类当中我为什么要写name属性和walk等方法?

这里我介绍的是从语义化的角度去思考的。

4. js继承的方法

这也可以参考我的这篇文章

JS的六种继承方式 - 掘金 (juejin.cn)

5. 数组中有哪些方法

6.数组中的indexof判断数组存在会返回什么?不存在会返回什么?

7. 数组中map和foreach的区别

- 相同点:
 都是循环遍历数组中的每一项
- 不同点:
1. map()创建了新数组,会返回新数组;
2. forEach返回值为undefined     return 不能中断其遍历
    ```
    [1,2,3].map(d => d + 1); // [2, 3, 4];
    [1,2,3].forEach(d => d + 1); // undefined;
    ```

8. 数组中map,foreach和for循环它们谁最快,为什么?

这个我是真不知道了

9. 你刷算法时,你觉得递归的副作用是什么呢?

这里要说到调用栈过多而导致爆栈的问题

10.操作符new主要做了一件什么事情

```
function mynew(Func, ...args) {
// 1.创建一个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}
```

11.call,apply,bind的区别

apply

apply 接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次。

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}

fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;
fn(1,2) // this指向window

call

call方法的第一个参数也是this的指向,后面传入的是一个参数列表

跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

    //创建一个函数
    const fn = function (age, height) {
            console.log(this)
            console.log(`年龄:${age},身高:${height}cm`)
        }
    //直接调用,this指向window
    fn(20, 175)  // window  年龄:23,身高:167cm
    const data = {
            name: "张三"
        }
    //使用call修改this指向
    fn.call(data, 20, 175) //{name: '张三'}  年龄:20, 身高:175cm
    //修改成功,fn的this指向了data这个对象

bind

bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)

改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}

const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立即执行需要执行一次
bindFn(1,2) // this指向obj
fn(1,2) // this指向window

二面

1. 自我介绍

2.对同程有哪些了解

3. 你觉得你和其他那些研究生和985.211的学生的优势是什么?

这种问题是真的不好答的呀

4. 你对前端的理解以及了解

这个方面更多的是前端这个行业存在的意义之类的理解。

我答到了为了用户的体验感以及一个产品要做到留住用户方面,这个答案也比较符合面试官的要求。

5. 微前端和低代码了解过吗?

6. 了解哪些性能优化方案

1. 防抖节流
2. 懒加载
3. 虚拟列表
4. 减少重排重绘
5. cnd的分发
6. ssr首屏优化

大概把这上面的都介绍了一遍

7.小程序与h5相比,它为什么更流畅? 这里就进入到了和面试官探讨的环节,因为我自己对小程序了解的也不多,所以这一块作答给我的感觉更像是聊天

8. 从输入url到页面展示

9. null和undefined的区别

null 表示“空值”,用于表示变量或对象中没有任何值。例如,如果一个变量未被赋值,它的默认值就是 null。null 是一个表示空对象指针的特殊值,可以使用 typeof 运算符检测它的类型,结果为 object。

undefined 表示“未定义”,用于表示变量或对象中缺少值或属性。例如,如果访问一个不存在的对象属性,返回的值就是 undefined。undefined 是一个表示未初始化变量或缺少参数的值,也可以使用 typeof 运算符检测它的类型,结果为 undefined。

10.监控页面的白屏率有什么思路吗?

不好答,好像是涉及到埋点的操作

11. 垃圾回收机制了解吗

上面介绍过

12. 一段js代码的执行过程了解吗

13. AST抽象语法树了解吗?

最后这两道题也仅仅就是涉及到了一点点皮毛,也没答出来。

反问环节

贵公司对实习生的培养方案是什么样的?

据说是挺不错的,一上来就说是按照转正的规则去培养,希望这次的实习生可以有以后能留下来的想法。

以及会有一个全公司的培训,什么方面的都有,然后就是有个一对一导师等等。反正我是真的心动了。

我这次的面试表现怎么样?

这里面试官就没有明确回答我了,反而让我觉得自己这次回答的怎么样,然后我就感觉有点悬了。

hr面

因为一面到二面我直接是一次性面完的,第一天晚上直接连续面了我两个小时,终于在第二天上午hr打电话给我了。

1. 为什么选择来苏州,而不去其他互联网发达的地方?

2. 之前实习的地方怎么样,为什么离职了?

3. 实习过程中最大的收获是什么?

4. 你的希望薪资是多少

5. 如果你是我,那么你凭什么要发这份offer给我呢?

本来我以为是不是意向了,没想到还需要和面试官再沟通沟通,又让我有点慌了。。

结尾

同程面试完后的第三天,hr又打电话给我了,说我面试通过了!!

于是在这个礼拜一,终于收到了正式的offer了

4FB03AADA965F5F0E6CED5402D9A3748.jpg

没错,这次的offer还是暑期实习哦!再也不会因为学校恶心人而去不了😭😭😭

非常感谢同程给我的机会。

🌹🌹🌹

感想

最近的面试,其实要拿到一家中小厂的实习,可以说问来问去,题目大概是哪些,真的只需要我们准备一下就能拿下的。如果想冲中大厂,还需要拓宽八股文的深度和广度,以及在一些手写和算法下认认真真做功课了。

第二点,我也对面试有了一种新的感悟,就是我们的专业技能,比如八股文,项目能力这些属于我们的硬实力,这毫无疑问是非常重要的。但是,可能我们的软实力也不可小视,它能极大的增大我们的容错率!

我认为的软实力,也有两点

  • 1.被问到不会的问题时的一种态度,这种态度不是说,完了,这个问题不会了,这次面试没那么好了,要挂了,这种焦虑消极的心理。而是要学会,既然现在的情况已经不好了,那么我们要如何才能化险为夷呢? 这里我觉得最重要的是你能让面试官看出你面对知识盲区的一种心态,这可以表现为积极和面试官去探讨该问题的结果,要让面试官了解到你的可塑性。因为他也知道,他现在面试的人,可能是他未来的同事,谁也会更喜欢乐观,不畏困难,积极学习的人作为自己的同事吧~

  • 2.另外一点塑造轻松,愉快的聊天氛围。在面试过程中尽量不要仅仅的就是呆板的一问一答,毫无人情味的沟通。我们可以在这种过程中加入一些添加剂。我的做法是,给面试官塑造一种积极乐观的形象,比如面带微笑,自信作答的声音等。尤其在反问过程中最为体现,这时候我们可以多聊聊题外话,比如我面云鲸智能的时候,聊了一下深圳这边的变化,能不能在高楼办公这样的。这种氛围在无意间对我们的面试也会有一定的好处的。

我之所以这么理解是因为我自己,在面脉脉和同程的时候,即使自己回答还有不少的漏洞,面试官也为我开了绿灯,而之前一些小公司的面试基本上答出来了,却还是被挂了,我觉得这种软实力还是不可忽视的。

最后的最后,还是不要忘记这句话。

你在挑选公司的时候,面试官自己也在挑选自己未来的同事,如果你是他的话,你会更想要一位什么样的同事和自己并肩作战呢?

祝大家也能早日拿到自己的暑期实习的offer~

本文正在参加「金石计划」