前端面试题总结

---------js面试题

继承和变量提升的笔试题

	function Foo() { 
        getName = function() { 
            alert(1); 
        };
        return this;
    }
    Foo.getName = function() { 
        alert(2);
    };
    Foo.prototype.getName = function() {
         alert(3);
    };
    var getName = function() {
        alert(4);
    };
    function getName() { 
        alert(5);
    }
    Foo.getName(); // 2
    getName(); // 4
    Foo().getName(); // 1
    getName(); // 1
    new Foo.getName(); // 2
    new Foo().getName();  // 3
    new new Foo().getName(); // 3
    

对浏览器回收机制的了解

http://www.ruanyifeng.com/blog/2017/04/memory-leak.html
https://segmentfault.com/a/1190000018605776
什么是内存泄漏
程序的运行需要内存,只要程序提出要求,操作系统或者运行时就必须供给内存。
对应持续运行的服务进程,必须及时释放不在用到的内存,否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏。

如何回收
标记回收:浏览器将所有引用变量加上标记,然后将全局引用的变量以及闭包的标记清除。在执行js代码的时候会进入一个执行环境,当离开当前执行环境时,当前执行环境内标记的变量会被清除,大多数浏览器都是使用这种方式。
引用计数:每次引用一个变量,都会在引用计数中+1,如果这个值赋给另一个引用,那么加+1,相反如果当引用这个值的变量引用了其他的变量,那么就会-1,当引用计数为0时,就会被垃圾回收器清除

什么是闭包,为什么要用它?

闭包是指有权访问留一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
闭包有两种常用的用途,闭包的第一个用途是使我们在函数外部能够访问到函数内部的变量。通过使用闭包,我们可以通过在外部调用闭包函数,从而在外部访问到函数内部的变量,可以使用这种方法来创建私有变量; 第二个用途是使已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收。
其实闭包的本质就是咋作用域链的一个特殊的应用,只要了解了作用域链的创建过程,就能够理解闭包的实现原理。

原型

   function foo() {
       getName = function () {
           console.log(1);
       }
       return this;
   }
   foo.getName = function () {
       console.log(2);
   }
   foo.prototype.getName = function () {
       console.log(3);
   }
   var getName = function () {
       console.log(4);
   }
   function getName() {
       console.log(5);
   }
   //foo.getName();           // 2
   //getName();               // 4
   //foo().getName();         // 1     这里调用foo()函数,改变了getName的值  相当于 var a = 1;调用一个方法后 a = 2;
   //getName();               // 1     如果 前面没有foo().getName()给 getName重新赋值的话,那就等于4
   //new foo.getName();       // 2    这里就是重新调用了一下foo上的方法
   //new foo().getName();     // 3     new的是foo()这个函数,它上面的显示有方法的话用方法,没有的话取原型的,否则default
   // new new foo().getName(); // 3       原型也可以拷贝


实现一个 new


function newA(fn, ...params){
    // 先创建一个空对象
    var obj = Object.create(fn.prototype); // 原型指向构造函数的 prototype属性
    /*
    同理 
    var obj = {};
    if(fn.prototype !== null){
        obj.__proto__ = fn.prototype
    }

    */

    // 改变this指向和参数
    var res = fn.apply(obj,params)
    /* 同理 var res = fn.apply(obj, Array.prototype.slice.call(arguments,1)) */
    //正常规定,如何fn返回的是null或undefined(也就是不返回内容),我们返回的是obj,否则返回rel
    return res instanceof Object ? res : obj

}

----------VUE面试题

vue 为什么是一个函数不是class类那

是因为在后面调用的 initMixin(Vue),stateMixin(Vue)等都会用到Vue,Vue按功能把这些扩展分散到多个模块中去实现,而不是在一个模块库实现所有,用class难以实现,所有用的function

为什么在init函数中调用initInjections函数和initProvide函数之间穿插一个initState函数呢

provide 和 inject 选项绑定的数据不是响应式的
我们通常所写data、props、watch、computed及method会用到inject的数据,所以inject选项接收到注入的值有可能被以上这些数据所使用到,所以在初始化完inject后需要先初始化这些数据,然后才能再初始化provide,所以在调用initInjections函数对inject初始化完之后需要先调用initState函数对数据进行初始化,最后再调用initProvide函数对provide进行初始化。

vue和react的区别有哪些那?

相同点

组件化
vue和react都可以将一个应用拆成一个一个组件,不同组件对应不同功能,相同功能组件还可以复用,提高开发效率同时还方便维护

