前端面试(12月底):第一次被裁员到疫情爆发 最后涨薪50%

260 阅读24分钟

12月初人生第一次被裁员(拿了三个月赔偿),本来11月就提了辞职被领导拦下,叫我找到再辞,后面得知有裁员机会,激动了好几天,运作下得偿所愿。

12月离职不是一个很好的时间段、前有金九银十招聘高需求过去、又迎来全国小阳人(很多公司放缓招聘节奏)ps(2022 1月份全年招聘工资最高 2023就不知道了)

很多忘了 只能挑我还记得的重点讲出来... 重复的不说

找工作一定要给自己预期更高的工资(毕竟要考虑未来几年不能加薪 市场通胀的问题)

11.6日面试(在职 请了半天假)

招聘薪资(12-18k)自研

面试结果:成功(15k)试用期同薪

  • 面试过程:
  • 自我介绍
  • 挑项目问

1.Vue的双向绑定(可能会有更好的解答 因为这个太常见了)

   使用发布订阅模式将数据劫持和模板编译结合,实现双向绑定
 
   1.observer 数据监听器,能对数据对象的所有属性进行监听,通过Object.defineProperty劫持.   (vue3   proxy)将他们转化为getter/setter,如果发生数据变化会通知订阅者
   2.compile 指令解析器 对每个元素节点进行解析 根据指令模版替换数据 以及绑定相对应的更新函数
   3.watcher 观察者 作为observe和compile的桥梁 能够订阅并通过订阅者收到每个属性变动的通知,执行指令绑定的回调函数 从而更新试图
   4.dep 订阅者 管理数据的订阅者 当数据发生变化之后 通知观察者来更新视图

2.v-model原理

1.本质是语法糖 等价于v-bind绑定属性的值 及v-on绑定input事件 监听input事件的输入 调用defineproperty方法 来修改属性的值

3.promise原理(高频题)

1.js异步编程的一种解决方案  表示一个异步操作的最终完成(或失败)
2.它有三种状态 pending fulfilld rejected 分别代表进行中 成功 失败
3.改变它的状态 
   resolve 如果当前是pending 就会变成resolved
   reject 如果当前是pending就会变成rejected
   状态一旦改变就不能再修改
4.通常使用new promise 来创建promise对象 也可以使用promise.resolve 和promise.reject
5.promise 可以解决回调地狱 在then里面返回异步操作结果 下一个then 接受数据
6.promise的实例方法 then catch finally  finally他不管promise 状态是成功还是失败 都会执行的操作
7.promise 三个常用静态方法
  all :接受数组参数 每个参数都是promise对象 如果数组中所有promise的状态都变成resolved all的状态也会变成resolved 只要有一个promise是rejected  all的状态就会变成rejected
  race:接受数组参数 每个参数都是promise对象 如果数组中所有promise 最先执行完成的状态是resolved race自身状态就是resolved 反正最先完成的rejectd 那么race自身状态就是rejected
  any :接受数组参数 每个参数都是promise对象 如果数组中任意promise 状态是resolved any自身状态就是resolved 所有promise 状态是rejected 那么any自身状态就是rejected

4.vue的理解

  组件化(每一个.vue可以看做一个组件 组件的职责单一 可以复用 降低系统耦合度)
  响应式 (通过  MVVM  思想实现数据的 双向绑定  ,数据驱动视图,让开发者不用再操作dom对象  )
  指令系统 (有v-前缀的特殊属性,当表达式的值改变时,作用在dom上)

5.js原型(高频)

js分为函数对象和普通对象  ,每个对象都有__proto__属性,但是只有函数对象才有prototype属性
比如说 构造函数通过new 实化一个实例对象 实例对象的__proto__ 指向原型对象 同时构造函数prototype也指向原型对象  原型对象的constructor属性指向构造函数  记录由那个构造函数创建
当读取实例的属性时,如果自身找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。找到 object.prototype.protonull

