前端基础知识问答

简答题

一、请说出下列最终的执行结果,并解释为什么?

 var a = []
 for(var i = 0; i < 10; i++) {
      a[i] = function() {
          console.log(i)
      }
  }
  a[6]() // 打印结果: 10

答案: 此题用var 定义变量 i 相当于
 var a = []
 var i;
 for(i = 0; i < 10; i++) {
     a[i] = function() {
         console.log(i)
     }
 }
 a[6]()
由于此时的 i 是全局变量,当循环运行完成时 i 已经变成了10,那么在windows 下打印 i 就会是10;
如果此题变成
var a = []
for(let i = 0; i < 10; i++) {
     a[i] = function() {
         console.log(i)
     }
 }
a[6]() // 打印结果: 6

二、请说出下列最终的执行结果

var tmp = 123;
if (true) {
  	console.log(tmp)
  	let tmp;
}
// Uncaught ReferenceError: tmp is not defined

答案:此时打印会报错 tmp is not defined, 因为 let 不会让变量提升,只能先定义在使用,而且 let 定义的变量会形成一个局部作用域,外面也是拿不到的

三、 结合ES6新语法,用最简单的方式找出数组中的最小值

    // var arr = [12,34,32,89,4]
    // console.log(Math.min(...arr))

四、请详细说明 var、 let 、const、三种声明变量的方式之间具体差别

答案:

  • var 全局声明变量,存在声明提升;
  • let 可全局声明变量,也可局部声明变量,不存在声明提升;
  • const 常量声明,不存在声明提升,并且定义后不可改变(严格来说:基本数据类型不可以改变值,引用数据类型仅可改变其类型)
varletconst
语法var a = 10let a = 10const a = 10
提升声明提升, 使用undefined初始化声明不提升声明不提升
作用域全局作用域块级作用域块级作用域
初始化可以仅声明不初始化可以仅声明不初始化必须在声明时初始化
重复声明可以不可以不可以
多次赋值可以可以基本数据类型不可以,引用数据类型尽可改变其值
声明前访问可以不可以不可以

五、请说出下列代码最终输出的结果,并解释为什么?

 var a= 10;
 var obj = {
     a: 20,
     fn () {
         setTimeout(() => {
             console.log(this.a);
         })
     }
 }
 obj.fn() // 20

答案: 控制台打印20,原因: 谁调用 this 就指向谁

六、 简述 symbol 类型的用途

答案: symbol 是一种全新的基本数据类型。定义方法 :直接使用 Symbol() 创建新的symbol类型,并可以用一个可选的字符串作为其描述。
const sym1 = symbol()
const sym2 = symbol()
每个从 Symbol() 返回的 symbol 值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。
借助symbol值是唯一的,我们还可以给对象创建似有成员

