面试记录一
面试记录一
ps:经历的大半个月的找工作, 终于约到了我的第一个面试了,从最先开始的拿着我那份什么东西写上去的菜鸟简历,投,没有任何响应 😅😅😅, 到后面经过同学,朋友的指导,只把自己想从事的工作岗位相关的东西写上总算是有 hr 愿意搭理我,到如愿约到我第一面试,中间虽有艰辛,但结果还是好的 😃😃😃,首选还是感谢 hr 和公司给了我一个面试机会,虽然没抱太大机会了,但是能走出第一步我已经很满足了,下面就对我这次面试作一个简单的记录.
1.笔试题
首先是笔试部分,都是些很基础的知识,但是由于我记忆不够牢固,还容易记混,很多东西只是有个印象,离开电脑,没有代码提示就大脑短路了 😔😔😔😔
1.1 javaScript 中数组有那些 API,表明那些数组是否改变原数组?(至少 10 个)
这个我感觉我写的不错,总的大部分都有写出来.数组的方法可以分为操作方法, 排序方法, 转换方法, 迭代方法
1.1.1 操作方法
增
下面前三种会影响原数组,最后一种不会, ps:(我把splice()
也写成不会改变原数组了, 跟slice()
记成一起去了 😭)
- push()
- unshift()
- splice()
- concat()
push()
方法接收任意数量的参数,并将他添加到数组末尾,返回数组长度
let num = []
let count = num.push(1, 2, 3)
console.log(count) // 3
unshift()
在数组开头添加任意多个值, 然后返回新的数组长度
let num = []
let count = num.unshift(1, 2, 3, 4)
console.log(count) // 4
splice()
传入三个参数,分别是开始位置, 0(要删除的元素数量),插入的元素,返回空数组
let num = [1, 2, 3, 4, 5]
let removed = num.splice(1, 0, 6, 7)
console.log(num) // [1, 6, 7, 2, 3, 4, 5]
console.log(removed) // []
concat()
首先会被创建一个当前数组的副本,然后再把它的参数添加到副本尾部,最后返回这个构建数组
let num1 = [1, 2, 3]
let num2 = num1.concat(4, [5, 6])
console.log(num1) // [1, 2, 3]
console.log(num2) // [1, 2, 3, 4, 5, 6]
删
前三种会影响原数组,最后一项不影响原数组
- pop()
- shift()
- splice()
- slice()
pop()
方法用于删除数组的最后一项,同时减少数组的 length 值,返回被删除的项
let num = [1, 2]
let item = num.pop() // 取得最后一项
console.log(num) // 1
console.log(item) // 2
shift()
方法用于删除数组的第一项,同时减少数组的 length,返回被删除项
let num = [1, 2]
let item = num.pop() // 取得最后一项
console.log(num) // 1
console.log(item) // 2
splice()
方法传入两个参数,分别是开始位置,删除元素的数量,返回包含元素的数组
let num = [1, 2]
let removed = colors.splice(0, 1) // 下标零开始,删除一个
console.log(num) // [2]
console.log(removed)[1]
slice()
用于创建一个包含原有数组中一个或多个元素的新数组.不会影响原数组
let num = [1, 2, 3, 4, 5]
let num1 = num.slice(1, 4)
console.log(num1) // [2, 3, 4,5]
查
都不改变原数组,查找元素,返回元素坐标或元素值 (ps:就写了第一个,其他的忘了)
- indexOf()
- includes()
- find()
indexOf()
返回要查找的元素在数组中的位置,如果没找到返回-1
let numbers = [1, 2, 3, 4, 5]
number.indexOf(4) // 3
includes()
返回要查找的元素在数组中的位置,找到返回 true, 否则返回 false
let numbers = [1, 2, 3, 4, 5]
numbers.includes(4)
find()
返回第一个匹配的元素
const people = [
{
name: 'Matt',
age: 27,
},
{
name: 'Nicholas',
age: 29,
},
]
people.find((element, index, array) => element.age < 28)
1.1.2 排序方法
主要有两个 ps:没写这方面的
- reverse()
- sort()
reverse()
将元素反转
let values = [1, 2, 3, 4, 5]
values.reverse()
console.log(values) // 5, 4, 3, 2, 1
sort()
接收一个比较函数,判断那个值应该排在前面
const arr = [1, 2, 3, 4, 5, 6]
console.log(arr.sort((a, b) => b - a)) // 6, 5, 4, 3, 2, 1
console.log(arr.sort((a, b) => a - b)) // 1, 2, 3, 4, 5, 6
1.1.3 转换方法
常见的转换方法有: (ps:这方面的我也没写)
- join()
join()
方法接收一个参数,即字符串分隔符,返回包含所有项的字符串
let colors = ['red', 'green', 'blue']
alert(colors.join(',')) // red,green,blue
alert(colors.join('||')) // red||green||blue
1.1.4 迭代方法
常用迭代数组的方法(都不改变原数组) (ps:只写了 forEach, filter, map,reduce)
some()
every()
forEach()
filter()
map()
reduce()
some()
对数组每一项运行传入测试的函数,如果至少有一个元素返回 true,则这个方法返回 ture(查找一样)
let numbers = [1, 2, 3, 4, 5, 6, 7]
let someReslut = numbers.some((item, index, array) => {
return item > 2
})
console.log(someReslut) // true
every()
对数组每一项都运行传入的测试函数,如果所有元素都返回 true ,则这个方法返回 true
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let everyResult = numbers.every((item, index, array) => item > 2)
console.log(everyResult) // false
forEach()
对数组每一项都运行传入的函数,没有返回值
filter()
对数组每一项都运行传入的函数,函数返回 true
的项会组成数组之后返回
map()
对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组
reduce()
每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入
const arr = [1, 2, 3, 4, 5, 6]
const total = arr.reduce((item, value) => {
return item + value
}, 0)
console.log(total) // 21
1.2 如何判断数组还是对象?(不少于两种)
ps:全部记得模模糊糊,记得一个通过Object.prototype.toString.call([])
都还没有没记全,其他的都没写出来 😭😭😭
// 以下体提供三种方法
const a = []
const b = {}
// Array.isArray() 方法
console.log(Array.isArray(a)) //true
console.log(Array.isArray(b)) // false
// 通过构造函数判断
console.log(a.constructor === Array) // true
console.log(b.constructor === Array) // false
// 通过`Object.prototype.toString.call([])`
console.log(
Object.prototype.toString
.call(a)
.toString()
.replace(/[\[\]]/g, '')
.split(' ')[1] === 'Array'
) // true
console.log(
Object.prototype.toString
.call(b)
.toString()
.replace(/[\[\]]/g, '')
.split(' ')[1] === 'Array'
) // false
1.3 把下面字符串进行分割成数组
const txt = '您好!欢迎来到,你是面试的吗?是的!'
ps:我首先想到的是正则txt.split(/!,。/)
回去试了一下, 没加[]
也没加g全局匹配符
, 真大脑短路,呜呜呜~~
// 正确答案
console.log(txt.split(/[!,\?。]/g)) // [ '您好', '欢迎来到', '你是面试的吗', '是的', '' ]
1.4 看以下代码的输出结果
setTimeout(() => {
console.log(1)
}, 0)
let promise = new Promise((resolve, reject) => {
console.log(2)
resolve(3)
}).then((res) => {
console.log(res)
})
console.log(4)
ps: 我写的答案是:4,2,3,1 中间有猜的成分,哈哈,分不清 settimeout 和 promise 那个先执行, 然后我回去测试了以下答案是:2,4,3,1, 又是错的 😭😭😭😭😭, 百思不得其解,为啥异步里的 promise 比主进程里的还先执行,网上查了下资料:
**promise 函数第一次执行是同步的!!!**只有 then 里面的才是异步的。
所以如上例子, 先执行console.log(2)
然后是打印 4
至于为什么promise.then
要优先于setTimeOut()
原因是promise.then
是微任务setTimeOut()
是**宏任务 **, 微任务的优先级要高于宏任务.
1.4.1 宏任务和微任务
在 js 中,有两类异步任务:宏任务队列,和微任务队列,宏任务队列可以有多个,微任务队列只有一个。
- 宏任务:就是 js 内部的任务,严格按照时间顺序压栈执行,如:SetTimeout, setInterval, setImmediate, i/o, 等
- 微任务:通常来说就是需要在当前 任务 执行结束后立即执行的任务, Promise, Async/Await
宏任务和微任务的执行顺序是,在一次事件循环中, 先运行一次宏任务 -> 然后取出所有微任务 -> 所有微任务执行完成 -> 开始其他宏任务
Script 代码为第一层宏任务,如果有 setTimeout,setInterval,则他们的回调函数会成为第二层的宏任务。
1.5 什么是纯函数,以下那种是纯函数?
列 1:
var a = 10
const fun = (b) => {
return a + b
}
例 2:
var obj = new Object()
const fun = (b) => {
obj.a = 10
return b
}
console.log(fun(5))
ps: 这一题概念记混了,以为除高阶函数之外的就是纯函数(其实例子里面也没有高阶函数,紧张脑子就跟装了浆糊一样,就乱写了)
纯函数:纯函数是指在函数执行过长中,除返回结果外,不会对其他外部状态产生影响,也不依赖外部状态函数,就如上例子中:例子一中, 因为使用了外部变量 a
所以它不是个纯函数,例子二中,因为太对外部变量进行了修改所以它也不是纯函数
1.6 vue2 中修改了对象和数组控制台打印数据更新,页面不更新问题,请给出解决方案
ps: 面的时候只记得数组的 splice 方法了,其他的脑子短路,全部都不知道
方式一:使用Vue.set
或者this.$set
,(对象)
Vue.set(obj, 'a', newValue)
方式二(数组):通过this.arr = [...this.arr]
this.arr = [...this.arr]
方式三(数组):splice 方法
this.arr.splice(index, 1, newValue)
1.7 React 中 useEffect 对应类组件那些生命周期
ps:这个不是很了解,React 没有系统的学习过,只有之前用的时候对照的官方文档看。
- 当 useEffect 第二个参数为空数组的时候[],会在组件挂载后仅执行一次.相当于
componentDidMount
- 不指定第二个参数,或者指定需要监听的依赖数组时,
useEffect
会在组件更新后触发, 相当于componentDidUpdate
useEffect
返回的清除函数会在组件卸载前触发,用于清理副作用。相当于componentWillUnmount
1.8 css 实现左侧固定,右侧自适应
ps:这个我理解成右侧自适适应外边距了 😭😭😭, 写成了margin-right:auto
!!!!, 回来仔细看了看,还 margin-right: auto......,这铁傻蛋了。。。。(怎么应该也是margin-left: auto
)
正确答案应该:flex 布局的
<div class="content">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
.content {
display: flex;
flex-direction: column;
}
.left {
width: 200px;
}
.right {
flex: 1;
}
</style>
1.9 如何实现一个 BFC?
ps: 这个我应该没错吧:overflow:hidden
不过就写了一个
- 方式一:将容器元素的
overflow
属性设置为auto
、hidden
、scroll
或其它非visible
值,会创建一个 BFC - 方式二:将浮动元素的
float
属性设置为left
或right
,会创建一个 BFC。 - 方式三:将容器元素的
position
属性设置为absolute
、fixed
、relative
或sticky
,会创建一个 BFC。 - 方式四:将容器元素的
display
属性设置为inline-block
、table-cell
、table-caption
、flex
、inline-flex
或grid
,会创建一个 BFC。 - 方式五:将一个元素的
clear
属性设置为left
、right
、both
,可以创建一个新的 BFC。
1.10 以下例子怎样才能输出 True?
const a = ?
console.log(a ==1 && a==2 && a==3)
ps:这个我只有在闲逛论坛时刷到过, 只记得要重写一个什么方法, 我写成了 toString()🙄🙄🙄,正确的是 ValueOf(), 好吧根据我后面的了解,两个方法都可以.
// 方式一
const a = {
value: 1,
toString() {
return this.value++
},
}
console.log(a == 1 && a == 2 && a == 3)
// 方式二
const a = {
value: 1,
valueOf() {
return this.value++
},
}
console.log(a == 1 && a == 2 && a == 3)
// 方式三
const a = new Proxy(
{},
{
i: 1,
get(target, prop) {
return () => this.i++
},
}
)
console.log(a == 1 && a == 2 && a == 3)
原因:js 中当对象于基本类型进行比较的时候, 默认会使用对象的valueOf
方法进行比较,没有valueof
方法就会使用toString()
方法,所有在如上例子中, 通过重写该方法 使其递增,就科一实现.
2.面试
ps:大部分都是问项目, 少数几个八股文,我也没准备,都是有啥说啥, 项目也讲的很乱, 老是把一些东西混在一起讲了,现在回想起来, 就一团浆糊, 乱起八糟 😅😅😅😅😅😅😅😅
2.1 Vue2 和 Vue3 有那些区别?
ps:说了 Vue3 的数据劫持的区别,vue3 用的代理,vue2 用到 defineProperty, 然后 vue3 有 tree-shaking,只会把有用的地方打包进去,然后 diff 算法有点区别之外其他的的就不知道.
2.2 v-if 和 v-for 能在一起使用吗?
ps:只知道不建议一起使用,原因不知道。
永远不要把 v-if
和 v-for
同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断),因为 v-for
具有比 v-if
更高的优先级
2.2 你觉得 Ts 在你项目里能起到什么帮助?
ps:说了能让代码更加的规范, 然后能起到类型提示的作用,方便代码编写。
2.3 你用过 git 做过除基本操作之外的其他使用吗?
ps:愣头青,直接说了只会 push, 和 pull .., 其他操作其实也有使用过,但是忘了。。。
其他的差不多都是项目上的问题,还有一些我也不记得了 😅😅😅😅
3.总结
这此面试对自己的表现总的来说可以是很糟糕
1.基础知识不牢固,记得模棱两可。
2.紧张,一问问题就大脑打转, 问完之后直接不知道刚刚回答的是啥,问的是啥.....
3.回答不通畅,表达能力有待提高.
一定要努力改正,增强自己的表达能力,争取下一次面试能做到自己满意。。