文章内容输出来源:拉勾教育大前端高薪训练营
1、下列代码执行结果,并解释原因。
var a = [];
for (var index = 0; index < 10; index++) {
a[index] = function(){
console.log(index);
}
}
a[6]()
输出10
这里使用var声明的变量会提升至全局执行上下文中,当循序结束时,index的值为10.
这个问题解决有两种方式:
- 通过闭包
- var 改成 let
2、下列代码执行结果,并解释原因。
var tmp = 123;
if(true){
console.log(tmp);
let tmp;
}
会报错 tmp undefined
在if的块级作用域中,log语句输出是tmp并未声明,let不存在变量提升。虽然if语句块外面有声明tmp,但语句块内部的声明优先级较高。
这里解决报错的两种方式:
- if语句块内不声明tmp变量
- if语句块内声明tmp变量的语句放在log语句之前
3、使用es6新语法,用最简单的方式找出数组中的最小值、
var arr = [12,34,32,89,4]
实现
var arr = [12,34,32,89,4]
console.log(Math.min(...arr));
4、详细说明let、const、var三种变量声明方式的区别
var声明变量存在变量提升、重复声明、变量污染的问题。
let、const声明引入块级作用域的概念,解决变量提升、重复声明、变量污染的问题。
let声明会有临时性死区问题的存在。
let声明之后不允许再次声明,可以更改。
const声明之后不允许更改,一般用来声明常量。这个不允许更改不是绝对的,当使用const声明的是对象类型(数组、函数、对象)时,是可以更改对象属性的,但是不允许更改对象引用。这是因为对象在JS内存中存在堆中的。栈中保存的是对象的引用,因此只要引用不变,对象的属性和方式是可以更改的。
5、下列代码执行结果,并解释原因。
var a = 10;
var obj = {
a:20,
fn(){
setTimeout(()=>{
console.log(this.a);
},0)
}
}
obj.fn();
输出20
首先通过obj调用fn函数,在fn函数内部this的指向是obj。
而setTimeout中的箭头函数是没有this的指向的,里面的this依赖于上层作用域中的this,即obj。
所以这里的this.a === obj.a
6、简述Symbol类型的用途
用来声明变量属性的唯一性,实现私有属性的作用。
7、什么是浅拷贝?什么是深拷贝?
- 浅拷贝:复制对象的引用,不复制对象本身。当其中一个对象属性更改时,另一个也会改变。
- 浅拷贝实现
- 引用赋值
- 深拷贝:复制对象本身。当其中一个对象属性更改时,另一个不会改变。
- 深拷贝实现
- object.assgin()
- JSON.parse(JSON.stringify())
- 自定义 递归的方式
8、简述TS和JS之间的关系
JS是弱类型语言,变量的声明可以随意更改。TS是JS的超集,是对JS的增强。
9、TS的优缺点
- 优点
- 增加代码可维护性
- 兼容JS语法
- 减少不必要的类型的判断
- 缺点
- 增加学习成本
- 开发成本
- 与一些库可能不兼容
10、引用计数的工作原理和优缺点。
通过一个变量来对引用的变量进行计数,初始值为0,每次引用时增加1,断开引用时减1,当引用计数为0时回收变量。
- 优点
- 发现垃圾时立即回收
- 最大限度减少程序暂停
- 缺点
- 空间的浪费(增加引用计数的变量)
- 时间开销大
- 无法回收循环引用的对象
11、简述标记整理算法的工作流程
首先遍历所有对象,将不可达对象进行标记。
然后在清除阶段将所有标记为不可达的对象空间进行回收,将所有可达对象进行整理,把可达对象放到连续的内存空间。
12、描述V8中新生代存储区的垃圾回收流程。
V8将新生代中的空间一分为二。使用的空间为From,空闲的空间为To。
活动对象存在From空间中,标记整理后将活动对象拷贝到To,From和To交换空间完成释放。
拷贝中会出现晋升(一轮GC还存活的对象)
13、描述增量标记算法在何时使用及工作原理。
GC的执行需要暂停程序的执行。增量标记算法是一步一步完成,在程序中穿插完成,最大限度减少程序暂停时间。
递归所有对象,将每个对象进行标记,标记完后执行清除。
答案仅供参考,如果错误,欢迎指正。