本文会用各种刁钻的角度来问问题,不考虑实际价值与这样写对不对,只作为考察(我自己)是否吃透(或者是还记得)高程三,防止各种坑爹面试题。(小部分补充不属于高程三)
问题
1. 请问以下语句浏览器会输出什么?
setTimeout(() => {
console.log(2)
},1000)
for(;;){
console.log(1)
}
2. 请问如何不使用多个break跳出多层循环?
3. 如何延长作用域链?
4. 这段代码哪里错了?
switch (1 + 2) {
case '2':
case '3':
alert('3');
break;
default:
alert('5');
}
5. 这段代码哪里错了?
"use strict"
function eval(arguments,arguments) {
arguments = 10
return arguments;
}
6. 对象的属性名可以带空格吗?
7. const a = Array.of(5)、var b = Array(5)和var c = Array('5')有什么区别?*
8. 请问这个数组的长度[,,,,,] *
9. 假设有一个数组arr,如何清空这个数组呢?
10. 请问以下代码运行完后,ddd除了push()和splice()都有哪些key,value?
var ddd = {
2: 'a',
3: 'b',
length:2,
push: Array.prototype.push,
splice: Array.prototype.splice
}
ddd.push(1, 2)
11. 请问以下代码返回结果 *
var eee = ['a']
console.log(eee.push('b', 'c'), eee.pop(),eee.unshift('d', 'e'), eee.shift(), eee.splice(0))
12. 请问以下代码输出什么?
var arr1 = [3,1,4,15,9]
var arr2 = arr1.sort()
var arr3 = arr2.reverse()
console.log(arr1, arr2, arr3)
13. 哪些数组方法会影响原始数组?
14. indexOf()和lastIndexOf()有什么异同?
15. 以下代码返回结果是啥?*
var strList = ['Tom', 'Jerry']
var obj = { action: 'eat'}
var res1 = strList.map(function(item, index, arr){
return `${item} ${this.action} ${index + 2} 'cookies'`
}, obj)
var res2 = res1.every(item => item.indexOf('cookies') !== -1)
var res3 = res1.some(item => item.indexOf('Tom') === -1)
var res4 = res1.forEach(item => item + 1)
console.log([res1, res2, res3, res4])
16. 以下代码返回结果是啥?*
var value = [1,2,3,4,5];
var sum = value.reduceRight(function(prev, cur, index, array){
return prev + cur
},10);
console.log(sum);
17. 这三个时间是否相同?*
var time1 = new Date('2020-05')
var time2 = new Date(2020, 5)
var time3 = new Date(Date.UTC(2020, 5))
console.log(time1, time2, time3)
18. 如何获取当前的时间戳?
19. 正则表达式的.能匹配所有字符吗?
20. 请问这两个pattern一样吗?
var pattern1 = /\[bc\]at/i
var pattern2 = new RegExp("\[bc\]at", "i")
答案
1. 会无限输出1,并卡死。原理:for语句中的初始化表达式、控制表达式和循环后表达式都是可选的。将这三个表达式全部省略,就会创建一个无限循环。(高程三第57页)
使用while循环做不到的,使用for循环同样也做不到。也就是说。for循环只是把与循环有关的代码集中在了一个位置。(高程三第56页)// 但是在ES6中使用let的话for循环会创建一个作用域用于管理i的值,而while则不行。
浏览器会先执行完同步代码,再执行异步代码,具体可以看这个链接的描述。
关于async/await: async 是一个可以暂停和恢复执行的函数,我们会在 async 函数内部使用 await 来暂停 async 函数的执行,await 等待的是一个 Promise 对象,如果 Promise 的状态变成 resolve 或者 reject,那么 async 函数会恢复执行。
2. 两种方法
1.用函数包裹,使用return即可。2.使用label语句。使用label语句可以在代码中添加标签,可以在将来由break或continue语句引用。加标签的语句一般都要与for语句等循环语句配合使用。(高程三58页)例子如下:(高程三59页)
var num= 0;
outermost:for (var i=0; i < 10; i++) {
for (var j=0; j < 10; j++) {
if (i == 5 && j == 5) {
break outermost;
//换成continue outermost;结果是95
}
num++;
}
}
alert(num); //55
3. 使用with语句。//用多了会导致性能下降,不建议用。(高程三60页)
或使用try/catch语句的catch块(高程三75页)
这两个语句都会在作用域链的前端添加一个变量对象。对于with语句来说,会将指定的对象添加到作用域链中。对catch语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。(高程三75页)
4. 判断条件不应该是字符串,switch语句在比较值时使用的是全等操作符。(高程三62页)
5. 严格模式对函数有一些限制:
- 不能把函数或参数命名为eval或arguments
- 形参不能重复(高程三64页)
- 重写arguments的值会导致语法错误(代码将不会执行)(高程三66页)
6. 可以。原理: 如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或者保留字,也可以使用方括号表示法。例如:
var person = {};
var person = {
"first name": "Jack"
}
person["second name"] = "Rose";
console.log(person["first name"]);// Jack
console.log(person["second name"]);// Rose
(高程三85页)
7. [5],[,,,,],['5']。 Array.of(params)会将参数作为列表元素生成一个新数组,而new Array(params)则是看情况(new可省略),如果参数是一个数字,那么生成长度为该数字的数组,所有元素都是undefined。否则将参数作为列表元素生成一个新数组。
8. 5或6。原理: 原因是IE8及之前版本中的ECMAScript实现在数组字面量方面存在bug。(高程三86页)所以会比其他浏览器多一项undefined。
9. arr = []。这样可以彻底清空。用arr.splice(0)或者arr.length = 0都只是清除数字下标的元素而已,如果通过arr['red']=1这样的语句设置了字符串下标的元素的话(这样相当于把arr当成对象),用这两种方式是清除不掉的。
10. 2: 1,3: 2,length: 4。因为push(a,b,c...)的机制是ddd[length] = a,然后length+= 1,然后b,c同样处理,因为一开始length为2,所以ddd[2]和ddd[3]都被覆盖了,而length则变成了4。
11. 3 c 4 d ["e", "a", "b"]。push和unshift都会返回插入后的数组长度,pop和shift则会返回被移除的项,
splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组)。(高程三95页)
12. Array(5) [ 9, 4, 3, 15, 1 ] Array(5) [ 9, 4, 3, 15, 1 ] Array(5) [ 9, 4, 3, 15, 1 ]。reverse()和sort()方法会返回排完序的数组,而排序的方法是先将数组每项都转化为字符串,再根据ASCII表来升序排序。
如果要对数字数组进行升序排序,像这样加入一个回调函数即可arr1.sort((a,b) => a - b)。降序则是将回调函数改成(a,b) => b - a。
13. push,pop,unshift,shift,reverse,splice,sort。
14. 相同点: 两者都用于查找,都用全等运算符判断是否与第一个参数一样,第二个参数都决定起始的位置。不同点: indexOf是从0向后找,lastIndexOf是从最后一位向前找。
[
[ "Tom eat 2 cookies", "Jerry eat 3 cookies" ],
true,
true,
undefined
]
除了forEach,其他迭代方法(map, some, every, filter)都有返回值,且这5种方法都不会修改数组中的包含的值。每个方法接收两个参数,第二个参数是(可选的)运行该函数的作用域对象——影响this的值。(高程三96页)。
16. 25。第二个参数是作为归并基础的初始值。reduce和reduceRight方向相反,其他都一样。
17. 各不相同。第一个是UTC的2020年5月1日0点,第二个是本地时间的2020年6月1日0点,第三个是UTC时间的2020年6月1日0点。
原理:使用new Date()的时候,根据传入参数会触发不同效果:
- 不传参数会返回调用时的时间戳。
- 传入一个字符串如果是合法日期的话,会后台调用Date.parse()将其转换为构造函数能接受的时间戳。(至于怎样合法,一般是因地区而异)
- 如果是非法日期,由于ECMAScript也没说咋整,所以不同浏览器的处理方式不同。
- 传入2个以上数字的话,构造函数会模仿Date.UTC,但是返回的不是UTC时间而是本地时间。(年月是必须的,日默认1,其他默认0,月份小时星期从0开始)
(高程三98页)
18. +new Date()或者Date.now()都可获取。(高程三100页)
19. 不能,换行符和不属于BMP的字符就不行。用[\s\S]则可以匹配属于BMP的包括换行符的所有字符。
20. 不一样,后者等价于/[bc]at/i。给RegExp构造函数的两个参数都是字符串,所有元字符都必须进行双重转义。(高程三104页)(也就是本来写一个\的,现在要写两个。)