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

引言


金三银四,特地整理一份面试题,现介绍本文特色:
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传递发送给服务器,

学如逆水行舟,不进则退
发布了587 篇原创文章 · 获赞 1723 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/weixin_42429718/article/details/104930855