# 近期校招笔试题

## 二分查找数组中出现的第一个元素

```function binarySearch(array, target) {
function getFirstItem(idx) {
while(idx >= 0 && array[idx] === target) {
idx -= 1;
}
return idx + 1;
}
function search(left, right) {
while(left <= right) {
let mid = Math.floor((left + right) / 2);
if(array[mid] === target) {
// 看看 mid 的左边元素是不是与 target 相等（因此要找第一个出现的元素）
return getFirstItem(mid - 1);
} else if(array[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
return search(0, array.length - 1);
}
```

## 防抖、节流

### 防抖：

```function debounce(fn, delay) {
let timer = null;

return function(...args) {
let self = this;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(self, args);
}, delay);
}
}
```

### 节流：

```function throttle(fn, delay) {
let timer = null;
return function(...args) {
let self = this;
// 首次调用不延迟
if(!timer) {
fn.apply(self, args);
}
if(timer)   return;
timer = setTimeout(function() {
fn.apply(self, args);
timer = null;
}, delay);
}
}
```

## 判断一个链表是否有环

```function hasCycle(node) {
if(!node || !node.next) {
return false;
}

let slow = node;
let fast = node.next;

while(slow !== fast) {
// 如果没有环，则快指针会抵达终点
if(!fast || !fast.next) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
// 如果有环，那么快指针会追上慢指针
return true;
}
```

```function hasCycle(node) {
let cache = new Map(),
temp = node;

while(temp) {
cache.set(temp, true);
temp = temp.next;
if(cache.get(temp)) {
return true;
}
}
return false;
}
```

## HTML 模板解析

```<script id="test" type="text/html">
<h1>{{title}} world!</h1>
<div>
<h3>My name is {{data.name}}</h3>
<h4>I'm {{data.age}}</h4>
</div>
</script>

<script>

const user = {
title: 'hello',
data: {
name: 'XiaoMing',
age: 20
}
};
// template 会把数据填充到模板里
const html = template('test', user);

</script>
```

```function template(id, data) {
let content = document.getElementById(id).innerHTML;
// 匹配 {{...}}
const templateReg = /\{\{\s*(.+)\s*\}\}/g;
// 匹配 a.b[1] 形式的数组
const arrayReg = /(\w+)\s*\[(\d+)\]/g;
// 主项就行匹配
let templateData = templateReg.exec(content);
while(templateData) {
// 拿到整体的模板 {{...}} 和 其中的属性
let [templateStr, protoStr] = templateData;
// 分离属性链
let protoArr = protoStr.split('.');
let tempData = data;

// 遍历
protoArr.forEach(proto => {
// 看看有没有数组
let execArr = arrayReg.exec(proto);
if(execArr) {
let [, protoName, index] = execArr;
tempData = tempData[protoName][index];
} else {
tempData = tempData[proto];
}
});
content = content.replace(templateStr, tempData);
templateData = templateReg.exec(content);
}
return content;
}
```

## 两秒后获取数组中的下一个元素

```function run(array, callback) {
let len = array.length, idx = 0;
function play() {
if(idx < len) {
callback(array[idx], idx);
idx += 1;
setTimeout(play, 2000);
}
}
setTimeout(play, 2000);
}

const ary = [
'hello',
'world',
'你好呀~',
'My name is Ming'
];

run(ary, function(item) {
console.log(item);
});
```

## DOM Diff

### Tree Diff

• 将新旧两棵树逐层对比，找出哪些节点需要更新；
• 如果节点是组件就进行 Component Diff；
• 如果节点是标签就进行 Element Diff；

### Component Diff

• 如果节点是组件，就先看组件类型；
• 类型不同直接替换（删除旧的）；
• 类型相同则只更新属性；
• 然后深入组件做 Tree Diff（递归）；

### Element Diff

• 如果节点是原生标签，则看标签名；
• 标签名不同直接替换，相同只更新属性；
• 然后进入标签后代做 Tree Diff（递归）

