解决问题的能力
1. [ ‘1’, ‘2’ , ‘3’ ].map (parseInt)输出什么
parseInt 最后返回的一定是一个 十进制的输,要么是NaN (not a Number)
// 2进制里面没有 3 ,只有1 或 2
parseInt("11", 2) // 答案 3
1 * 2 + 1
parseInt("3", 2) // 答案 NaN
// 3进制里面没有 4
parseInt("11", 3) // 答案 4
1 * 3 + 1
// 8进制里面没有 9
parseInt("11", 8) // 答案 9
1 * 9 + 1
parseInt("9", 8) // 答案 NaN
// 10进制里面没有 11,十进制中最多是 9
parseInt("11", 10) // 答案 11
1 * 10 + 1
// 16进制中 最多是15
parseInt("11", 16) // 答案 17
1 * 16 + 1
parseInt("A", 16) // 答案 10
parseInt("B", 16) // 答案 11
parseInt("F", 16) // 答案 15
parseInt('G', 16) // 答案 NaN
// 123456789ABCDEF | 123456789 10 11 12 13 14 15
parseInt("1F", 16) // 答案 31
1 * 16 + 15
parseInt("2F", 16) // 答案 47
2 * 16 + 15
parseInt ( "2", 1) 答案 NaN 。 0是不存在,1存在,但1 不符合 2-36区间
- 扩展 :
eslint 会建议 parseInt 写第二个参数
2. 以下代码输出什么
如下情况:会发生改变
- 扩展 :
eslint建议函数参数不要修改,当作常量
3. 手写 convert 函数,将数组转为树
// 就是 arr数组中 {id:1,name:'部们A',parentId:0} 每个结构
interface IArrayItem {
id: number
name: string
parentId: number
}
interface ITreeNode {
id: number
name: string
// 它是叶子节点可有可无,是最下面的节点
children?: ITreeNode[]
}
function convert(arr: IArrayItem[]): ITreeNode | null {
// 用于 id 和 treeNode 的映射
const idToTreeNode: Map<number, ITreeNode> = new Map()
let root = null // tree ,返回一个树,返回的就是根节点 rootNode
// 遍历数组
arr.forEach(item => {
const {
id, name, parentId } = item // 获取数组的各项参数
// 定义 tree node 并加入 map
const treeNode: ITreeNode = {
id, name }
idToTreeNode.set(id, treeNode)
//找到 parentNode 并加入到它的 children
const parentNode = idToTreeNode.get(parentId)
if (parentNode) {
if (parentNode.children == null) parentNode.children = []
parentNode.children.push(treeNode)
}
// 找到根节点
if (parentId === 0) root = treeNode
})
return root
}
const arr = [
{
id: 1, name: '部们A', parentId: 0 }, // 0 代表顶级节点,无父节点
{
id: 2, name: '部们B', parentId: 1 },
{
id: 3, name: '部们C', parentId: 1 },
{
id: 4, name: '部们D', parentId: 2 },
{
id: 5, name: '部们E', parentId: 2 },
{
id: 6, name: '部们F', parentId: 3 },
]
const tree = convert(arr)
console.info(tree)
树其实就是一个 json
4. 连环问:将树转为数组
// 就是 arr数组中 {id:1,name:'部们A',parentId:0} 每个结构
interface IArrayItem {
id: number
name: string
parentId: number
}
interface ITreeNode {
id: number
name: string
// 它是叶子节点可有可无,是最下面的节点
children?: ITreeNode[]
}
// 定义了函数 convert,接受一个树对象 root,返回一个符合 IArrayItem 接口的数组。
// 函数中使用了广度优先遍历的方式将树对象转换为数组。
function convert(root: ITreeNode): IArrayItem[] {
// 定义 Map 映射当前节点和父节点的关系
const nodeToParent: Map<ITreeNode, ITreeNode> = new Map()
const arr: IArrayItem[] = [] // arr 表示最终的数组
// 广度优先遍历,queue 是一个队列,用于存储待处理的节点。
const queue: ITreeNode[] = []
queue.unshift(root) // 将根节点 root 入队到 queue 中。
// 进入一个 while 循环,只要队列不为空就一直循环。
while (queue.length > 0) {
// 从队列中弹出一个节点 curNode
const curNode = queue.pop()
// 如果这个节点不存在(即队列已经空了),则跳出循环。
if (curNode == null) break
// 从当前节点 curNode 中解构出属性 id、name 和 children。其中 children 是一个可选属性,默认值为空数组。
const {
id, name, children = [] } = curNode
// 使用 nodeToParent 获取当前节点的父节点 parentNode。
const parentNode = nodeToParent.get(curNode)
// 如果不存在,则默认父节点为根节点,即 parentId 为 0。
const parentId = parentNode?.id || 0
// 创建一个新的数组元素 item,包含三个属性:id、name 和 parentId。
const item = {
id, name, parentId }
// 将 item 放入 arr 数组中。
arr.push(item)
// 遍历当前节点的子节点 children
children.forEach(child => {
// 将它与当前节点 curNode 建立映射关系
nodeToParent.set(child, curNode)
// 将子节点入队
queue.unshift(child)
})
}
return arr
}
const obj = {
id: 1,
name: "部门A",
children: [
{
id: 2,
name: "部门B",
children: [
{
id: 4, name: "部门D" },
{
id: 5, name: "部门E" }
]
},
{
id: 3,
name: "部门C",
children: [{
id: 6, name: "部门F" }]
}
]
}
const arr = convert(obj)
console.info(arr)
- 遍历当前节点的子节点
children
,对于每个子节点child
,将它与当前节点curNode
建立映射关系,即nodeToParent.set(child, curNode)
,然后将子节点入队queue.unshift(child)
。 - 最终返回转换后的
数组 arr
。
5. 以下代码输出什么
6. 一道令人失眠的 Promise.then执行顺序
7. 对象和属性的连续赋值
以下代码输出什么
let a = {
n: 1 }
let b = a
a.x = a = {
n: 2 }
console.log(a.x)
console.log(b.x)
8. 对象属性类型的问题
2. XXX公司 JS机试题
// 菜单:menu
class BaseMenu {
constructor(title, icon) {
this.title = title
this.icon = icon
}
isDisabled() {
return false
}
}
// 按钮菜单
class ButtonMenu extends BaseMenu {
constructor(title, icon) {
super(title, icon)
}
exec() {
console.log('hello')
}
}
// 列表菜单
class SelectMenu extends BaseMenu {
constructor(title, icon) {
super(title, icon)
}
exec() {
return ['item', 'item2', 'item3']
}
}
// 模态对话框菜单
class ModalMenu extends BaseMenu {
constructor(title, icon) {
super(title, icon)
}
exec() {
const div = document.createElement('div')
div.innerText = 'modal'
return div
}
}
1. 普通函数 和箭头函数 this 看如下题?
-
当我们在JS中定义一个类(class)时,this关键字指的是当前实例对象。也就是说,在类的内部,使用this关键字可以访问和操作当前实例对象的属性和方法。
-
在类的普通函数中,this关键字仍然指向当前实例对象。这与常规的JavaScript函数相同。
-
但是,在类的箭头函数中,this关键字指向的是该箭头函数所在的上下文,而不是当前实例对象。这是因为箭头函数没有自己的this值,它会从外部作用域继承this的值。