VDOM
虚拟dom,vue和react都用到了虚拟dom,因为考虑的修改真实dom比修改js的开销比较大,通过比较js的vdom判断要修改的dom,减少真实dom修改次数,提高性能。

不同点

模板
vue是把html,js,css写在了一个vue的文件里,除了一些vue的一些方法,原有原生的方法基本都可以用。
react是在javascript里面可以写html语法,也就是jsx语法。

传参
vue 父子传参可以用 props 和$eimt ,组件之间传参有 provide 和vuex等方法
react 父子可以通过在子组件上绑定属性,用 super(props) 来 获取属性上的值和方法,组件之间有react-redux

状态管理
vue的状态是在data里面管理,可以通过 this.name 修改,dom是可以直接绑定使用
react 是在 constructor里面声明 this.state ,修改需要用 setState()

语法
vue 相当于我们平常写的页面,js html css变化不大,很好上手
react 用jsx,偏向于函数编程。

Vue2和Vue3数据响应式的区别

vue2数据响应式用的是 Object.defineProperty()getset方法对数据做劫持。
vue3是用的ES6的 Proxy代理重新生成一个对象,重新定义的getset行为。
主要区别:
1, Object.definePropety()是数据劫持,会重写原对象,Proxy 代理原对象生成一个新的对象,不会被覆盖。
2,在vue2里的数据绑定需要循环和递归,数组要进行方法重新定义劫持,而 Proxy可以省略这些方法,直接绑定即可,减少代码量也减少浏览器开销
3, 代码更加简洁优雅。

vue diff的理解

1、必要性:在创建每个组件的时候($mount),都会创建一个Watcher,用diff算法可以精确找到要更新的节点,更高效的执行patch。
2、diff算法执行的时候是创建和更新的时候,通常旧节点和新节点对比,这个过程我们称为patch,也是diff的核心
在这里插入图片描述
3、diff过程整体遵循 深度优先,同层对比的策略,两个节点之间比较会根据他们是否有子节点做不同的操作;比较两组节点是算法的重点。首先假设头尾几点可能匹配的4次对比,如果没有找到对应的节点,就会用遍历的方式比较,借助key通常可以非常精确的找到相同的节点,因此,整个patch过程非常高效。

v-if和v-for的优先级

v-for的优先级比v-if高,在源码中,v-for的判断语句在v-if前面,而在我们实际开发中也经常用到,在for循环中绑定if。

vue key的作用在这里插入图片描述

如图: 如果我们要在B和C之间添加F
不加key的操作是, F覆盖C ,C覆盖D ,D覆盖E,最好在新建E插入到末端。
加key, A B不变, 然后根据diff算法 E D C不变 , 最后新建F插入到BC之间
可见,加key可以准确定位要更新的数据,也可以更高效的刷新数据,减少vnode更新,提高性能, 也可以区分它们。

你对vue组件化的理解

什么是组件化
我们平常开发中,遇到一些相同功能或相似的页面频繁刷新,这些我们可以提取出来,单独开发和维护,这样的技术就是组件化

组件优点
复用性:一个功能有多个地方会用到,可以统一维护
优化性能:如果我们只有局部刷新,那么我们需要更新或替换局组件。
开发效率:一个页面可能有多个组件,可以多个人开发,互不影响
组件常用技术
Props,父子组件之间的通讯;这也是复用组件时,可以适用多个场景
自定义事件$emit , 也是常用于父子组件通讯
组件可以使用插槽,优化组件

vue的data为什么是个函数

因为我们每创建一个组件就会生成一个新的data对象,互不影响,如果不是函数是一个对象,那么返回来的data都指向一个data,这样会造成数据污染。

组件化和模块化

组价化: 在我们开发中,经常遇到一些重复代码或者功能提取出来合成一个组件,位于框架底层,组件主要的就是 可以复用
模块化: 在一个项目中,我们把一个功能或一个业务代码形成一个独立的模块(像登录功能,首页,展示页,支付功能),属于业务框架层,目的是降低模块耦合性

为什么要使用组件化和模块化那(优点)

1、开发和调试效率高: 随着功能越来越多,代码结构会越发复杂,要修改某一个小功能,可能要重新翻阅整个项目的代码,把所有相同的地方都修改一遍,重复劳动浪费时间和人力,效率低;使用组件化,每个相同的功能结构都要调用一个组件,只需要修改这个组件,即可全局修改
2、可维护性强: 便于后期代码查找和维护
3、避免阻断:模块化可以独立运行的,如果一个模块产生了bug,不会影响到其他模块的调用。
4、版本管理更容易: 如果由多人协作开发,可以避免代码覆盖的冲突。

