普通双非本科生,学的计算机+测绘=地信专业,打不过计算机,干不过测绘,校招企业没一个专业对口的岗位,拿什么跟人家玩?想当年个个任课老师可是夸下海口,说咋们专业可是样样精通,就业面广,文能坐办公室敲代码,武能扛三脚架上山下乡,到头来是两眼泪汪汪。
1.投递的是中国银行湖南分行的科技信息岗(4K-6K),面试流程主要是简历筛选-笔试-面试/复试。这个校招主要就是我们拿着简历给人家看,人家觉得可以就给你一个网申直通卡,这个东西你可以直接在规定的时间去笔试,不用经过简历筛选了,因为如果不是校招去投简历的话一般Hr是看不到你的简历的,所有校招主要就是保证我们可以通过简历筛选直达笔试,但是这个网申直通卡还是比较容易拿到的,简历写得满满当当,人家就看三项指标:1.籍贯(你不是本省的,家人同意你到这边工作吗?),2.期望工作地点(如果不是在期望工作地点可以接受吗?),3.期望薪资(写高了人家就问不是这个薪资范围你可以接受吗?),我一直点头说可以接受就拿到了网申直通卡,当时的想法主要是想验证一下之前的网上说中国银行的笔试题目很变态(题目涉及面非常广,英语、三层矩阵、粒子的静态能源公式、不定积分、高等数学、太阳系天体运动、原子、量子数、洛朗级数展示、计算机题、线性代数、人造卫星半径……只要想不到,没有考不到),但是我觉得那个应该是总部的面试笔试题吧,分行的应该不像网上说的那样变态吧。
2.是通过智联招聘面试的(WebGis工程师,8K-13k,包住不包吃),起初是要到长沙线下面试,但是我跟hr说线上面试就面(主要我知道这个工作其实不适合我,但我还是想积累一下面试经验,所以斗胆提出线上面试),后面那边妥协了,面试主要是先自我介绍,然后就问了一些项目上的问题,问得很简单,最后就谈薪资福利这块了(时间最久),最后了解到是要加班,转正后底薪3000,其他都是绩效奖金,努努力加班6K不是问题,如果项目进度快可以保证每周休息一天,特别强调了新员工要适应加班的环境。
3.参加了长沙某个‘智慧矿山’企业校招的前端开发工程师面试,先是笔试,常规的题目,但是有些我个人认为考得就比较刁钻。笔试+简历筛选后参加一面,先自我介绍,接着和hr聊了简历上面的东西,由于我学习的技能不是纯前端技术栈,因为我是做WebGis的(前端+GIS),但我暑假实习就是干前端,所以hr问了我技能掌握程度如何?(我说没问题,现在技术更新迭代快,学习能力强才是真的强),为什么不在实习公司转正?(其实不是不可以转正,而是我希望可以拿到几家offer后再选择,不是再那里实习就在那里工作)后面还问了学习生活、恋爱和家人对工作地点的意见以及自己的优点问完就说国庆前会有技术面(我说的期望薪资是到手7000,税前应该是9000左右)。技术面问了很多专业性的东西,都是前端的虽然感觉也不难,但就是你平时没注意到,知道但没了解透彻。
这是我在一些面试中遇到的题目,包括笔试和面试问到的以及经典的面试题目:
1.盒子模型:
盒子中主要的属性:width(内容宽)、height(内容高)、margin(外边距)、border(边框)、padding(内边距)。
W3c标准的盒子模型(标准盒模型),width和height指的是内容区域的宽度和高度;
IE标准的盒子模型(怪异盒模型),width和height指的是内容区域、边框、内边距总的宽度和高度;
2.元素盒子水平垂直居中:
分已知元素宽高和不知宽高两种情况
3. alert弹窗:
alert("WWWW", 123);//WWWW
alert("WWWW" + 123);//WWWW123
4. JS判断数据类型方法:
// 1.typeof判断(可以判断基本类型,无法判断对象类型)
console.log(typeof 'hello');//string
console.log(typeof 123);//numnber
console.log(typeof false);//boolean
console.log(typeof Symbol);//function
console.log(typeof new Function());//function
console.log(typeof null);//object,空对象的指针,类型还是对象
console.log(typeof [1, 2, 3]);//object
console.log(typeof { a: 1, b: 'nb' });//object
console.log(typeof new Date());//object
console.log(typeof undefined);//undefined
// 2.instanceof判断(根据已知对象类型判断是否为真)
console.log(null instanceof Object);//false
console.log([1, 2, 3] instanceof Array);//下面的都是true
console.log([1, 2, 3] instanceof Object);
console.log(new Date() instanceof Date);
console.log(new Date() instanceof Object);
console.log(new Function() instanceof Function);
console.log(new Function() instanceof Object);
console.log((/\d/) instanceof RegExp);
console.log((/\d/) instanceof Object);
console.log({ a: 1, b: 'nb' } instanceof Object);
// 3.Object.prototype.toString.call()判断所有数据类型
console.log(Object.prototype.toString.call(123));//Number
console.log(Object.prototype.toString.call("123"));//String
console.log(Object.prototype.toString.call(true));//Boolean
console.log(Object.prototype.toString.call(null));//Null
console.log(Object.prototype.toString.call(undefined));//Undefined
console.log(Object.prototype.toString.call(Symbol()));//Symbol
console.log(Object.prototype.toString.call({ name: 'Hello' }));//Object
console.log(Object.prototype.toString.call([1, 2, 3]));//Array
console.log(Object.prototype.toString.call(function () { }));//Function
console.log(Object.prototype.toString.call(new Date()));//Date
console.log(Object.prototype.toString.call(/\d/));//RegExp
5.改变this指向的方法:
let Person = {
name: "张三",
age: 23
}
function aa(x, y) {
console.log(x + "," + y);
console.log(this);
console.log(this.name);
}
aa(4, 5); //4,5 window undefined
aa.call(Person, 4, 5); //4,5 { name: '张三', age: 23 } 张三 参数分开
aa.apply(Person, [6, 7]); //6,7 { name: '张三', age: 23 } 张三 参数是数组形式
let a=aa.bind(Person, 8, 9); //8,9 { name: '张三', age: 23 } 张三 需要调用方法返回值
a();
6.数组去重方法:
// 1.set方法去重
// 由于set数据结构本身不允许重复的元素出现,为此利用该特性可以快速去重
let arr = [12, 34, 34, 22, 12];
console.log([...new Set(arr)], Array.from(new Set(arr)));//[ 12, 34, 22 ]
// 2.filter去重
// filter不改变原数组,返回符合条件的元素组成新数组,
// 当前元素在数组第一次出现的位置indexof()是唯一的,如果当前元素出现了第二次,
// 那下标index肯定不等于indexof(),所以返回的都是第一次出现的元素
let arr1 = arr.filter((item, index, arr) => { return arr.indexOf(item) === index });
console.log(arr1);
// 3.indexof去重
let arr11 = [];
for (let i = 0; i < arr.length; i++) {
// 空数组没有这个元素就添加进来,有就不追加,确保了空数组最后存储的元素都是唯一的
if (arr11.indexOf(arr[i]) == -1)
arr11.push(arr[i]);
}
console.log(arr11);
// 4.循环对比去重
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
// 前后两元素相同则用splice将后面的那个元素删除
arr.splice(j, 1);
// 元素删除后元素全部前移一位,为此循环位置也要随着前移一位,不然无法判断下一位元素的值
j--;
}
}
}
7.深浅拷贝:
浅拷贝:是对象的引用地址,没有开辟新的栈,复制的结果是两个对象指向同一个地址,所以修改其中一个对象的属性,另一个对象的属性也跟着改变了。默认情况下引用类型(object)都是浅拷贝。
深拷贝:开辟新的栈,两个对象对应两个不同的地址,修改对象A的属性,并不会影响到对象B。默认情况下基本数据类型(number,string,null,undefined,boolean,symbol)都是深拷贝。为此我们一般注重的问题是对象类型如何进行深拷贝?
一维数组的深拷贝(不适用于2维数组及以上,元素不能是对象类型):
let as = [11, 22, 33, 44, 55];
let as1 = [...as];
let as2 = Array.from(as);
let as3 = as.slice();
let as4 = as.concat();
as[4] = 999;
console.log(as);//[ 11, 22, 33, 44, 999 ]
console.log(as1);//[ 11, 22, 33, 44, 55 ]
console.log(as2);//[ 11, 22, 33, 44, 55 ]
console.log(as3);//[ 11, 22, 33, 44, 55 ]
console.log(as4);//[ 11, 22, 33, 44, 55 ]
//不适合2维数组进行深拷贝
let as = [[11, 22], [33, 44, 55]];
let as1 = [...as];
let as2 = Array.from(as);
let as3 = as.slice();
let as4 = as.concat();
as[1][2] = 999;
console.log(as);//[ [ 11, 22 ], [ 33, 44, 999 ] ]
console.log(as1);//[ [ 11, 22 ], [ 33, 44, 999 ] ]
console.log(as2);//[ [ 11, 22 ], [ 33, 44, 999 ] ]
console.log(as3);//[ [ 11, 22 ], [ 33, 44, 999 ] ]
console.log(as4);//[ [ 11, 22 ], [ 33, 44, 999 ] ]
//不适合对象数组进行深拷贝
let as = [{ name: 'LiuMing' }, { age: '21' }];
let as1 = [...as];
let as2 = Array.from(as);
let as3 = as.slice();
let as4 = as.concat();
as[0].name = '李四';
as[1].age = 18;
console.log(as);//[ { name: '李四' }, { age: 18 } ]
console.log(as1);//[ { name: '李四' }, { age: 18 } ]
console.log(as2);//[ { name: '李四' }, { age: 18 } ]
console.log(as3);//[ { name: '李四' }, { age: 18 } ]
console.log(as4);//[ { name: '李四' }, { age: 18 } ]
对象的深拷贝:
// 构造函数
function person(pname) {
this.name = pname;
}
const Messi = new person('Messi');
// 函数
function say() {
console.log('hi');
};
const oldObj = {
a: say,
b: new Array(1),
c: new RegExp('ab+c', 'i'),
d: Messi,
e: 23,
f: 'niubi',
g: [1, 2, 3],
h: true,
};
const newObj = JSON.parse(JSON.stringify(oldObj));
// 无法复制函数
console.log(newObj.a, oldObj.a); // undefined [Function: say]
// 稀疏数组复制错误
console.log(newObj.b[0], oldObj.b[0]); // null undefined
// 无法复制正则对象
console.log(newObj.c, oldObj.c); // {} /ab+c/i
// 构造函数指向错误
console.log(newObj.d.constructor, oldObj.d.constructor); // [Function: Object] [Function: person]
newObj.e = 99;
newObj.f = 'Lihai';
newObj.g = ['ef', 'gf'];
newObj.h = false;
console.log(newObj.e, newObj.f, newObj.g, newObj.h);//99 Lihai [ 'ef', 'gf' ] false
console.log(oldObj.e, oldObj.f, oldObj.g, oldObj.h);//23 niubi [ 1, 2, 3 ] true
8.递归及其应用:
递归是函数运行过程中不断调用自己,终止条件必须在自身调用前,调用次数多容易导致内存栈溢出。
// 递归----阶乘
function jc(n) {
if (n <= 1)
return n;
return jc(n - 1) * n
}
console.log('递归---阶乘:', jc(6));//720
// 递归----斐波那契数列
function fbnq(n) {
if (n <= 1)
return n;
return fbnq(n - 1) + fbnq(n - 2);
}
console.log('递归---斐波那契数列:', fbnq(6));//8
9.闭包及其应用:
闭包:有权访问另一个函数作用域变量的函数;
形成条件:函数嵌套;内部函数调用外部函数的局部变量,延长其生命周期;
缺点:函数变量一直保存在内存中,过多的闭包容易导致内存泄漏。
节流:如果鼠标在屏幕一直动,每一秒钟显示一次屏幕坐标;
防抖:如果鼠标在屏幕一直动则不显示坐标,鼠标停下来一面后显示屏幕坐标;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
#mydiv {
display: flex;
height: 300px;
width: 500px;
border: 2px chartreuse solid;
}
#mydiv1 {
display: flex;
height: 300px;
width: 500px;
border: 2px salmon solid;
}
</style>
<body>
<div id="mydiv">
</div>
<div id="mydiv1">
</div>
</body>
<script>
// 节流:持续触发不会执行多次,到一定时间在执行
let box = document.getElementById('mydiv');
let run = true;
function throttle(func, delay) {
return function () {
if (!run) {
return // 如果开关关闭了,那就直接不执行下边的代码
}
run = false // 持续触发的话,run一直是false,就会停在上边的判断那里
setTimeout(() => {
func.apply(this, arguments)
run = true // 定时器到时间之后,会把开关打开,我们的函数就会被执行
}, delay)
}
}
box.onmousemove = throttle(function (e) {
box.innerHTML = `${e.clientX}, ${e.clientY}`
}, 1000)
// 防抖:持续触发不执行,不触发一段时间后执行
let box1 = document.getElementById('mydiv1');
let timeout
function debounce(func, delay) {
return function () {
clearTimeout(timeout) // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。
timeout = setTimeout(() => {
func.apply(this, arguments)
}, delay)
}
}
box1.onmousemove = debounce(function (e) {
box1.innerHTML = `${e.clientX}, ${e.clientY}`
}, 1000)
</script>
</html>
10.Set和Map数据结构:
都可以存储不重复的值,Set类似于一维数组,Map类似于二维数组,但是里面元素是以键值对的形式存在。
// set的属性方法
let arr = new Set([5, 6, 8]);
arr.add(1);//添加值
arr.delete(8);//删除值
let a = arr.has(8);//判断是否有某个值
for (let x of arr) { // 遍历Array
console.log(x);
}
console.log(arr,a);//Set(4) { 5, 6, 1, 2 } false
arr.clear();//清空集合
console.log(arr);//Set(0) {}
// map的属性方法
let m1 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85], ['Tracy', 85]]);
m1.set('Adam1', 67);//添加或者修改某个键key的值
m1.delete('Bob');//删除键key对应的值
console.log(m1.has('Bob'))//判断字典中是否有对应的键key
console.log(m1.get('Adam1'))//获取键key对应的值
for (let x of m1) { // 遍历Array
console.log(x);
console.log(x[0] + '-' + x[1]);
}
// [ 'Michael', 95 ]
// Michael-95
// [ 'Tracy', 85 ]
// Tracy-85
// [ 'Adam1', 67 ]
// Adam1-67
m1.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引key
// array: 指向Array对象本身
console.log(element + ', index = ' + index);
});
// 95, index = Michael
// 85, index = Tracy
// 67, index = Adam1
m1.clear();//清空字典
console.log(m1);//Map(0) {}
11.字符串和数据的加减乘除:
+:结果是字符串+字符串;
-,*,/:结果都是数字-数字,数字*数字,数字/数字;
console.log('123' + 45);//12345
console.log('46' - 45);//1
console.log('55' / 5);//11
console.log('5' * 5);//25
12.基本类型比较判断:
![],[],false,'',0这5个之间使用==比较都是true,剩下的数据类型使用==比较都是false;
===是数据类型相同情况下比较才可能相等;
// 假
console.log(0 == null, 0 == undefined, 0 == {})
console.log(undefined == null, undefined == '', undefined == [], undefined == {})
console.log(null == '', null == [], null == {})
console.log('' == {}, false == undefined, false == null, false == {});
// 真
console.log(false == 0, false == '', false == [], false == ![],
'' == [], '' == ![], '' == 0, 0 == [], 0 == ![], [] == ![]);
13.JS数组操作方法:
非常多,这里罗列一部分。
// js数组操作方法
let s1 = [1, 2, 3]
let s2 = [4, 5]
let s3 = s1.concat(s2)
console.log(s3) // [1, 2, 3, 4, 5]
// join(str) 数组转字符串
let s4 = [1, 2, 3]
console.log(s4.join()) // 1,2,3
console.log(s4.join(':')) // 1:2:3
// 实现重复数组
let s5 = new Array(9).join('啦')
console.log(s5) // 输出8个啦
let s6 = [1, 2, 3];
s6.push(7, 7, 8, 8);//后面加上若干元素
s6.unshift(0, 0, 0);//前面加上若干元素
s6.pop();//删除最后一个元素
s6.shift();//删除第一个元素
console.log(s6);
// sort排序
let s7 = [2, 4, 3, 1, 9, 12]
s7.sort((a, b) => a - b);
console.log(s7);//小到大
s7.sort((a, b) => b - a)
console.log(s7);//大到小
console.log(s7.reverse());//反转数组
let s8 = [1, 2, 3, 4, 5]
console.log(s8.splice(0, 3));//从第0个元素开始截取,一共截取3个元素,会改变原数组
let s9 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(s9.splice(1, 4, 99, 98, 97));//从第1个元素开始截取,一共截取4个元素,会改变原数组
console.log(s9)//此时原数组已经被挖了4个元素且在挖掉的地方填充了99,98,97这3个元素
let s10 = [1, 2, 3, 4, 5, 6, 7]
console.log(s10.slice(2, 4));//从第2个元素开始截取,截取到第3个元素,一共截取2个元素,不改变原数组
篇幅太长,后面再加点面试题吧,太多了,一下子写不完的。