嗯,上次写blog已经是几周前的事情了,其实已经积攒了很多小问题需要记录和分享了。但是在8月底,VK我一次经历了了携程、拼多多、腾讯、网易等多轮面试轰炸,忙得不可开交,有喜有忧的同时,还是赶快记录了不足,把一些充满迷惑性的问题继续记录和学习。
JavaScript总是给人以惊喜,学习不止,进步不断,今天继续补充JS容易搞错的几道笔试/面试题,为了秋招继续努力,欢迎一起为秋招努力的小伙伴共勉
系列笔记:
面试&常识题
Q1. forEach 与 map的区别? forEach不支持中断循环?
这是一道巨坑的题目
先看下很多博客、文章总结的一个关于循环的区别是怎么说的
- map可以做链式操作、forEach不可以
- map有返回值,return、 forEach没有返回值
- for循环不用担心兼容性问题,可以break跳出循环,是基础循环
- forEach不支持continue和break,是不能退出循环本身的。
上面这些比较,本身没有什么问题,但是当第三点和第四点结合的时候,就很容易让人有个推论:
map是可以跳出循环的,可以提前中断
然而,也的确有些面试官,认为forEach不能break,map是可以的跳出的
。 真的是这样的?
首先,众所周知,forEach
是不能用break提前中断循环的,如果使用了,会直接报错。比如以下:
1 | var list = [1,2,3,4]; |
但是,如果真的想要中止? 因为会报错,这也提供给我们一个思路,那就是用try..catch
把它保住,捕获错误。 但是,个人认为真是多此一举,应该没人会这么用。就不多做讨论了。
那么map
可以用break吗?
很显然,它也不行。所以如果有面试官问你,甚至告诉你”forEach和map的不同,forEach不可以中止”时,你真的可以大胆回击:
- 想要用
Array.prototype.map
实现break,也是完全不可能的 - map中文翻译为映射,所谓映射,当然是把数组中每个值进行映射处理,有何理由中断循环,特殊处理?
Q2. 对象与继承
请问以下程序中,person1
和person2
哪个是Person的实例?其__proto__
分别指向谁?
1 | function Person(name) { |
Ans
1 | person1和person2都不是Person的实例 |
这题题目的关键就是理解new
的过程,这也是常见的面试题之一了。如果遇到关键字new
,那么,函数就不单单是一个函数了:
- 函数执行,首先隐式建立对象
this
- 执行,绑定this相关的属性,本例中
this.name = name
- 函数最后,隐式的return
this
当然,这里简化了这个过程,但是核心是这几步。 但是如果在隐式返回this
之前,提前返回了一个对象,那么就会退出函数了。 要知道,只有这个this
才是实例本身,它的__proto__
才指向构造函数,如果不能把this
返回出去,那么一切都是徒劳的。因此,这里无论是否new
,都返回的是一个新对象{}
。
Q3. 垃圾回收机制方式及内存管理(爱奇艺2018提前批二面)
这里,自己当时回答的不好,就引用别人博客整理的内容啦.
回收机制方式
定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。
原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
实例如下:
1 | function fn1() { |
fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。
- 垃圾回收策略:标记清除(较为常用)和引用计数。
标记清除:
定义和用法:当变量进入环境时,将变量标记”进入环境”,当变量离开环境时,标记为:”离开环境”。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
引用计数:
定义和用法:引用计数是跟踪记录每个值被引用的次数。
基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。
内存管理
- 什么时候触发垃圾回收?
垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。
IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。
IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。
- 合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。
- GC缺陷:(1)、停止响应其他操作;
- GC优化策略:(1)、分代回收(Generation GC);(2)、增量GC
说实话,这一块,自己没有很好的整理,但是目前准备秋招和毕设,没有更多的经历,只能待有空再深入学习研究了。
编程题
Q1. 表格排序
请将以下表格,按年龄进行排序,使用原生JS,不允许使用任何第三方工具。
1 | <table> |
Ans:
这个其实很easy了,只是我在写的时候,还是调试了好几次,这里主要两点:
- 通过
document.getElementsBytagNames
选择的对象,在dom的映射机制下,是双双绑定的; - 使用
dom.appendChild()
方法,要保证参数是node节点。 Array.sort()
方法,注意,只能用在Array上。
1 | var sortByAge = function () { |
Q2.时间’0101’转换为正常时间值(杭州有赞2018秋招二面在线编程)
一天24小时,我们将其折为每30分钟为一段,这样一天共有48段。我们用1表示这段时间有效,0表示无效,比如10...
表示开始时间为00:00
持续了半个小时,技术时间为00:30
。111001..
则表示00:00~01:30
02:30~03:00
两个时间段。
要求写一个函数,对时间码进行转换:
输入:110100000000000000000000000000000000000000000000
输出: ["00:30~01:30", "01:00~02:00"]
Ans
这个是我视频面试时的一道编程题,由于时间紧,面对面试官有点小压力,所以就用了比较笨的方法实现了,后来也没有重新思考和优化,有好的思路和简单的方法的小伙伴欢迎交流。
以下思路:
- 遍历输入字符串
- 当为1,判断是否为第一次,如果是第一次,根据index,记录
startTime
;如果不是第一次,进行time
累加 - 当为0,判断之前是否为1,如果之前是1,则根据
time
值进行累加,计算endTime
,并将时间段push到数组 - 判断是否为第一次、判断之前是否为1,主要通过一个flag进行记录。
根据上面思路,代码如下:
1 | function timeTransfer(str) { |
以上程序,是跑通了的,虽然有点笨,但是勉强满足要求。