Vue3的新特性

1 使用proxy实现数据响应式,完美支持数组和对象,组件初始化速度提高,节省内存开销
2 对TypeScript 更好的兼容,也说明在我们开发中也更好的检测代码,高效的开发

3 渲染更快,虚拟DOM重写, 优化slots的生成,静态内容提取,静态属性提升,也就是说,我们在编译静态节点时,会把这个节点变成常量,不会在改变,从而减少 patch时间

4 Composition API
提高代码质量的上线,也降低了下线
ref和reactive

5 生命周期
名称改动: beforeDestory => beforeUnmount
Destroyed => unmounted
然后在 setup函数里定义,前面需要加‘on’关键字

Vue nextTick的原理

首先我们了解一下 js的运算机制

事件队列(Event Loop):
所有同步任务都在主线程上执行,形成一个 执行栈,
主线程之外,还存在一个任务队列, 遇到异步任务,就在 任务队列后面放置一个事件,当执行栈执行完后,就会读取任务队列
任务队列里有 微任务和宏任务

微任务microtask
Promise, Object.observer, MutationObserver ,process.nextTick(node)

宏任务
setTimeout,setInterval, postMessage , MessageChannel 等

MutaionObserver 是H5中的API,是用于监听DOM变动的接口,它可以监听一个DOM对象上发生的节点删除,属性修改,文本内容修改等

nextTick 既然是在 DOM更新后执行的 函数,那么我们就需要在事件队列添加时间,因为微任务的优先级比较高,所以我们可以用微任务来处理,vue 之前用的是 MutationObserver,但是这个方法在ios里有bug(vue2.弃用),所以我们用promise

Vue 向下兼容方式
因为promise 是ES6语法,不兼容ie等浏览器,所以我们用的一个兜底方式,用的setTimeout

vue.use做了什么

vue.use主要是安装Vue.js插件,如果是插件是一个对象,必须提供install方法,如果插件是一个函数,那么它就会当做install方法调用。
该方法要在 new Vue()之前调用。
在源码中, 我们会定义一个 installedPlugins数组,用了储存已安装过额插件,安装插件前会先判断是否被安装过,避免重复安装,然后才会去判断是一个对象还是函授进行调用。

简单说下vue数据驱动

Object

创建Observer,先判断数据类型如果是Object类型,就会调用walk(Object.defineProperty),将每一个属性转换成 getter/setter 的形式来侦测变化,然后进行递归
然后我们创建Dep收集依赖,我们在getter总收集依赖,在setter中通知依赖更新,对依赖进行增删改查
依赖 Watcher,谁用到了数据,谁就是依赖,我们就在为谁创建Watcher实例,Watcher先把自己设置到全局唯一的指定位置window.target,然后读取数据,触发这个数据的getter,我们在getter中收集依赖调用dep.depend(),这个方法会取到window.terget上的值存入依赖数组中去,同时会释放window.terget,收集好后,当数据发生变化时会触发setter中的dep.notify(),这个方法会遍历所有依赖,执行updata更新视图

Array

创建Observer,因为我们在的数组也是写在data对象中的,那我们就可以和Object一样进行监听
收集依赖,也是在getter里面收集,通过observer()函数为被获取的数据arr创建一个Observer实例,然后创建new Observer将其转化为响应式,并将数据对应的Observer实例返回,然后在getter中调用Observer实例上的依赖管理器,收集依赖
监听array变化,以为数组setter方法,所以我们需要自己定义改变数据的方法,覆盖数组方法在原型上拦截,然后在调用dep.notify(),更新视图

--------服务端面试题

http和https的区别

首先我们了解下什么是http和https

超文本传输协议http协议会在web浏览器和服务器之间传递信息,http会以明文方式发送内容,不提供任何方式数据加密,如果攻击者劫持了web浏览器的网站之间的传输报文,就可以获取其中的信息。
为了解决http协议的问题,出现了https协议,https在http的基础上加入了ssl协议,ssl依靠证书来验证服务器身份,并为浏览器和服务器之间的通信加密。https协议主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全; 另一种就是确认网站的真实性。
主要区别有:

  1. https协议需要到AC申请证书,一般有免费的也有付钱的。
  2. http是明文传输,https有ssl加密,所有https更安全
  3. http和https的端口不一样,一个是80,一个是443
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值