简答题
请说出下列最终的执行结果,并解释为什么。
var a = [];
for(var i = 0;i<10;i++){
a[i] = function (){
console.log(i)
}
}
a[6]()
答:因为for循环中的 i 用var来声明会提升变量,并且循环体内的函数并不是每次循环都会执行,当所有循环结束时 i已经变成了10,所以无论a数组中的哪个元素,执行结果都是10。
解决方案:将var改为let声明方式 形成块级作用域
请说出下列最终的执行结果,并解释为什么
var tmp = 123;
if(true){
console.log(tmp)
let tmp
}
答:最终结果是报错 因为用let 声明了tmp,let声明形成块级作用域,在声明之前调用是会报错的,它不会受上层作用域同名变量的影响
结合ES6新语法,用最简单的方式找出数组中的最小值
var arr = [12,34,32,89,4]
答:console.log(Math.min(...arr))
请详细说明var,let,const三种声明变量的方式之间的具体差别
1.作用域:var的作用域是整个函数,但let和const是块级作用域
2.重复定义:var可以对关键词多次定义,而let和const不可以
3.变量提升:var声明变量会提升到运行顶部,而let和const不会 只能在作用域中使用 不能先使用后声明
4.更改:const声明的常量不能被更改 声明引用类型数据时 引用类型数据属性可以被更改 但是指向的内存地址不能被更改,而var和let可以
请说出下列代码最终输出的结果,并解释为什么
var a = 10
var obj = {
a:20,
fn(){
setTimeout(()=>{
console.log(this.a)
})
}
}
obj.fn()
答:20。 setTimeout中使用的箭头函数,箭头函数自己不会创建this,它只能继承自己作用域上一层的this,而指向的是obj对象
简述Symbol类型的用途
1.一种全新的原始数据类型 唯一的 避免属性名冲突
比如:一个对象要合并一个新的对象 但不知道其中是否有同名的情况
const obj = {}
obj[Symbol()] = '123'
obj[Symbol()] = '456'
console.log(obj) // {[Symbol()]:'123',[Symbol()]:'456'}
2.建立私有成员
const name = Symbol()
const person = {
[name]:'zce',
say(){
console.log(this[name])
}
}
// 外部没办法创建一个相同的Symbol
// person[Symbol()]
person.say() //只能调用这个普通对象的成员
3.改变toString()默认标签
const obj = {
[Symbol.toStringTag]:'XObject'
}
console.log(obj.toString()) // [object XObject]
4.获取Symbol 属性名
Object.getOwnPropertySymbols(obj) // 获取Symbol属性名
Object.keys(obj) 只能获取对象字符串属性名
说说什么是浅拷贝,什么是深拷贝
浅拷贝:所谓的浅拷贝就是拷贝指向对象的指针(拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间),
浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误
深拷贝:所谓的深拷贝指拷贝对象的具体内容,其内容地址是自助分配的,拷贝结束之后,内存中的值是完全相同的,但是内存地址是不一样的,两个对象之间相互不影响,也互不干涉.
请简述TypeScript与JavaScript之间的关系
JavaScript: 是一种可以运用到html网页上的脚本语言, 可通过浏览器进行解析执行,javascrip非常轻巧,目前市面的浏览器大部分都支持javascript语言。
JavaScript:无特定的运行环境,只要浏览器支持,就可以运行,是一种通过对象,事件触发其运行。
TypeScript:由Microsoft开发的面向对象语言,TypeScript是 JavaScript 的超集,包含了 JavaScript 的所有元素,在TypeScript中可以运行JavaScript代码。
请谈谈你所认为的TypeScript的优缺点
优点:
1.解决JavaScript类型系统的问题
2.错误更早的发现 在编码阶段
3.代码更加智能、准确
4.重构更加牢靠
5.减少不必要的类型判断
缺点:
1.语言本身多了很多概念
2.不能直接被浏览识别,需要通过编译工具编译为JS代码
3.项目初期,TypeScript会增加一些成本(适合长期大项目)
描述引用计数的工作原理和优缺点
核心思想:
1.设置引用数,判断当前引用数是否为0
2.引用计数器
3.引用关系改变时修改引用数字
4.引用数字为0时立即回收
优点:
1.发现垃圾时立即回收
2.最大限度减少程序暂停
缺点:
1.无法回收循环引用的对象
2.时间开销大
function init(){
const obj1 = {}
const obj2 = {}
obj1.name = obj2
obj2.name = obj1
}
init()
描述标记整理算法的工作流程
答:分为三个阶段,标记、清除、整理。在标记阶段,collector从mutator根对象开始进行遍历,对从mutator根对象可以访问到的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象。而在清除阶段,collector对堆内存(heap memory)从头到尾进行线性的遍历,如果发现某个对象没有标记为可达对象-通过读取对象的header信息,则将对象的地址进行移动,使其在地址上连续,然后再回收。
描述V8新生代存储区垃圾回收的流程
1.V8内存分配
(1)V8内存空间一分为二
(2)小空间用于存储新生代对象(32M|16M)
(3)新生代指的是存活时间较短的对象
2.新生代对象回收实现
(1)回收过程采用复制算法+标记整理
(2)新生代内存区分为两个等大小空间
(3)使用空间为From,空闲空间为To
(4)活动对象存储于From空间
(5)标记整理后将活动对象拷贝至To
(6)From与To交换空间完成释放
3.回收细节说明
(1)拷贝过程中可能出现晋升
(2)晋升就是将新生代对象移至老生代
(3)一轮GC还存活的新生代需要晋升
(4)To空间的使用率超过25%
描述增量标记算法在何时使用及工作原理
1.JS程序执行过程中,会伴随着垃圾回收的工作。
2.当垃圾回收工作时,需要遍历对象进行标记,此时不需要将所有对象进行标记,可以先将直接可达的对象进行标记,标记完成后暂停标记
3.然后让JS程序执行一会,再让GC机制去做二步标记,将间接可达的对象进行标记,标记完成后暂停标记。
4.重复以上两不操作,让程序执行和垃圾回收的标记操作交替执行,来达到优化效率和提升用户体验的目的。
5.直到标记全部完成后,执行垃圾回收
优点:让垃圾回收与程序执行可以交替完成,让时间消耗更合理,达到效率优化的好处。