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.实现