需求已改活已加,加班通宵看朝霞。 终是上线已延期,bug仍是改不完。javascript
面试造火箭,工做拧螺丝,虽然我只想拧螺丝,但是我须要用造火箭的技术去寻找拧螺丝的工做,如何能在面试过程当中让本身处于不败的地步呢,刷题是一个比较好的捷径,今天就汇总了一些比较经典的面试题进行了汇总,分享给你们。前端
本文中的全部题目首发于公众号【前端有的玩】,小编天天都会整理一道两道面试题,而后推送给全部的朋友,关注小编,天天带你去刷面试题,不想当咸鱼,想要换工做,还在犹豫什么,关注 === 大厂offer。java
以下为一段代码,请完善sum函数,使得 sum(1,2,3,4,5,6) 函数返回值为 21 ,须要在 sum 函数中调用 asyncAdd 函数进行数值运算,且不能修改asyncAdd函数面试
/** * 请在 sum函数中调用此函数,完成数值计算 * @param {*} a 要相加的第一个值 * @param {*} b 要相加的第二个值 * @param {*} callback 相加以后的回调函数 */
function asyncAdd(a,b,callback) {
setTimeout(function(){
callback(null, a+b)
},1000)
}
/** * 请在此方法中调用asyncAdd方法,完成数值计算 * @param {...any} rest 传入的参数 */
async function sum(...rest) {
// 请在此处完善代码
}
let start = window.performance.now()
sum(1, 2, 3, 4, 5, 6).then(res => {
// 请保证在调用sum方法以后,返回结果21
console.log(res)
console.log(`程序执行共耗时: ${window.performance.now() - start}`)
})
复制代码
本题根据程序输出时间不一样,能够划分为三个难度等级数组
async function sum(...rest) {
// 取出来第一个做为初始值
let result = rest.shift()
// 经过for of 遍历 rest, 依次相加
for(let num of rest) {
// 使用promise 获取相加结果
result = await new Promise(resolve => {
asyncAdd(result, num, (_,res) => {
resolve(res)
})
})
}
// 返回执行结果
return result
}
// 执行成功,执行时长大于6秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`计算结果为:${res}`)
})
复制代码
在青铜难度,咱们把数组里面的每一项依次相加。可是也能够进行一些优化,能够并发执行多个,好比 sum(1,2,3,4,5,6)
,能够同时执行 1+2
,3+4
,5+6
,这样就能够提高执行效率promise
async function sum(...rest) {
// 若是传的值少于2个,则直接返回
if (rest.length <= 1) {
return rest[0] || 0
}
const promises = []
// 遍历将数组里面的值两个两个的执行
for (let i = 0; i < rest.length; i += 2) {
promises.push(
new Promise(resolve => {
// 若是 rest[i+1] 是 undefined, 说明数组长度是奇数,这个是最后一个
if (rest[i + 1] === undefined) {
resolve(rest[i])
} else {
// 调用asyncAdd 进行计算
asyncAdd(rest[i], rest[i + 1], (_, result) => {
resolve(result)
})
}
})
)
}
// 获取第一次计算结果
const result = await Promise.all(promises)
// 而后将第一次获取到的结果即 [3,7,11] 再次调用 sum执行
return await sum(...result)
}
// 执行成功,执行时长大于3秒小于4秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`计算结果为:${res}`)
})
复制代码
async function sum(...rest) {
let result = 0
// 隐氏类型转换, 对象 + 数字,会先调用对象的toString 方法
const obj = {}
obj.toString = function() {
return result
}
const promises = []
for(let num of rest) {
promises.push(new Promise((resolve) => {
asyncAdd(obj, num, (_, res) => {
resolve(res)
})
}).then(res => {
// 在这里将 result的值改变以后,obj.toString 的返回值就变了,这时候下一个setTimeout调用时就使用了新值
result = res
}))
}
await Promise.all(promises)
return result
}
// 执行成功,执行时长大于1秒小于2秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`计算结果为:${res}`)
})
复制代码
由于js
是执行在单线程里面的,因此上面的代码,咱们在for of
将全部的计算放到promises
数组里面,而后经过Promise.all
去一次性执行,这时候并不须要考虑到底先执行哪两个数字相加。由于单线程的缘由,咱们能够保证这几个Promise
是依次执行的,这时候obj.toString
返回值就是上一个Promise
的返回值,多跑几遍代码你就懂了哦markdown
请说明如下代码各输出了什么?并发
console.log(typeof (() => {}))
console.log(typeof ['前端有的玩','公众号'])
console.log(typeof null)
console.log(typeof undefined)
console.log(typeof Function.prototype)
console.log('子君' instanceof String)
console.log(new Date() instanceof Date)
复制代码
// 输出 function
console.log(typeof (() => {}))
// 输出 object
console.log(typeof ['前端有的玩','公众号'])
// 输出 object
console.log(typeof null)
// 输出 undefined
console.log(typeof undefined)
// 输出 function
console.log(typeof Function.prototype)
// 输出 false
console.log('子君' instanceof String)
// 输出 true
console.log(new Date() instanceof Date)
复制代码
须要注意的是,对于 typeof
, 能够正确判断除了null
以外的全部基本类型,而对于引用类型,除了函数外其余都会被判断为object
。app
对于instanceof
,没法判断基本类型,但能够正确判断引用类型async
请实现一个instanceof
,让如下代码可正常运行
/** 自定义instanceof */
function instanceOf(left, right) {
// 请完善如下代码,不能使用原生instanceof
}
class A{}
class B extends A {}
class C{}
const b = new B()
// 输出 true
console.log(instanceOf(b,B))
// 输出 true
console.log(instanceOf(b,A))
// 输出 false
console.log(instanceOf(b,C))
复制代码
本题主要考察instanceof
的判断原理,instanceof
主要的实现原理就是只要右边变量的 prototype
在左边变量的原型链上便可。所以,instanceof
在查找的过程当中会遍历左边变量的原型链,直到找到右边变量的 prototype
,若是查找失败,则会返回 false
。
/** 自定义instanceof */
function instanceOf(left, right) {
let proto = left.__proto__
while(proto){
if(proto === right.prototype){
return true
}
proto = proto.__proto__
}
return false
}
class A{}
class B extends A {}
class C{}
const b = new B()
// 输出 true
console.log(instanceOf(b,B))
// 输出 true
console.log(instanceOf(b,A))
// 输出 false
console.log(instanceOf(b,C))
复制代码
请模拟实现new
操做符,使下面代码正常运行
function myNew(constructor, ...rest) {
// 请在此处完善代码,不能直接使用 new 操做符
}
function Fun(name,sex) {
this.name = name
this.sex = sex
}
Fun.prototype.getUserInfo = function() {
return `个人姓名${this.name},个人性别${this.sex}`
}
const fun = myNew(Fun,'子君','男')
// 个人姓名子君,个人性别男
console.log(fun.getUserInfo())
复制代码
这道题考察的是使用new操做符
调用构造函数所经历的阶段:
function myNew(constructor, ...rest) {
if (typeof constructor !== 'function') {
return constructor;
}
//建立新的对象,关联构造函数的原型对象
const _constructor = Object.create(constructor.prototype);
//执行构造函数
const obj = constructor.apply(_constructor, rest);
//若是构造函数执行结果是对象则返回执行结果
if (typeof obj === 'object') {
return obj;
} else {
return _constructor;
}
}
function Fun(name,sex) {
this.name = name
this.sex = sex
}
Fun.prototype.getUserInfo = function() {
return `个人姓名${this.name},个人性别${this.sex}`
}
const fun = myNew(Fun,'子君','男')
// 个人姓名子君,个人性别男
console.log(fun.getUserInfo())
复制代码
请说出如下代码输出内容
const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'
// 我是子君仍是君子呢
console.log(a[b])
const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'
// 我是子君仍是君子呢
console.log(d[e])
复制代码
const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'
// 输出子君
console.log(a[b])
const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'
// 输出君子
console.log(d[e])
复制代码
对于第一个输出,Symbol()
函数会返回**「symbol」**类型的值,而Symbol
函数传的参数仅仅是用于标识的,不会影响值的惟一性
对于第二个输出, 由于e
和f
都是对象,而对象的key
只能是数值或字符,因此会将对象转换为字符,对象的toString
方法返回的是[object Object]
, 全部输出的是君子
请说出如下代码输出的内容
console.log([] + [])
console.log({} + [])
console.log([] == ![])
console.log(true + false)
复制代码
// 输出 "" 空字符串
console.log([] + [])
复制代码
这行代码输出的是空字符串""
, 包装类型在运算的时候,会先调用valueOf
方法,若是valueOf
返回的仍是包装类型,那么再调用toString
方法
// 仍是 数组
const val = [].valueOf()
// 数组 toString 默认会将数组各项使用逗号 "," 隔开, 好比 [1,2,3].toSting 变成了"1,2,3",空数组 toString 就是空字符串
const val1 = val.toString() // val1 是空字符串
复制代码
因此上面的代码至关于
console.log("" + "")
复制代码
第二行代码
// 输出 "[object Object]"
console.log({} + [])
复制代码
和第一题道理同样,对象 {}
隐氏转换成了[object Object]
,而后与""
相加
第三行代码
// 输出 true
console.log([] == ![])
复制代码
对于===
, 会严格比较二者的值,可是对于==
就不同了
因此对于上面的代码,看下面一步一步分析
// 这个输出 false
console.log(![])
// 套用上面第三条 将 false 转换为 数值
// 这个输出 0
console.log(Number(false))
// 包装类型与 基本类型 == 先将包装类型经过 valueOf toString 转换为基本类型
// 输出 ""
console.log([].toString())
// 套用第2条, 将空字符串转换为数值、
// 输出 0
console.log(Number(""))
// 因此
console.log(0 == 0)
复制代码
null == undefined
number
与number
比较,会将其转换为number
boolean
,那么会先将boolean
转换为number
第四行代码
// 输出 1
console.log(true + false)
复制代码
两个基本类型相加,若是其中一方是字符,则将其余的转换为字符相加,不然将类型转换为Number
,而后相加, Number(true)
是1
, Number(false)
是0
, 因此结果是 1
本文中的全部题目首发于公众号【前端有的玩】,小编天天都会整理一道两道面试题,而后推送给全部的朋友,关注小编,天天带你去刷面试题,不想当咸鱼,想要换工做,还在犹豫什么,关注 === 大厂offer。
不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高