6.闭包(高频)

  闭包是指有权访问另一个函数作用域中的变量的函数 或者说一个函数的返回值是另一个函数
  作用    
      1.可以访问其他函数内部的变量
      2.函数调用完成 作用域的变量也不会被消失  可以封装对象的私有属性,方法
      3.防止变量名污染,不受外部干扰
 为啥便利不销毁的原因
      闭包中变量存在堆内存  而不是栈内存中 如果是栈内存 那么就会被系统自动回收 这也是闭包中的变量不会被销毁的原因
 怎么检查泄露 
      performance 面板 和 memory 面板可以找到泄露的现象和位置
 闭包影响
      过度使用闭包可能造成内存泄露 因为闭包携带其他函数作用域 比一般函数占用的内存多 
 闭包情况     
      意外的全局变量: 无法被回收
      定时器: 未被正确关闭,导致所引用的外部变量无法被释放
      事件监听: 没有正确销毁 (低版本浏览器可能出现)
      闭包: 会导致父级中的变量无法被释放
      dom 引用: dom 元素被删除时,内存中的引用未被正确清空      
 闭包案例
      案例 闭包常用在自执行函数 防抖 节流 函数柯里化
 垃圾回收机制
     垃圾回收机制 是指  js  的执行环境会去管理代码执行过程中使用的内存 其原理 有一个垃圾收集器会定期去清除那些不被使用的变量 释放他们的内存 垃圾回收开销很大并且会停止其他操作 所以只能周期性清理
 常见方法   
      标记清楚 比如函数声明变量 标记变量进入环境  函数执行完毕 离开环境
      引入计数 每引入一次 计数一次   

11.21日面试(在职 请了1天假)

招聘薪资(12-25k)自研

面试结果:失败(有点打击到我了 面试官考验基础能力)

  • 面试过程:
  • 自我介绍
  • 挑项目问

让你写一个vue框架 该如何写(应该还有更好的答案 面试官想知道用了哪些设计模式)

第一步 首先要分析vue是一个mvvm 的思想 m是数据模型 v视图模型 
vm 监听数据的变化 然后通知视图更新
第二步 我们要创建一个vue的类 并且是单例模型 全局有且只有一个子类
第三步 我们要对data中的数据进行代理 监听数据属性的变化 会用到object.defineProperty 将他们转化为getter setter方法
第四步 我们实现一个compile类 实现模版编译  首先获取所有子节点 遍历节点  如果是元素节点 就解析指令。如果是文本节点 就是替换花括号内容  如果还在存在子节点 继续递归判断
第五步 我们要实现一个watcher类 观察者 当他观察的数据发生变化时 需要去更新视图
第六步 还需要一个订阅者dep 订阅数据 当数据发生 通知观察者更新视图。

  你知道设计模型

1.单例模式
  核心:一个类有且只有一个实例 提供一个访问它的全局访问点  
  举例 比如说弹窗 无论点击多少次 只会创建一次
 2.工厂模式
  核心:父类中提供一个创建对象的方法 允许子类实例化不同类型的对象
3.策略模式
  核心 定义一系列不同算法 放到对应的类中 
  举例 常见表单验证
4.发布订阅模式
  消息通讯。有订阅者 和发布者  订阅者只会关注自己订阅的消息  每个订阅者可以订阅多个发布者 
  举例 :常见组件跨层级通讯 
5.装饰器 模式
  核心 在不改变对象的基础的 给他动态添加一些属性或者方法
  举例 常见 防抖 节流 高级组件    
6.观察者模式
  核心 定义一对多的依赖关系 让多个观察者监听同一个目标对象 当目标对象发生改变 会通知所有观察者
7.代理模式 
  核心 为一个对象提供一个占位符 以方便对他控制
  举例 比如说图片懒加载时 先用loading 代替 加载完成之后用真实图片路径

你知道的数据结构

  普通数组结构:堆、栈、数组、队列、链表、树  
  高级数组结构:图

11.21日下午面试(在职 请了1天假)

招聘薪资(15-30k)自研

面试结果:失败(被妹子面了一个半小时 面试官看着网上考题在问 领导在开会没拿到二面)

  • 面试过程:
  • 自我介绍
  • 挑项目问

