头条前端 面试小记
因为是职业生涯第一次面试, 所以有很多地方准备不足的地方, 心理上有点慌张, 现将面试的题目整理一下,实际上这些题目私底下稍微想一下, 都应该能写出来.
1. 实现界面中一个正方形, 宽度高度是body的一半, 同时在body中居中
第一思路是使用flex布局, 确实可以水平和垂直居中, 但是重点在于正方形, 宽高是body的一半
后来提示说可以使用css3的新单位, 想了想rem不行, 后来想到了用vh vw但是自己不会用, 写了一半放弃了, 实际上vh可以实现
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
display:flex;
align-items: center;
justify-content:center;
background: #aaa;
}
.div-center {
height: 50vh;
width: 50vh;
border: 1px solid red;
}
第二种实现方案: 原理: 利用padding的百分比是按照父元素的宽度计算来实现
* {
padding: 0;
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
body {
position: relative;
}
.box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: red;
box-sizing: border-box;
width: 50%;
padding-bottom: 50%;
height: 0;
margin: auto;
}
2. call, apply, bind的区别, 用apply实现自己的bind方法
- 不多说了, 直接贴代码吧, 当时写到一半, 以为自己写不出来, 有点虚, 平时实践的代码还是写的太少了, 概念性的东西懂, 所以要多写代码
function func(a) {
this.a = a;
}
var obj = {};
// var f1 = func.bind(obj, a)
// 柯理化
Function.prototype.bd = function(context) {
// 这里this指的是当前调用的方法
console.log(typeof this)
var _this = this;
return function(a) {
_this.apply(context, [a])
}
}
var a = 1
// 第一个参数 替换func里面的this 第二个参数表示传递的参数
func.bd(obj)(a)
console.log(obj)
Function.prototype.mybind = function(context) {
// 调用mybind的时候传递的参数
var outerArg = Array.prototype.slice.call(arguments, 1)
var _this = this;
// 标准浏览器 这里比较难理解
if ("bind" in Function.prototype) {
// 传递进来的参数传递过bind, 还需要将bind的this指正
return this.bind.apply(this,[context].concat(outerArg))
}
// 兼容化处理
function _fn() {
var innerArg = Array.prototype.slice.call(arguments)
// 将默认传递的参数传递进入
if (innerArg.length==0) {
innerArg.push(window.event);
}
var arg = outerArg.concat(innerArg)
_this.apply(context, arg)
}
return _fn;
}
// 完整版
function bind(callback, context) {
// 考虑传递的参数问题
var ourterArg = Array.prototype.slice.call(arguments, 2)
context = context || window;
function _fn() {
var innerArg = Array.prototype.slice.call(arguments)
console.log(innerArg) // MouseEvent
callback.apply(context, outerArg.concat(innerArg))
}
return _fn;
}
3. JSONP原理, 自己实现JSONP
- 好吧, 我讲的是后台是怎么实现的, 前端我平时都是用jquery已经封装好的, 原理当时讲的是后台返回一段用callback包好数据的一段字符串, 前端用eval进行运行, 写代码的时候傻到用XMLHttpRequest, 唉, 回头一想就知道自己错了
- JSONP原理: 利用<script>标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。当需要通讯时,本站脚本动态创建一个<script>元素,地址指向第三方的API网址, 调用双方协商好的回调函数, 在回调中处理数据
优点: 兼容老式浏览器, 无跨域限制
缺点: 只能是GET请求, 不能发送POST请求
function JSNP(url, callbackName) {
var script = document.createElement('script');
script.src = url+'&callback='+callbackName; // callbackName前后台协商
document.body.appendChild(script); // 只有在append的时候, 脚本才会运行
}
function callback(data) {
alert(data)
}
4. 隐式转换的问题
问题: 隐式转换规则即案例分析
如果x不是正常值(比如抛出一个错误),中断执行。
如果y不是正常值,中断执行。
如果Type(x)与Type(y)相同,执行严格相等运算x === y。
如果x是null,y是undefined,返回true。
如果x是undefined,y是null,返回true。
如果Type(x)是数值,Type(y)是字符串,返回x == ToNumber(y)的结果。
如果Type(x)是字符串,Type(y)是数值,返回ToNumber(x) == y的结果。
如果Type(x)是布尔值,返回ToNumber(x) == y的结果。
如果Type(y)是布尔值,返回x == ToNumber(y)的结果。
如果Type(x)是字符串或数值或Symbol值,Type(y)是对象,返回x == ToPrimitive(y)的结果。
Number( {toString() {return 1} } ) 为1
对象和其他类型比较的时候 对象转化成为PrimitiveValue如果Type(x)是对象,Type(y)是字符串或数值或Symbol值,返回ToPrimitive(x) == y的结果。
不满足上述情况返回false。
- 案例分析: (不多讲直接贴原理)
1) 0==null 不属于上述1-11情况 返回false
2) false == '0'
x是布尔值 属于第8种情况 则 0 == '0'
0 == '0' 属于第6种情况 则 0 == 0
0 == 0 满足第三种情况 返回true
3) true == ({toString() {return '1'}})
x是布尔值 第七种情况 则 Number(true) 即比较 1== ({toString() {return '1'}})
1== ({toString() {return '1'}}) 中 y是对象 满足第10种情况 所以 1 == '1'
1=='1' 满足第6中情况 所以 1==Number('1')
1 == 1 第三种情况 返回true
4) NaN == NaN 不满上上述11种情况 返回false
5) undefined == undefined 满足第三种情况 执行 undefined === undefined 为true
// 头条题目
if ([]== false) { console.log(1); };
if ({} == false) { console.log(2); };
if ([]) { console.log(3); }; //Boolean([])
if ([1] == [1]) { console.log(4); };
5. 自己实现inherit函数, 即实现自己的继承函数
var Animal = function(name) {
this.name = name;
}
Animal.prototype.hello = function() {
console.log('hello, '+ this.name)
}
var Cat = inherit(Animal, {
say:function() {
console.log('MiaoMiao, ' + this.name)
}
})
var cat = new Cat('miaomiao');
cat.hello();
// 题目: 实现inherit函数
6. promise nextTick setTimeout setImmediate的执行顺序问题
console.log('script start'); // 1
setTimeout(function() {
console.log('setTimeout');
}, 0);
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
// 2
console.log('script end');
7. 从长度为m的数组中选取n个数 使其和满足为target, 已知n个数必存在
// 从给定的无序、不重复的数组data中,取出n个数,使其相加和为sum(不需要找到所有的解,找到一个解即可)
8. 快速排序
算法思想: 在待排序的表中L[0....n-1]中, 任意取一个元素作为基准值pivot, 通过一趟排序将待排序列划分为两个独立的部分, 其中L[0 ... k-1]和L[k+1 ... n-1], 其中L[0 ... k-1]所有的元素都小于pivot基准元素, L[k+1 ... n-1]中的元素都大于或者等于pivot , 同时将pivot放在最终的位置L[k]上吗这一趟过程称之为
快速排序
- 时间复杂度: O(nlog2n)
- 稳定性: 不稳定
- 优化:
- 当递归过程中的子序列的规模较小的时, 不要再继续递归调用快速排序, 可以采用直接插入排序算法进行后续的操作
- 尽量选取一个可以将数据中分的枢纽元素 (从序列中头尾以及中间选取三个元素, 将三个元素的中间值作为枢纽元素, 或者随机在序列中获取)
/*时间复杂度: log2n*/
function QuickSort(arr, low, high) {
if (low < high) {
var pivotPos = PartionSort(arr, low, high);
QuickSort(arr, low, pivotPos);
QuickSort(arr, pivotPos + 1, high);
}
}
/*时间复杂度: n */
// 一次PartionSort之后 将arr[low]放在了合适的位置上, 其左侧都比其小, 右侧都比其大
function PartionSort(arr, low, high) {
// 将当前表中的第一个元素当做枢纽值
var pivot = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
var a = [5, 2, 4, 3, 8, 6, 9, 0, 1, 7];
QuickSort(a, 0, a.length - 1);
console.log(a);