## 作用域和作用域链

• 变量对象（VO，存储着变量和函数声明）；
• 作用域链；
• this 指向

`[[scope]]` 指的是我们所说的作用域，其中存储了执行期上下文的集合。

### 代码执行过程

• 创建全局上下文；
• 全局执行上下文逐行自上而下执行，遇到函数时，函数执行上下文被 push 到执行栈顶层；
• 函数执行上下文被激活，开始执行函数中的代码，全局执行上下文被挂起；
• 函数执行完毕，函数执行上下文 pop 移除出执行栈，控制权交还给全局上下文，继续执行下面的代码。

## ES5 和 ES6 中的继承

### ES5 版：

```function Super(age, gender) {
this.age = age;
this.gender = gender;
}
Super.prototype.sayAge = function() {
return this.age;
}

function Sub(name, age, gender) {
this.name = name;
Super.call(this, age, gender);
}
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.sayName = function() {
return this.name;
}

let sub = new Sub('ming', 18, 'male');
console.log(sub.sayName());
console.log(sub.sayAge());
```

### ES6 版：

```class Super{
constructor(age, gender) {
this.age = age;
this.gender = gender;
}
sayAge() {
return this.age;
}
}
class Sub extends Super{
constructor(name, age, gender) {
this.name = name;
super(age, gender);
}
sayName() {
return this.name;
}
}
```

## Promise 版 Ajax

```function ajax(url, options) {
options = Object.assign({
method: 'GET',
data: null
}, options);

return new Promise((resolve, reject) => {
let { method, data, headers } = options;
let xhr = new XMLHttpRequest();
xhr.open(method, url, true);
}
if(xhr.status === 200 || xhr.status === 304) {
resolve(xhr.response);
} else {
reject(xhr);
}
}
}
xhr.onerror = function(e) {
reject(e);
}
xhr.send(data);
});
}
```

## 全排列

```function permute(nums) {
function fn(list, tempList, nums) {
if(tempList.length === nums.length) return list.push([...tempList]);
for(let i = 0;i < nums.length;i ++) {
if(tempList.includes(nums[i]))  continue;

tempList.push(nums[i]);
fn(list, tempList, nums);
tempList.pop();
}
}

let result = [];
fn(result, [], nums);
return result;
}
```

0 条评论

• ### 美团2021校招笔试题

·················· END ··················

• ### 华为2017校招C++岗笔试题

输入两个字符串M和N，从字符串M中删除字符串N中所有的字符。例如，输入”abcda”和”ac”，则删除之后的第一个字符串变成”bd”。

• ### 2015美团校招部分笔试题

http://blog.csdn.net/lanxuezaipiao/article/details/41774539

• ### 2014 360校园招聘技术类笔试题

原文：http://blog.csdn.net/lanxuezaipiao/article/details/41892553

• ### 网易2013校园招聘笔试题详解

http://blog.csdn.net/silangquan/article/details/18142651

• ### 19年面试经历分享：我的打怪升级之路

大四开始转语言，开始学习 Java，在此之前只有 Java 基础语法的基础，错过秋招，春招完败。在 19 年的 4 月，在广州找到了一份 Java 的实习，小公...

• ### 找工作面试会遇到哪些坑（校招篇）

先简单介绍一下我的个人履历：我于2013年6月毕业于一个很普通的二本学校，2016年6月毕业于电子科技大学（985院校）。从学校毕业后，我的第一份工作是在一家不...

• ### 备战明年3月

本来周一白天还在外面，晚上6点回到学校，想起当晚在中大有宣讲会，就赶紧吃个晚饭，拉上同学一起过去，本来是准备星期三去华工的那场的。

• ### IC技术圈期刊 2021年第4期

大侠好，欢迎来到FPGA技术江湖，江湖偌大，相见即是缘分。大侠可以关注FPGA技术江湖，在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源，或者一起煮酒言欢。...