盒子模型

     分为两种模式标准盒(w3c)模型 和怪异盒模型 div分为四个部分 从里到外 content padding border margin
     标准盒模型: 实际宽度=设置的宽度+pading+border的宽度 
     怪异盒模型 实际宽度=设置的宽度 
     如果设置了pading和border 要减去pading和border的宽度 才是它的实际宽度 我们可以通过box-sizing 设置content-box为标准盒模型 border-box为怪异盒模型。

  响应式布局方案

   媒体查询 百分比 rem vh vw scale

  三栏布局

    float流体布局

    左侧float left 右侧float right 中间 margin-left margin-right

    bfc布局

    左侧 float left 右侧 float right 中间设置overflow:hidden 触发bfc

    flex布局

    父级diplay:flex 左右侧宽度固定 中间 flex:1

    position布局

    父级相对定位 左右绝对定位 中间margin 两侧的宽度

    Table 布局

    父级设置display table 子级设置display :tab-cell

  居中对齐

    方法一:父元素 display:flex,align-items:center;

    方法二:元素绝对定位,top:50%,margin-top:-(高度/2)

    方法三:高度不确定用 transform:translateY(-50%)

    方法四:父元素 table 布局,子元素设置 vertical-align:center;

    方法五 绝对定位 top left bottom right 为零

  url渲染过程

   1.地址栏输入url回车

    2. dns解析域名 域名转化为ip地址 这层是应用层

    3.然后进入到传输层 协议有tcp和udp 默认是tcp 传输之前进行三次握手和四次挥手 客户端向服务器发送一个SYN 请求同步 服务器收到之后会返回一个ACK 确认请求同步 然后客户端收到后再回复ACK 这样做是为了建立可靠的连接

    4.进入到网络层 ip层 转发路由 帮助数据包寻找下一跳

    5进入链路层 数据进入后 会加上mac地址 等头部数据封装成数据帧 传到物理层

    6.物理层不对数据处理 传送信号 服务收到对数据进行处理 返回响应报文给客户端

    7.浏览器解析渲染页面

    浏览器解析html 生成dom树

    解析css 生成css规则树

    合并html和css 生成render树

   布局render树 尺寸 位置的计算

  http和https区别

    http是明文传输,https主要通过加密套件ssl tsl对数据加密,

    http的端口是80 https端口是443

    https需要CA认证,一般免费证书很少 需要缴费

    https的ssl和http协议构建的可加密传输,身份认证的网络协议 比http更安全

  http1和http2区别

   1.请求更快

   2.多路复用

   同一域名下,只需要建立一个连接。 => 减少握手等待时间,以及多个 tcp 竞争带宽。

   单个连接可以承受任意数量的双向数据流。 => 并行多个请求响应。

  如何实现一个new

function newFunc(Func,...args) {
    // 1.创建一个新对象
    let newObj = {}
    // 2.将新对象和构造函数通过原型链连接
    newObj.__proto__ = Func.prototype
    // 3.将构造函数的this绑定到新对象上
    const result = Func.apply(newObj,args)
    // 4.根据返回值类型判断,如果是值类型返回newObj,如果是引用类型返回正常引用类型
    return result instanceof Object ? result : newObj   
}

  this指向

    1.在全局函数中 永远指向window

    2.在严格模式中 this永远不指向window 在es5函数中使用use strick 指向

    3.当函数为某个对象的属性时 在函数内指向这个对象

   4.在构造函数中 this指向新创建的对象

   5.在箭头函数中 this指向父级作用域

  箭头函数

    没有this

    没有arguments

    不能用new 关键字调用

    优点 书写简单

  Call bind apply区别

    都是改变this指向的方法, bind返回一个函数 可以延时调用。
    apply和call是直接调用,他们区别在于传参方式不一样,apply第一个参数是this的指向,第二个要传入的参数数组,call 第一个是this的指向,后面是依次要传入的参数

  。。。不想写了全是面经

11.24日面试(在职 偷摸出去两小时)

招聘薪资(15-30k)自研

面试结果:二面失败(二面之后 hr中间联系我 我没理 后面gg 估计找性价比 )

  • 面试过程:
  • 自我介绍
  • 挑项目问

