您的位置:首页 > 其它

【金三银四】一个问题就知道你看没看过源码了 深度挖掘必问源码题

2020-04-07 18:31 1651 查看

引言

金三银四,特地整理一份面试题,现介绍本文特色:
1、适合前端,需要面试找工作
2、即将毕业面临实习,积累经验
3、从务实基础到彻底弄懂
4、探索框架源码,研究前端必备算法
5、直击阿里、腾讯、美团、今日头条等大厂原题,逐步引入
6、学完即准备投简历

BAT/TMD这样的大公司是如何面试的

注意嗷,在这里TMD可不是骂人的话哦,可能你知道BAT,但TMD你知道么?(不知道赶紧去百度!)

T(今日头条)M(美团)D(滴滴)成为了BAT之后互联网江山的新巨头

相关文章

【金三银四】一个问题就知道你会不会CSS了

【金三银四】一个问题就知道你会不会JS了 阿里、头条真题解析

上期遗漏的知识拓展

在上一篇关于JS真题,最后忘记对知识进行拓展了,因此在这里进行补充

第一题

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
var a = ?; //该题意思是变量a应该等于什么值 可以让条件成立
if(a == 1 && a==2 && a==3){
console.log(1);
}
</script>
</body>
</html>

相关知识点:

== 数据类型不一样

例如: 对象 == 字符串 会通过对象.toString()变为字符串

null == undefined 相等 但是和其它值进行比较时不相等

NaN == NaN 不相等 因为NaN和任何都不相等,包括自己

剩下的都是转化成数字,例如:

第一种解决办法,自己写一个toString()( 也可以用valueof() )

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
var a = {
i: 0,
toString(){
return ++this.i;
}
}
if(a == 1 && a==2 && a==3){
console.log(1);
}
</script>
</body>
</html>

第二种解决办法,采用数据劫持

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
var i=0;
Object.defineProperty(window,'a',{
get(){
return ++i;
}
})
if(a == 1 && a==2 && a==3){
console.log(1);
}
</script>
</body>
</html>

第三种解决办法,用数组的shift()方法

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
var a=[1,2,3];
a.toString=a.shift;
if(a == 1 && a==2 && a==3){
console.log(1);
}
</script>
</body>
</html>

当然,方法还有很多很多,这里就例举容易想到的三个

第二题

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
function A(){
alert(1);
}
function Func() {
A=function(){
alert(2);
}
return this;
}
Func.A=A;
Func.prototype={
A:()=>{
alert(3);
}
};
A();   //'1'
Func.A(); //'1'
Func().A(); //'2'
new Func.A(); //'1'
new Func().A(); //'3'
new new Func().A(); //'bug'
</script>
</body>
</html>

相关知识点:

箭头函数无法new

箭头函数和普通函数的区别:

  • 箭头函数没有this主体,this都是继承上下文的this。
  • 箭头函数无法被new的原因是箭头函数没有原型链,也就没有构造器函数constructor

第三题

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>
<body>
<script>
var x=0,y=1;
function fn(){
x+=2;
fn=function(y){
console.log(y+ (--x) );
};
console.log(x,y);
}
fn(3); //2 1
fn(4); //5
console.log(x,y); // 1 1
</script>
</body>
</html>

相关知识点:

重写fn函数

第四题

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>面试真题</title>
</head>

<body>
<script>
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);

setTimeout(() => {
console.log(3);
}, 10);

console.log(4);
console.time('AA');
for (let i = 0; i < 90000000; i++) {
//do something
}
console.timeEnd('AA'); //97ms左右
console.log(5);

setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
</script>
</body>

</html>

相关知识点:

宏任务: 定时器例如setTimeout(异步)、事件绑定

面试题引入

1.Vue2.0双向绑定的实现原理

强烈推荐阅读:Vue 技术栈 手写响应式原理 到 探索设计模式(通过源码精通双向绑定)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
name:<span id="spanName"></span>
<br>
<input type="text" id="inpName">
<script>
let obj={
name:''
};
let newObj={
...obj
};
Object.defineProperty(obj,'name',{
get(){
return newObj.name;
},
set(val){
if(val===newObj.name) return;
newObj.name=val;
observer();
}
});
function observer(){
spanName.innerHTML=obj.name;
inpName.value=obj.name;
}
observer();
setTimeout(()=>{
obj.name="超逸の博客!";
},2000);

inpName.oninput = function() {
obj.name=this.value;
};

</script>
</body>
</html>

2.0版本defineProperty存在的问题:

  • 需要对原始数据进行拷贝
  • 需要分别给对象中的每一个属性设置监听,会需要for in循环以及递归操作
2.Vue3.0双向绑定的实现原理

强烈推荐阅读:Vue 技术栈 手写响应式原理 到 探索设计模式(通过源码精通双向绑定)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
name:<span id="spanName"></span>
<br>
<input type="text" id="inpName">
<script>
let obj={
name:''
};
obj=new Proxy(obj,{
get(target,prop){
return target[prop];
},
set(target,prop,value){
target[prop]=value;
observer();
}
})
function observer(){
spanName.innerHTML=obj.name;
inpName.value=obj.name;
}
observer();
setTimeout(()=>{
obj.name="超逸の博客!";
},2000);

