某上市公司前端面试流程可以完善如下:
简历投递筛选:可以通过直接投递、猎头推荐或内部员工推荐的方式进行简历投递。简历通过初筛后(建议简历要写的尽可能漂亮一些,懂得都懂......),HR会联系候选人了解基本情况。
笔试或线上评测:现场笔试大概四五十分钟,时间基本足够的,我是现场笔试,线上具体情况不知。
技术面试:技术面试可能会涉及到具体的开发技术栈相关的问题,如JS数组的常用方法(foreach、map、filter、reduce等)、闭包、JS事件循环机制、。
专业面试:通过笔试或者线上测评后,会进入专业面试环节,面试官可能会根据简历中的项目相关问题进行详细询问。
HR面试:HR面试环节,HR会询问候选人的个人情况、实习经历、职业规划等,并讨论薪资待遇问题。
综合评估:面试结束后,公司会对候选人进行综合评估。
背调+体检:在某些情况下,公司可能会进行背景调查和体检。
Offer发送:然后就是HR提offer审批流程,走完审批会向候选人发送Offer。
入职:接受offer并上传入职资料,候选人正式入职。
以上为本人前端面试相对完整的流程。下面也简单分享下一些笔试面试题,可能不是原题,但具体的知识点大概就是这些,可以当作参考。
选择题:
-
主要涉及以下知识点
- 声明变量的关键字var/let/const, 各自特点和区别
- var变量提升
- 闭包。
- 原型链。
- 箭头函数。
- 作用域链
- this指向
1. 关于var、let、const的变量声明,以下代码的输出是什么?
var a = 10;
let b = 20;
const c = 30;
if (true) {
var a = 5;
let b = 6;
const c = 7;
console.log(a + b + c); // ?
}
A. 10 + 20 + 30
B. 5 + 6 + 7
C. 5 + 20 + 30
D. 10 + 6 + 7
答案:B
解析:var声明的变量a被提升并重新赋值为5,而let和const声明的变量b和c不会提升,它们只在它们所在的块级作用域内有效,所以b和c的值分别是6和7。
2. 下列关于JavaScript变量提升的代码,输出是什么?
console.log(foo); // ?
var foo = 1;
A. undefined
B. 1
C. ReferenceError
D. null
答案:A
解析:var声明的变量会发生变量提升,但是不会提升赋值,所以当尝试打印未赋值的foo时,会是undefined。
3. 关于JavaScript闭包,以下代码的输出是什么?
function outer() {
var x = 10;
function inner() {
console.log(x);
}
inner();
}
outer(); // ?
A. undefined
B. 10
C. ReferenceError
D. null
答案:B
解析:闭包允许内部函数inner访问外部函数outer的变量x,所以输出是10。
4. JavaScript原型链的以下代码输出是什么?
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
};
var person = new Person('Kimi');
person.sayName(); // ?
A. undefined
B. Kimi
C. Person
D. ReferenceError
答案:B
解析:sayName方法通过this关键字访问了Person实例的name属性,输出是Kimi。
5. 下列关于箭头函数的代码,输出是什么?
const add = (a, b) => a + b;
console.log(add(1, 2)); // ?
A. 3
B. undefined
C. "12"
D. ReferenceError
答案:A
解析:箭头函数没有自己的this,它们会捕获其所在上下文的this值,这里this不是需要的,因为add函数只是简单地返回两个参数的和。
6. 关于JavaScript作用域链的以下代码,输出是什么?
var x = 10;
function test() {
var x = 20;
function doTest() {
var x = 30;
console.log(x);
}
doTest();
}
test(); // ?
A. 10
B. 20
C. 30
D. undefined
答案:C
解析:doTest函数访问了它自己的局部变量x,其值为30。
7. 下列关于this指向的代码,输出是什么?
function showThis() {
console.log(this);
}
showThis.call(window); // ?
A. window
B. undefined
C. showThis
D. null
答案:A
解析:call方法显式地设置了this的值,这里this被设置为window对象。
填空题:
- 主要也是关于作用域链、闭包等知识点 以下是一些关于作用域链和闭包的填空题,结合代码:
1. 下面代码的输出是______________________
function outerFunction() {
var outerVar = "I am outer";
function innerFunction() {
var innerVar = "I am inner";
console.log(outerVar + " " + innerVar); // ?
}
innerFunction();
}
outerFunction();
填空:上述代码的输出是 "I am outer I am inner"。这是因为innerFunction通过作用域链可以访问到其外部函数outerFunction的变量outerVar。
2. 下面代码的输出是______________________
function createClosure() {
var secret = "I am a secret";
return function() {
console.log(secret); // ?
};
}
var closure = createClosure();
closure();
填空:上述代码的输出是 "I am a secret"。这是因为返回的函数是一个闭包,它捕获了createClosure函数的词法环境,包括变量secret。
3. 下面代码的输出是______________________
function foo() {
if (typeof bar === "undefined") {
var bar = "Local variable";
}
console.log(bar);
}
foo();
填空:上述代码的输出是 "Local variable"。这是因为bar在foo函数的作用域中被声明,且变量提升只提升了声明,没有提升赋值。
4. 闭包和循环填空题
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // ?
}, 100);
}
填空:上述代码的输出是 "5" 五次。这是因为setTimeout回调函数中的i是被闭包捕获的,且由于var的函数作用域特性,所有的回调函数共享同一个i。
5. 下面代码的输出是______________________
function bindContext(someContext) {
let outerStr = 'nav'
return function() {
console.log(outerStr === someContext); // ?
};
}
const boundContext = bindContext('nav');
boundContext();
填空:上述代码的输出是 true。这是因为bindContext函数返回了一个闭包,这个闭包捕获了bindContext被调用时的outerStr值。
6. 作用域链和全局变量填空题
var myVar = "I am global";
function outerFunction() {
myVar = "I am outer";
function innerFunction() {
var myVar = "I am inner";
console.log(myVar); //?
}
innerFunction();
}
outerFunction();
填空:上述代码的输出是 "I am inner"。这是因为myVar变量在innerFunction函数的作用域内被声明,即使在outerFunction语句块中重新赋值,也不会影响innerFunction内部的myVar变量。
7. 下面代码的输出是______________________
function generateFunctions() {
var result = [];
for (var i = 0; i < 5; i++) {
result.push(function() {
return i; // ?
});
}
return result;
}
var functions = generateFunctions();
functions[0]();
填空:上述代码的输出是 5。这是因为所有的回调函数共享同一个i变量,而这个变量在循环结束时被赋值为 5。
代码实现题目
1、要统计一个字符串中出现最多的字符及其个数:
function findMostFrequentChar(str) {
// 创建一个对象用于存储每个字符的出现次数
let charCount = {};
// 遍历字符串,将每个字符的出现次数记录到对象中
for (let char of str) {
charCount[char] = (charCount[char] || 0) + 1;
}
// 初始化变量存储出现最多的字符和次数
let maxChar = '';
let maxCount = 0;
// 遍历字符出现次数的对象,找出出现次数最多的字符
for (let char in charCount) {
if (charCount[char] > maxCount) {
maxChar = char;
maxCount = charCount[char];
}
}
return { maxChar, maxCount };
}
// 测试
let str = "abbbccddeeeffgggghhh";
let result = findMostFrequentChar(str);
console.log(`出现最多的字符是 '${result.maxChar}',共出现了 ${result.maxCount} 次。`);
代码解释:
charCount对象用于记录每个字符的出现次数。- 遍历字符串
str,将每个字符的出现次数记录在charCount中。 - 遍历
charCount对象,找到出现次数最多的字符,并更新最大值。 - 返回最多字符和其出现次数。
2、实现一个JS的继承(可以自由发挥,可以使用ES5的组合式继承,也可以使用ES6的语法糖)
在ES6中,我们可以使用class关键字和extends关键字来实现继承。以下是一个使用ES6语法糖实现继承的示例:
// 父类(基类)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
// 子类(派生类)
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类的constructor方法
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`);
}
// 子类特有的方法
fetch() {
console.log(`${this.name} fetches the ball.`);
}
}
// 使用
const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // 输出:Buddy barks.
dog.fetch(); // 输出:Buddy fetches the ball.
在这个例子中:
Animal类是一个父类,它有一个speak方法。Dog类通过extends关键字继承自Animal类。Dog类的构造函数中,使用super(name)调用了父类的构造函数,这是必要的,因为子类的构造函数需要确保父类的构造函数被执行。Dog类覆盖了父类的speak方法,并添加了一个新方法fetch。
这样,Dog类就继承了Animal类的属性和方法,并且还可以有自己的特定属性和方法。
3、将多端英文句子处理成每个单词首字母大写
如果句子包含多行,并且需要将每行中的每个单词首字母大写,可以使用以下函数来处理:
function capitalizeText(text) {
// 将文本按行分割成数组
const lines = text.split('\n');
// 处理每一行,将每个单词的首字母大写
const capitalizedLines = lines.map(line =>
line.split(' ').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' ')
);
// 将处理后的行重新组合成一个字符串,并用换行符连接
return capitalizedLines.join('\n');
}
// 使用示例
const text = `hello world,
this is kimi.
how are you today?`;
const capitalizedText = capitalizeText(text);
console.log(capitalizedText);
输出将会是:
Hello World,
This Is Kimi.
How Are You Today?
在这个函数中:
text.split('\n')将输入的多行文本按照换行符分割成数组。map(line => line.split(' ').map(...).join(' '))对每一行进行处理,将每个单词的首字母大写。join('\n')将处理后的行重新组合成一个字符串,并用换行符连接。