vue3和vue2的区别

    1.双向数据绑定原理发生了变化

     vue2 是数据劫持加发布订阅模式 使用object.defineproperty来劫持data中属性的getter 和 setter 在数据变化时触发监听

     vue3是通过es6中的proxyApi对数据劫持

     能劫持整个对象 而defineproperty 只能只能监听某个属性 省去遍历 提高性能

     proxy能够直接监听数组下标的修改

     2.vue3支持多个根节点

     3.Composition API(组合api) 相对于vue2 data props methds位置散乱 vue3中按照属性分组 代码更整洁

     4.生命周期变了 (比如说 beforeCreated created 变成setup)

     5.vue3 数据在setup中初始化 setup 接受两个参数 prop context(attrs,emit ,slots)

  深拷贝、浅拷贝区别

     深拷贝是从对象内存地址拷贝一份出来 在堆内存中开辟一个新的空间存放 和原先的互不干扰

    浅拷贝 如果数据是基本类型就是值拷贝 如果是引入类型就是内存地址引入

    浅拷贝

    object.assign [...] slice concat

    深拷贝

    json.parse json.stringify

  ES6 Api

    新增let const常量

    symbol 唯一的值

    模版字符串

    解构表达式

    Set 类似数组 里面的值是唯一的

    Map 保存键值对

    数组的新方法

    forEach map filter Array.from some every includes

    对象的新方法

    object.assgin object.keys object.values

    Class

    promise proxy

    箭头函数

    扩展运算符

  性能优化(高频)

   前端性能优化主要是减少下载资源的大小 或者延迟加载 按需加载

    1.合并减少http请求数量

    2.将js脚本放底部 html加载是从上至下加载

    3.可以设置script标签设置defer 属性 等html解析完成之后在加载执行

    4.还可以通过createElement 动态引入script标签

    5.压缩图片体积、合并精灵图、使体积更小的webp格式 。压缩图片是减少项目体积最重要的手段之一 效果很明显 长网页中可以懒加载图片 减少首屏资源加载。

    6.使用cdn更快速下载静态资源

    7.使用浏览器强制缓存 或者协商缓存 读取本地资源

    8.nginx 配置gzip

    9.Webpack 工具

    使用一些插件 减少代码体积 或者分析代码依赖

    比如 treeShaking 去掉无用代码

    还有webpack-bundle-analayzer(安了来则)可以分析代码里面的依赖

    比如说使用day.js 去代替moment.js

    生产环境去掉sourceMap

    像vue 的优化手段

    1.import 动态引入组件

    2.object.feeze 去冻结不需要更新的长列表

    3.computed 的计算熟悉 他只有依赖发生变化才会去更新 否则读取缓存

    4.频繁隐藏dom 用v-show 偶尔用v-if

    5.通过v-for 渲染列表 加keykey最好不用index diff 算法更好识别节点 实现复用节点

    react 的优化

    react.memo 可以缓存组件 当props 不变的情况

    react.useMemo 缓存函数的计算结果

    pureComponents 纯组件 当props也不会重新渲染

    shouldComponentUpdate 控制是否更新组件

    react.lazy 懒加载组件

    小程序的优化

    小程序主要是体积有限制 最常见就是分包 减少主包体积

    或者小程序预加载其他页面

    h5方面就是ssr渲染 在服务端渲染html 返回给浏览器 可以选择next.js这个框架写ssr

    单页面和多页面 单页面首屏加载快 次屏慢 多页面正好相反 首屏慢 次屏快

12.13日面试(离职 )

招聘薪资(15-25k)自研

面试结果:成功(16k)

  • 面试过程:
  • 自我介绍
  • 挑项目问

小程序分包(自行体会)

  性能优化

  作用域

   首先变量需要执行环境 也就是作用域

    分两种函数作用域和全局 es6新增了块级作用域 let const

    1.最外层函数和变量拥有全局作用域

    2.未定义直接赋值的变量拥有全局作用域

    3.所有window对象的属性拥有全局作用域

    变量提升会将变量声明 放到所在作用域最顶部 并赋值undefined

    函数声明优先变量声明。

    函数作用域函数定义的时候就创建了 执行上下文是在执行前创建的 最常见就是this的指向

    1.var es5提出来的 const let是es6提出来的

    2.const let 是常量 存在块级作用域 var 没有块级作用域

    3.var 存在变量提升 在声明前使用 值为undefinedconst let 没有变量提升 不能在声明前使用

    4.const 声明必须赋值 声明后不能修改 let 可以不声明 声明之后可以修改值

    5.let const 不能重复声明 var可以

  跨域解决方案

   当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。

   1.配置代理

   比如在vue.config 配置proxy 服务器代理 /api转发路径

    2.创建jsonp script标签不受跨域限制

    3.配置cros(跨域资源共享) 设置access-control-allow-origin 允许代码

  兼容问题(很喜欢问 啥样才叫兼容问题啊)

   小程序中

    1.ios 时间兼容问题 用/代替

    2.ios 刘海屏 可以通过getSystemInfo 去获取手机信息 适配

    3.textarea组件的maxlength长度限制 在android 不生效

  Websocket 传数据 参数数据很大扎解决

   兄弟们帮我想想