inpName.oninput = function() {
obj.name=this.value;
};

</script>
</body>
</html>

总结:为什么Vue 3中使用proxy

  • defineProperty只能监听某个属性,不能对全对象进行监听
  • 可以省去for in遍历找对象中的属性,提高效率,省去很多代码
  • 可以监听数组,不用再去单独的对数组进行特异性操作
  • 不会污染原对象,会返回一个新的代理对象,原对象依旧是原对象
  • 只需对代理对象进行操作
3.MVC和MVVM的区别

关于这个问题呢,就是关于vue和react的区别,你可以参考如下回答:

没有很大区别,知识MVC是单向数据绑定,只绑定了数据更改然后视图跟着渲染,而MVVM实现了双线数据绑定,在基础上多了一层视图更改,对应数据绑定也跟着更改。要从MVC到MVVM其实不难,一个onchange事件搞定,所以没很大区别。

4.跨域问题的解决方案和实现原理

跨域问题的产生及其价值意义

知识点拓展:

http默认端口 80
https默认端口 443
ftp默认端口 21

在过去,前后端分离之前,不存在跨域问题,是因为那时候前端和后端都是部署在同一个服务器上,同一个域下,同一个端口下,代码都放一起就不存在跨域问题了。

后来,区分Web服务器和数据服务器之后,就存在了跨域问题。

JSONP跨域解决方案的底层原理

客户端

get请求问题:

  • 不安全
  • 有缓存
  • 大小限制
  • 需要服务器的支持 拼接数据等

发现问题挺多,JSONP就过时了,于是尝试用post请求

基于iframe的跨域解决方案

  • window.name
  • document.domin
  • location.hash
  • post message

但上述都是存在一些问题的,后来呢,能不能让服务器进行跨域请求呢?

于是,出现了如下解决方式:

CORS跨域资源共享

客户端

import axios from 'axios';
import qs from 'qs';
axios.defaults.baseURL = "http://127.0.0.1:3000";
axios.defaults.timeout = 10000;
axios.defaults.withCredentials = true;

/**
* 设置请求传递数据的格式(看服务器要什么格式)
* x-www-form-urlencoded
*/
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = data =>qs.stringify(data);

/**
* 设置请求拦截
* TOKEN校验(JWT):接受服务器返回的token,存储到vuex/本地存储中,
* 每一次向服务器发送请求,应该把token带上
*/
axios.interceptors.request.use(config => {
let token = localStorage.getItem('token');
token && (config.headers.Authorization = token);
return config;
}, error => {
return Promise.reject(error);
});

/**
* 响应拦截器
*/
axios.interceptors.response.use(response => {
return response.data;
},error => {});

export default axios;

服务器端

app.use((req,res,next) => {
res.header("Access-Control-Allow-Origin","");
res.header("Access-Control-Allow-Credentials",true);
res.header("Access-Control-Allow-Headers","PUT,POST,GET,DELETE,OPTIONS,HEAD");
res.header("Access-Control-Allow-Methods","Content-Type,Content-Length,Authorization,Accept,X-Requested-With");
req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMIN REQUESTS!') : next();
});

CORS跨域与客户端没啥关联,主要是看服务端,但是也存在一点问题:

例如在服务端设置"Access-Control-Allow-Origin","*" (设置这里为 * ) ,允许所有源,此时就不能携带证书凭证了。

于是,后面又出现了新的一种跨域方式:

基于http proxy实现跨域请求(开发时使用)

nginx反向代理(部署时使用)

5.Vue框架中关于组件信息通信问题

(还在学习中,拖更…)

  • 属性传递
  • 发布订阅(EventBus):$on / &emit
  • Provide / inject
  • slot
  • $parent / $Children
  • vuex

客户端

但是,想实现任意组件之间都能通信,只能通过

本地存储
方案。包括vuex / redux公共状态管理,不过存储在虚拟机内存里面。

另外,还有一个能够存储在

浏览器
里面的就是
localStroage

vuex和localStorage两者区别:

vuex一刷新就没了,而localStorage一直存在(持久化存储),不过需要进行时间限制

因此引申到cookie,为什么不用cookie呢,因为大小限制,只有4k,而localStorage有5M

而且cookie容易被干掉。

那么例如用户是否登录,基本信息就不用localStorage存储了,就考虑使用vuex / redux公共状态管理,因此对性能进行了优化

服务端

与cookie相对应的就是

session
,当服务器设置session,服务器返回给客户端的信息,在响应头中,会携带
set-cookie="content_sid"
客户端会把信息种植到本地的cookie中,并且是http公认的,只可读不可写。

客户端再次向服务器发送请求的时候,会默认在请求头的cookie中,把content_sid传递发送给服务器,

学如逆水行舟,不进则退
  • 点赞 2
  • 收藏
  • 分享
  • 文章举报
一百个Chocolate 博客专家 发布了600 篇原创文章 · 获赞 2156 · 访问量 34万+ 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: