面试题整理——JavaScript

228 阅读7分钟

1.闭包

其实就是一个高阶函数,在一个函数中返回一个函数,

直接回答:

      1.概念:每当创建一个函数,闭包就会创建出来,它是连接函数内部和外部的桥梁。

闭包可以让我们在函数内部访问函数外部的变量和内容

     2.使用场景:

        延长变量的使用生命周期。

        原因:一般函数的词法环境会在函数在返回时会销毁,但是闭包会保存创建时所在词法环境的引用,及时所在环境的执行上下文被销毁,但是对创建时所在环境的词法环境的引用依然保留,所以延长了所在词法环境的生命周期。

       创建私有变量

    3.内存泄漏

      内存泄漏的原因是垃圾回收策略造成的。

2.执行上下文和执行栈

    outer指向的是词法环境

      变量在初始化之前,是不能访问的,

      只要有代码执行,就会产生执行上下文

      2.2生命周期

          创建-》执行-》回收

3.类的创建和继承

      继承的都是实例

6种继承方式

1.原型链继承

        优点:理解简单

        缺点:用了同一个原型对象,内存空间是共享的

2.构造函数继承

       优点:用的不是同一个原型对象,父类内存空间不会共享

      缺点:不能共享父类原型链上的属性和方法

3.组合式继承

      优点:解决了1和2的问题

      缺点:父类函数执行了两次

4.原型式继承

     原型式继承和原型链继承的本质

    都是让新对象的__proto__指向一个实例

   缺点:原型指向的都是同一个实例

5.寄生式继承

   寄生式继承,就是把原型式继承方法,进行了封装而已,然后添加一些方法

     对参数对象的一种浅复制

     原型式继承和寄生式继承都是对目标对象实现的一种浅复制。增强浅复制的能力

6.寄生组合式继承

用call继承实例属性和方法,用object.create继承原型属性和方法

4.异步编程回调地狱的解决方法

promise generate asycn await

5.generate

generate对象返回的就是一个遍历器对象

1.使用next遍历结果

2.next()可以带参数,这个参数会被当做上一个yeild的值

3.promise:代码变得冗余了,语义化并不强。

4.generator并不是为了异步而设计出来的,它还可以部署遍历器接口

5.aync是generator的语法糖,会自动执行generator函数

6.说说前端中的事件流

事件流描述的是页面元素接收事件的顺序;

捕获阶段、目标阶段、冒泡阶段

7、三种事件模型

原始事件模型

标准数据模型

IE事件模型

8.事件委托

大批量和动态添加

9.图片的懒加载和预加载

10.mouseover 和 mouseenter 的区别

mounseover:会冒泡 :存在子元素时,会有重复触发的过程。

mounseenter:不会冒泡

11.JS 的各种位置,比如 clientHeight,scrollHeight,offsetHeight ,以及 scrollTop, offsetTop,clientTop 的区别?

offsettop:距离最近的父元素和子元素border之间的距离。

client和offset的区别,是否包含border和滚动条

12.JS 拖拽功能的实现

    mouseup。mousemove,mousedown

13.异步加载js方法

14.垃圾回收

       什么是垃圾回收,为什么需要垃圾级回收

回收的是变量占据的内存

            代码运行需要变量内存,运行过程中产生的变量存储都需要内存空间。但是内存是有限的,所以需要释放代码运行不需要的变量占据的空间

          变量存储,占据内存 

因为字符串、数组、对象的大小不固定,只有知道了大小,才能动态分配存储。JavaScript每次创建新的数组,对象,解释器都要分配空间。但是空间有限,所以要释放掉不需要的对象占据的空间

    ** 垃圾回收的方式**

有一个垃圾回收器,会定时运行一次

标记清除

概念

垃圾回收器在运行的时候,首先会标记所有在内存中的变量,然后去除那些带在上下文中的变量,以及上下文中变量引用的变量的标记。最后垃圾回收器做一次清理,销毁带标记的变量和他们所占用的内存

优缺点

哪些浏览器在使用

引用计数

系统中会维护一张引用表,记录每一个值【不是变量】的引用次数,在算法运行的时候,如果值的引用次数是0,就会回收。内存泄漏就是因为。引用数不是0,但是不再用到了。

        一个变量不想用了,就标记为null。

用引用计数法会存在内存泄露,

常见的内存泄漏的情况

1.意外的全局变量

function foo(arg) {    bar = "this is a hidden global variable";}
function foo(arg) {    bar = "this is a hidden global variable";}

   2.闭包

  3.没有清除对dom的引用

   4.监听addevetLister的时候,没有取消监听

15.eval 是做什么的

eval就是将字符串解析成js代码执行,应该避免使用,因为耗能,一次解析,一次执行

16.如何理解前端模块化 AMD,CMD,以及CommonJS

为什么会有前端模块化

最开始就是一个script标签,直接引入,存在的问题,最大的问题,就是变量和多人开发

1.变量污染,不同的文件,可能出现命名相同的同级变量,但是成员不知道

2.维护困难,

3.封装,抽象和复用复杂

前端模块化的方法 

es6 module  :

            i mport和 export  :导出的变量只读,不允许修改

          默认严格模式

             在接口名与模块内部变量之间,建立了一一对应的关系。

            可以动态更新

动态import()

AMD  require()

commnJS

区别

es6很大的特点,就是静态加载

require 是在运行的时候加载,只能在运行的时候,确认模块的依赖关系,以及输入输出的变量;但是import是尽量的静态化,在编译时就能确定模块的依赖关系,以及输入输出的变量

因为commonjs就是对象,输入时必须通过对象查找,而import是通过export

require是全部加载,而import是按需加载

require返回的是拷贝,所以可以改,但是import不能改

require首次执行后会缓存结果,想要再次执行,要清理缓存

es6的好处:服务器和浏览器都支持

浏览器的api可以通过魔窟提供,不再必须做成全局变量或者navigation的属性

不再需要对象作为命名空间

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是的只读引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

defer和async

defer:渲染完再执行

async:下载完就执行

浏览器对于带有type="module"<script>,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>标签的defer属性。

一旦使用了async属性,<script type="module">就不会按照在页面出现的顺序执行,而是只要该模块加载完成,就执行该模块。

  • 模块之中,顶层的this关键字返回undefined,而不是指向window。也就是说,在模块顶层使用this关键字,是无意义的。

最后,export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。

17.对象深度克隆的简单实现

1.不同类型的复制

2.如何判断不同的类型

Object.p

3.考虑相互引用,就是用map

18.常见正则表达式的匹配意义

匹配单个数字:\d,

匹配单个字母:\w, 【a-zA-Z0-9】

匹配

19.用promise封装ajax

xmlhttpreust()

onreadystatechange

readyState

19.setTimeout、setInterval 和 requestAnimationFrame 之间的区别

20.实现