12.15日面试(离职 )

招聘薪资(15-20k)外包

面试结果:未知(一面过了 二面我拒了)外包面的比自研还挺打击 不说他难 但是确实大厂的员工有时候问问题喜欢刨根问底

  • 面试过程:
  • 自我介绍
  • 挑项目问

Vue和react如何实现双向绑定

   react 首先我们在input中添加一个onChange事件,然后把这个输入框的value绑定到state中 这个onChange事件会在这个input的值改变后触发 通过setState修改value

   vue 自行体会

  vue3 proxy优缺点

   1.Object.defineProperty需要遍历所有的属性,如果vue对象的data/computed/props中的数据规模庞大、会占据大量内存;

   2、无法监听es6的SetWeakSetMapWeakMap的变化;

   3、无法监听Class类型的数据;

   4、属性的新加或者删除也无法监听;

   5、数组元素的增加和删除也无法监听。

   解决方案

    运用this.$forceUpdate()强制刷新。

    使用vm.$set(vm.items, indexOfItem, newValue)

    将原数据 obj 进行深拷贝一下,然后再对拷贝后的数据 obj1 进行操作,然后再把操作后的数据obj1 赋值给原数据 obj

    第一种情况,可以使用数组的splice方法,arr.splice(index, 1, item)

  为什么用proxy

   使用proxy能解决以上问题 能达到速度加倍、内存减半的效果。

   1Proxy 可以直接监听对象而非属性;

   2Proxy 可以直接监听数组的变化;

   3Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是Object.defineProperty 不具备的;

   4Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;

   5Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

  

  proxy缺陷 我不知道(面试官一直笑 他觉得在背面经 让我无地自容 差点一度打击我了)


  它唯一的缺点就是,对IE不友好,所以vue3在检测到如果是使用IE的情况下(没错,IE11都不支持Proxy),会自动降级为Object.defineProperty的数据监听系统。所以如果是IE用户,那么就享受不到速度加倍,内存减半的体验了。

redux和mobx区别

mobx跟vue的思想差不多 它可以多个store,然后去监听数据属性的变化,可以直接通过数据更变触发Ui渲染

Redux 有且只有一个store,多个reducers会合并成root reducers 任何数据的更变 都是通过这一个store来触发整个UI树的渲染 如果不做性能优化的话 当页面dom数量多的时候 性能消耗是很大的 那mobx 监听数据的属性变化来实现的,而且是多store的 可以做到更精确更新dom 而不是整个dom树

flex等于1自动铺满

flex:1实际代表的是三个属性的简写

flex-grow是用来增大盒子的,比如,当父盒子的宽度大于子盒子的宽度,父盒子的剩余空间可以利用flex-grow来 设置子盒子增大的占比

flex-shrink用来设置子盒子超过父盒子的宽度后,超出部分进行缩小的取值比例

flex-basis是用来设置盒子的基准宽度,并且basis和width同时存在basis会把width干掉

react diff算法(高频)

这个内容太多了

react 生命周期(高频)不知道为啥喜欢问这种问题

    1.Constructor 初始化state和自定义方法绑定this
    2.getDerivedStateFromProps 组件初始化时或者更是 用props映射到state 替换了react16 componentswillMount和componentswillreceiveProps
    3.componentWillMount 初始化时的状态
    4.componentWillReceiveProps 监听父组件是否render 异步回调中改变state
    5.componentWillUpdate 组件更新前的状态 比如说dom的位置
    6.render 将jsx 转化react element
    7.getSnapshotBeforeUpdate 在dom更新前获取dom的快照 return 给componentDidupdate
    8.componentDidUpdate 获取更新后的dom
    9componentDidMount 用来出dom操作 dom监听 或者获取异步数据
    10.componentsShouldUpdate 是否更新组件     
    11.componentswillUnMount 卸载组件