```javascript
const name = Symbol()
const person = {
	[name]: '张三',
	say(){
		console.log(this[name])
	}
}
// let naMe = person[Symbol()] //undefined
person.say()//张三
由于不能直接调用对象中的symbol属性,所以创建了所谓的私有成员。
总体来说,目前symbol的主要作用就是为对象添加独一无二的属性标识符;

七、 说说什么是浅拷贝,什么是深拷贝?

答案:

  • 浅拷贝: 是对内存地址的复制,如果是引用类型,则是让目标对象的指针和源对象指向同一个内存空间,也可以理解为拷贝的是指针。

结合下面代码理解:

// 浅拷贝
let a = {name: 'zhangsan'}
let b = a
 console.log('b',b); // b {name: "zhangsan"}
 delete b.name
 console.log(b,b.name); //{} undefined
 console.log(a,a.name); //{} undefined
  • 深拷贝: 是拷贝对象的具体内容或者为拷贝的是内存地址。拷贝结束完成后,两个对象虽然值是一样的,但是两者互不影响。

结合下面代码理解:

var a = {name: 'zhangsan'}
var b = JSON.parse(JSON.stringify(a))
console.log(b,b.name); // {name: "zhangsan"} "zhangsan"
delete a.name
console.log(b,b.name); // {name: "zhangsan"} "zhangsan"
console.log(a,a.name); // {} undefined
//深拷贝的另一种方法
var a = {name: 'zhangsan'}
var b = Object.assign({},a)
console.log('b',b); //b {name: "zhangsan"}
b.name = 'lisi'
console.log(a,a.name); //{name: "zhangsan"} "zhangsan"
console.log(b,b.name); //{name: "lisi"} "lisi"

由此可见,对于引用类型而言,浅拷贝只是拷贝了“指针”,而深拷贝则是开辟了另一块内存空间。

八、 请简述 Typescript 与 Javascript 之间的关系。

答案:有人说TypeScript 是JavaScript 的一个超集,这种说法也不为过。因为Typescript可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。

九、 请谈谈你所认为的Typescript 优缺点。

TypeScript 优点

  • 增强代码的可读性和可维护性,强类型的系统相当于最好的文档,在编译时即可发现大部分的错误,增强编辑器的功能。
  • 包容性,js文件可以直接改成 ts 文件,不定义类型可自动推论类型,可以定义几乎一切类型,ts 编译报错时也可以生成 js 文件,兼容第三方库,即使不是用ts编写的
  • 有活跃的社区,大多数的第三方库都可提供给 ts 的类型定义文件,完全支持 es6 规范

Typescript 缺点

  • 增加学习成本,需要理解接口(Interfaces)和泛型(Generics),类(class),枚举类型(Enums)
  • 短期项目增加开发成本,增加类型定义,但减少后期维护成本
  • ts 集成到构建流程需要一定的工作量
  • 目前和有些库结合时不是很完美

十、描述引用计数的工作原理和优缺点

引用计数算法核心思想: 设置引用数,判断当前引用数是否为0
当引用关系改变时修改引用数字,当引用数字为0时空间立即被回收

引用计数的优点:

  • 发现垃圾时立即回收
    只要发现被引用计数为0时立即回收内存

  • 最大限度减少程序暂停
    只要程序在运行时就要去消耗内存,而引用计数算法,只要发现某一块内存的引用数为0时就会立即回收,这样大大降低了内存爆满现象,从而减少程序卡顿暂停的说法。

引用计数的缺点:

  • 无法回收循环引用的对象

十一、 描述标记整理算法的工作流程

标记整理算法核心思想:分标记、整理和清除三个阶段完成

  • 遍历所有对象找到并标记活动(可达)对象
  • 遍历所有对象,将活动对象整理为连续内存,再将无标记对象(即将被清除的对象整理为连续内存)整理到一起,成为连续内存。
  • 清除无标记对象

配合图例理解

回收前
标记整理后
回收后

十二、描述V8中新生代存储区垃圾回收的流程

首先结合图例看一下 V8中内存的分配
V8内存分配示例
其实 V8将内存一分为二,左侧白色区域为新生代存储区,右侧红色区域为老生代存储区;
新生代存储区用于存储新生代对象,新生代对象指的是存活时间较短的对象(局部作用域下的变量对象)。新生代存储区大小一般为32M【64位系统】 | 16M【32位系统】。
了解完什么是新生代对象,我们就说一下新生代对象回收是如何实现的

  • 回收过程采用复制算法 + 标记整理算法
  • 新生代内存区分为两个等大小空间
  • 使用空间为From, 空闲空间为To
  • 活动对象存储于From 空间
  • 标记整理后将活动对象拷贝至To
  • From 与 To 交换空间 完成释放
    总的来说,新生代对象空间也是一分为二的,新生代对象回收过程采用复制算法 + 标记整理算法,当活动区(From)标记整理完成之后将活动对象复制到 To 空间,之后完全释放From 空间,再将From 与 To 空间交换,原来的From变成To,原来的To变成From ,完成空间释放和回收操作。

十三、 描述增量标记算法在何时使用及工作原理

标记增量,就是把一整段的垃圾回收操作,拆分成多个小步,整合着完成垃圾回收,从而去替代一口气做完的垃圾回收操作。这样的好处主要就是垃圾回收和程序执行是交替着进行工作,这样时间消耗更合理一些。
可参照图例
在这里插入图片描述

当程序执行到一个阶段,由于是在老生代区域操作会由循环遍历对象进行标记,然后程序会继续执行,接着再进行标记,直到程序把垃圾对象都标记完,然后进行清除,当然这不是一次标记完成的。
当老生代区域内存达到1.5G 时V8就会触发最大的垃圾回收即非增量垃圾回收,时间也不会超过1s 钟,所以看似程序停顿很多次,其实不影响用户使用感官的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值