JS进阶篇(前端面试题整合)(一)

本文最后更新于:9 个月前

js的垃圾回收机制是什么原理

垃圾回收机制有两种方法

  • 第一种是标记清除法:当变量进入执行环境时,就标记这个变量为”进入环境”,当变量离开环境的时候,则将其标记为”离开环境”,垃圾收集器在运行的时候会给储存在内存中的所有变量都加上标记,然后它会去掉环境中的标量以及被环境中的变量引用的标记,而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了,最后,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间
  • 第二种是引用计数法:当声明了一个变量并将一个引用类型赋值给改变量是,则这个值得引用次数就是1,相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值得引用次数就减1,当这个引用次数变成0时,则说明没有办法在访问这个值了,因而就可以将其所占的内存空间给收起来,这样垃圾收集器再下次运行时,它就会释放那些引用次数为0的值所占的内存

哪些操作会造成内存泄露,怎样避免内存泄露

会造成内存泄漏的操作:

  • 意外的全局变量引起的内存泄露
  • 闭包引起的内存泄露
  • 控制台日志
  • 没有清理的DOM元素引用
  • 被遗忘的定时器或者回调

避免内存泄露的操作:

  • 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收
  • 注意程序逻辑,避免“死循环”之类的
  • 避免创建过多的对象 原则:不用了的东西要及时归还(置为null)

AMD\CMD区别

  • AMD即Asynchronous Module Definition,翻译过来就是异步模块化定义(RequireJS)
  • CMD即 common moudle definition,翻译过来即通用模块定义(SeaJS)
  • RequireJS在主文件里是将所有的文件同时加载,然而SeaJS强调一个文件一个模块。
  • AMD推崇依赖前置,CMD推崇依赖就近。
  • AMD加载完模块后,就立马执行该模块;CMD加载完某个模块后没有立即执行而是等到遇到require语句的时再执行
  • 所以,他们两者的不同导致各自的优点是AMD用户体验好,因为模块提前执行了;CMD性能好,因为只有用户需要的时候才执行。

面向对象的三个特性

封装 : 屏蔽内部细节 用户直接调用被封装的功能
继承 : 子类拥有父类的所有属性或方法
多态 (js中不存在多态概念)

原型,原型链的理解

所有的构造函数都有一个prototype属性,这个属性也叫 原型对象 构造函数.prototype 所有的构造函数new出来的对象也都有一个原型对象 实现 :对象.__proto__
原型链就是实例对象和原型之间的链接
原型对象的执行流程:

  • 首先去实例上查找,如果找到了就返回
  • 如果没做查找到,就去改构造函数的原型上查找,如果找到了就返回,如果没找到,就去Object.prototype的原型上查找,找到了就返回,否则返回undefined

继承的方式

1.通过改变父类的执行环境来实现
2.通过call
3.通过apply
4.原型继承
5.混合继承
6.es6构造函数

作用域链的理解

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
安全隐患:污染全局环境,或者造成内存泄露的问题,变量的提升

闭包的理解

什么是闭包
一个函数内部返回一个匿名函数,这个函数就称为闭包
闭包中this指向 window
特点
(1)函数嵌套函数
(2)函数可以引用外层的参数和变量
(3)参数和变量不会被垃圾回收机制回收
闭包的缺点:常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
为何要使用闭包:为了设计私有方法和变量,避免全局变量污染 希望一个变量长期驻扎在内存中

下面这个ul,如何点击每一列的时候alert其index(闭包解决方式)

<ul id="test">
    <li>这是第一条</li>
    <li>这是第二条</li>
    <li>这是第三条</li>
</ul>

方法一:

//将i属性绑定到标签对象中的index
var liItems=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<liItems.length;i++)
{
    liItems[i].index=i;
    liItems[i].onclick=function(){
        alert(this.index);
    };
}

方法二:

//将i属性通过参数传递至function作用域中,立即执行函数在下一次循环之前先将i绑定至作用域
var liItems=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<liItems.length;i++)
{
     liItems[i].onclick=(function(a){
        return function() {
            alert(a);
        }
    })(i);

}

方法三(es6的let产生暂时性死区,与声明的变量所在的块级作用域(for循环内)都不会造成闭包,var只受function的作用域影响,let受所有带‘{}‘大括号的作用域影响):

//通过let
var liItems=document.getElementById('test').getElementsByTagName('li');
        for (let i = 0; i < liItems.length; i++) {
            liItems[i].onclick = function () {
                alert(i);
            }
        }

高内聚低耦合的理解

高内聚 :模块内部高内聚 。 一个系统有多个模块组成,在划分模块式,要把功能关系紧密的放到一个模块中,这就叫做高内聚低耦合:功能关系远的放到其它模块中。模块之间的联系越少越好,接口越简单越好,这叫做低耦合,也称为细线通信

TCP和UDP的最完整的区别

1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证

JS处理异步的方式

  • 利用回调函数(es5常用方法)
  • 用async和await来处理异步(es7-8中新增)
  • promise(es6新增)
  • 发布/订阅 我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式”(publish-subscribe pattern),又称”观察者模式”(observer pattern)(和事件原理一样)
  • 事件 触发一个事件也可以作为异步的处理 当触发某个事件再来执行某件事(js底层解决异步常用方法)

深拷贝浅拷贝的理解

浅拷贝:只是复制当前的对象,该对象内部的引用(Object,Array等堆内存数据)不能复制
深拷贝:对对象内部的引用均复制,是创建一个新的实例
简言之:是否复制了子对象,修改了克隆后的对象属性值,影响到原对象-浅拷贝 不影响-深拷贝

常见的HTTP请求返回状态码

  • 200成功
  • 304请求浏览器缓存的内容
  • 400语义有误,当前请求无法被服务器理解
  • 401当前请求需要用户验证
  • 404未找到
  • 403服务器已经理解请求,但是拒绝执行它
  • 500服务器错误
  • 503服务器端暂时无法处理请求

1开头的(信息类):表示接收到请求并且继续处理,用于指定客户端应相应的某些动作
2开头的(响应成功):表示动作被成功接收,理解和接受。
3开头的(重定向):为了完成指定的动作,必须接受进一步处理,用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息
4开头的(客户端错误类):请求包含错误语法或不能正确执行
5开头的(服务器端错误):服务器遇到错误,无法完成请求

html页面怎么解析的?它加载顺序是什么?

  1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件
  2. 浏览器开始载入html代码,如果发现标签内有一个标签引用外部CSS文件
  3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件
  4. 浏览器继续载入html中部分的代码,并且CSS文件已经加载完成了,开始渲染页面
  5. 如果浏览器在代码中发现一个标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是异步渲染后面的代码
  6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码
  7. 如果浏览器发现了一个包含一行Javascript代码的