setState同步还是异步

   新取决他的执行环境 本身是同步执行 异步只是合成多个state一起批量更新
   在合成事件和生命周期里是异步的
   在js原生事件和settimeout会调中是同步的

vue的data为啥是对象

    原因是因为如果data是一个对象的话,两个组件中设置的data都会引用同一个内存地址,而用函数的话,则会在每次引用的时候返回一个新的地址。

vue的路由模式 (面试官又笑了 可能是面多了 我可以理解)

     1.hash在地址栏有#号 history没有 相对不美观
     2.hash 回车刷新可以跳到地址栏相应页面 history必须写完整 否则会404
     3.history 应用了浏览器的历史记录栈 包括forward back go 等 html5 新增pushState和replaceState
     来对历史记录栈进行修改,需要后端进行配合。
     1.hash模式是一种前端路由的路径用#拼接真实url后面 ,当#后面的路径发生比变化时,浏览器并不会重新发起请求,而是触发hashChange事件
     
     hash的变化 会触发网页的跳转 即网页前进和后退 hash的改变是保存在window.history 简单来说hash的跳转只发生在客户端 不需要服务器 所以说他不是一次http请求 不会刷新页面 。这样不利于seo优化
     history 利用h5的history Api比如说forward back go 以及pushState和replaceState来实现新增路由栈和替换路由栈 当你刷新页面的时候 会重新发起请求 nginx没有匹配到当前路径 可能404



   使用场景
     To b hash
     To c history

react为啥有hooks

函数式组件:

和Hooks组件相比,它组件本身是没有状态的,并且没有任何的副作用; 完全受控于父组件,后期如果业务调 整,那函数式组件需要改成class组件,非常麻烦并且具有破坏性。

Hooks组件:

本身是有状态的,所以后期业务调整,也是可以在此基础上去修改。弥补函数组件无状态 无生命周期的问题 解决函数组件逻辑状态复用的问题

useMemo 和 useCallback区别(高频)

1.useMemo 计算结果是 return 回来的值, 主要用于 缓存计算结果的值 ,应用场景如: 需要 计算的状态

2.useCallback 计算结果是 函数, 主要用于 缓存函数,应用场景如: 需要缓存的函数,因为函数式组件每次任何一个 state 的变化 整个组件 都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,提高性能,和减少资源浪费。

seo优化

增加seo 权重 搜索引擎通过爬虫去抓取标签上的关键字

1.突出重要内容 比如title description keyword

2.使用语义化标签 符合w3c标准 比如title nav aside main article footer

3.比如img 添加alt 和 title属性

4.链接a标签添加title

5.或者使用h1标签 自带权重

Ajax 和 axios区别

axios和ajax的区别:1、axios是一个基于PromiseHTTP库,而ajax是对原生XHR的封装;2、ajax技术实现了局部数据的刷新,(追问什么是局部刷新我表达不清 在浏览器的内部,发起请求,获取数据,改变页面的部分内容。其余的页面无需加载和渲染,网络中的数据传输量少,给用户感觉好。 )而axios实现了对ajax的封装。

什么是ajax

****Ajax是对原生XHR的封装,为了达到我们跨越的目的,增添了对JSONP的支持。

异步的javascript和xml,ajax不是一门新技术,而是多种技术的组合,用于快速的创建动态页面,能够实现无刷新更新数据从而提高用户体验。

12.16日面试(离职 )

招聘薪资(18-25k)自研

面试结果:成功(五面) (试用期同薪)

  • 面试过程:
  • 自我介绍
  • 挑项目问

(团队刚成立不久 喜欢问我项目开发流程的问题 现在我是公司第一个前端)

拿到这个offer 我内心万分纠结去不去 其实我才离职一周 一周也拒了两个offer 当然我只是一个普通搬运工

我害怕后面没有那么高的工资 害怕疫情影响招聘(那真的只能等3月份 过年回家要被笑失业了)

人就是这样 拿到想要的 就想要更多