Interview questions for 1299 yuan sold at the front end of the MOOC [Phase 1] JS-day03

JS interview questions - there are advanced questions in the back


Previous MOOC JS interview questions, link address

1. What types can the typeof operator determine?

1. Identify all value types

 a 定义 undefined 不可以 使用 const ;
 let a;                     typeof a   // undefined; 未定义类型
 const str = '字符串类型';    typeof str // string;      字符串类型
 const n = 100;             typeof  n  //  number;  数字类型    
 const b = true;            typeof  b  // boolean;   布尔类型
 const s = Symbol( 's' );   typeof  s  // symbol;    独一无二的值

2. Identification function

  typeof    console.log           // function     函数
  typeof    function () {
    
     }       // function     函数

3. Determine whether it is a reference type (cannot be further subdivided)**

   typeof     null             // object   对象
   typeof     [ 'a' , 'b' ]    // object   对象
   typeof     {
    
     x: 100 }       // object   对象
   比如它是null 还是数组 或者对象,识别不出,不可再细分

2. Handwritten shallow copy and deep copy

1. Handwritten shallow copy

   //   浅拷贝 Shallow copy
    const obj1 = {
    
    
      age: 20,
      name: ' xxx ',
      address: {
    
    
        city: '北京'
      },
      arr: [' a ', ' b ', ' c ']
    }
    const obj2 = obj1
    obj1.address.city = ' 上海 ';
    console.log(obj.address.city)   // 打印结果: 上海     

2. Handwritten deep copy

   接  浅拷贝 改  const  obj2 = deepClone( obj1 ) 即可
   //    深拷贝  deep copy 
   function  deepClone ( obj = {
     
      } ) {
    
    
         // 如果 obj 类型不是对象也不是数组 或者 obj 为空
         if ( typeof obj !== ' object ' || obj == null ) {
    
    
              return obj   // 终止返回,不进行拷贝
         }
         // 初始化返回结果
         let result ; 
         if ( obj  instanceof  Array ) {
    
         // 判断 拷贝的内容 是否是数组
              result = [ ] ;
         } else {
    
    
              result = {
    
     } ;
         } 
         
         for ( let key in obj ) {
    
    
              if ( obj.hasOwnProperty ( key ) ) {
    
    
                 // 递归调用 !!!
                 result [key] = deepClone( obj[ key ] )
              }
         }
        // 返回结果
        return result 
}

3. When to use the == operator

   //  除了 == null 之外, 其他都一律使用 ===,例如:
   const  obj = {
    
     x: 100 }
   if ( obj.a == null ) {
    
     }
   // 相当于 :
   if ( obj.a === null || obj.a === undefined ) {
    
     } 

If you don't use ===, it will show the following effect

   100  ==  ' 100 '             // true
    0  ==  '  '                 // true
    0  ==  false                // true
    false  ==  ' '              // true
    null ==  undefined          // true

4.truly variable and falsely variable

truly variable: a variable where !!a === true

例如 : const n = 100
       打印 !n 为 false 
       打印 !!n 为 true
 如果是 对象 那就是 truly 变量
       !!{
    
     } 打印为 true

falsely variable: !!a === false variable

例如 : const n1 = 0
       打印 !!0false
       打印 !0true
以下是falsely 变量。除此之外都是 truely 变量
       !!0     === false
       !!null  === false 
       !!' '   === false 
       !!NaN   === false (NaN = not a number 把一个个字符串,转换为数字 转换不出来,使用)
       !!false === false
       !!undefined  === false

insert image description here
logical judgment

1. console.log ( 10 && 0) // result: 0

10 is a truely variable, and then it is judged that 0 is a falsely variable and returns 0

2. console.log ( ’ ’ || ’ abc ’ ) // ‘ abc ’

' 'is a falsely variable, and later judges that 'abc' is a truely variable, and returns 'abc'

3. console.log ( !window.abc ) // true

3. class class extends inheritance

insert image description here

insert image description here
insert image description here

4. Type instanceof judgment and JS prototype

insert image description here

1. JS Prototype

insert image description here
insert image description here

insert image description here

insert image description here
insert image description here

2. Prototype chain

insert image description here
insert image description here

insert image description here

insert image description here

insert image description here
insert image description here

4. JS Closures

insert image description here

  • Closure: The search for free variables is at the place where the function is defined, and
    it is searched to the upper scope, not at the place where the function is executed! ! !

insert image description here

5. Briefly describe this

insert image description here

insert image description here
insert image description hereinsert image description here

1. Handwritten bind

insert image description here
insert image description here
insert image description here
insert image description here

2. The role of closures in actual development

Hidden data
is as follows to make a simple cache cache tool
insert image description here
insert image description here

6. js asynchronous and single thread

insert image description here

insert image description here

insert image description here
insert image description here

What problem does promise solve?

insert image description here
callback hell callback hell
insert image description here

insert image description here

7. Handwritten promise to load a picture

  • Asynchronous usage scenarios: network requests, such as ajax image loading, timed tasks, such as setTimeout
    insert image description here
    insert image description here

8. DOM node operation interview questions

property is not part of the API name, it is a form, a form of manipulating dom elements using js properties
insert image description here

The difference between property and attribute

property form

Modifications made to dom element js variables
property: modifying object properties will not be reflected in html

attribute form

The attribute of the dom element structure is also a modification of the node attribute, which can actually be applied to the node attribute
attribute: modifying the html attribute will change the html structure

Both may cause the DOM to re-render, if necessary: ​​it is recommended to use the property form

Please add a picture description
insert image description here

Get DOM node

insert image description here

DOM performance

insert image description here

Change frequent operations to one-time operations
insert image description here

9. BOM operation interview questions

1. Event binding and event bubbling

insert image description here
insert image description here

insert image description here

insert image description here

insert image description here

insert image description here

insert image description here
insert image description here

insert image description here

insert image description here

2. How to identify the type of browser

insert image description here

3. Split the various parts of the url

Please add a picture description

4. JSONP cross-domain

insert image description here

insert image description here

insert image description here

5. Handwritten Ajax core API-XMLHttpRequset initiates a request

false is a synchronous request, true is an asynchronous request

insert image description here

Why xhr.readyState === 4

insert image description here

Why xhr.status === 200

insert image description here

insert image description here

insert image description here

10. Describe the difference between Cookie LocalStorage SessionStorage

insert image description here

insert image description here
insert image description here

insert image description here

11. JS extension (advanced)

1.Arrag Flatten implements first-level flattening of arrays

insert image description here
insert image description here

Please add a picture description

    function flatten1(arr) {
    
    
      // 定义了一个空数组变量 res,用于储存展开后的结果。
      const res = [];
      // 使用 forEach 方法遍历输入数组 arr 中的每一个元素,并对每个元素执行一个回调函数。
      arr.forEach(item => {
    
    
        // Array.isArray 方法检查当前处理的元素是否为数组类型。如果是数组类型
        if (Array.isArray(item)) {
    
    
          // 使用 forEach 方法遍历当前元素(即数组)中的每一个元素,并将其加入结果数组 res 中。
          item.forEach(n => res.push(n));
        } else {
    
    
          // 将当前元素直接加入结果数组 res 中。
          res.push(item);
        }
      });
      return res;
    }
    // 功能测试
    const arr = [1, [2, [3], 4], 5, 6];
    console.info(flatten1(arr));

Please add a picture description

Please add a picture description

function flatten2(arr) {
    
        // 声明一个函数,接收一个数组作为参数
  let res = [];             // 声明一个空数组用于存放扁平化后的结果

  arr.forEach(item => {
    
         // 使用 forEach() 方法遍历传入的数组 arr
    res = res.concat(item); // 将当前元素 item 连接到结果数组 res 中
  });
  
  return res;               // 返回结果数组 res
}

const arr = [1, [2, [3], 4], 5, 6]; // 声明一个多维数组 arr,用于测试 flatten2 函数
console.info(flatten2(arr));         // 执行函数并打印结果

Please add a picture description
push can modify an array, but concat cannot modify an array

2. Array Flatten realizes the complete flattening of the array

Please add a picture description
train of thought

  • First achieve a level of flattening, and then call recursively until all are flattened

insert image description here

function flattenDeep1(arr) {
    
    
  const res = [];

  arr.forEach(item => {
    
    
    if (Array.isArray(item)) {
    
    
      const flatItem = flattenDeep1(item); // 递归
      flatItem.forEach(n => res.push(n));
    } else {
    
    
      res.push(item);
    }
  });
  return res;
}

// 功能测试
const arr = [1, [2, [3, ['a', [true], 'b'], 4], 5], 6];
console.info(flattenDeep1(arr));

insert image description here

    function flattenDeep2(arr) {
    
    
      let res = []

      arr.forEach(item => {
    
    
        
        if (Array.isArray(item)) {
    
    
          const flatItem = flattenDeep2(item) // 递归
          res = res.concat(flatItem)
        } else {
    
    
          res = res.concat(item)
        }
      })
      return res
    }
    // 功能测试
    const arr = [1, [2, [3, ['a', [true], 'b'], 4], 5], 6];
    console.info(flattenDeep2(arr));

insert image description here

3. Write a getType function by hand to get the detailed data type

insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

insert image description here
insert image description here
insert image description here

4. What happens to new an object? Please write the code to indicate

代码演示:class是function的语法糖
insert image description here
insert image description here
insert image description here

insert image description here
insert image description here
insert image description here

5. Serial question: What is the difference between Object.create and {}?

insert image description here

insert image description here

6. Traversing the DOM tree

insert image description here
insert image description here

  • Depth first is: <div>, then <p>, "hello" again, and then there is no more, go back to, go down <p>, <b>go to the world, go back to <p>, go back to <div>, go to <img/>. loop until<ul>下<li>标签下的"b"走完结束。
  • Breadth-first is:<div>完后,往下<p>、<img/>、<!--注释-->、<ul>,随后"hello",<b>、<li>、<li>。下面依次这样,直到"b"结束。
    Please add a picture description

insert image description here

insert image description here
Breadth-first traversal: as follows

function breadthFirstTraverse(root: Node) {
    
    
  const queue: Node[] = [] // 数组 vs 链表

  // 根节点入队列
  queue.unshift(root)
  while (queue.length > 0) {
    
    
    const curNode = queue.pop()
    if (curNode == null) break

    visitNode(curNode)

    // 子节点入队
    const childNodes = curNode.childNodes
    if (childNodes.length) {
    
    
      childNodes.forEach(child => queue.unshift(child))
    }
  }
}

const box = document.getElementById('box')
if (box == null) throw new Error('box is null')
breadthFirstTraverse(box)

insert image description here

insert image description here

7. Handwritten LazyMan

insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

7. Write a curry function by hand to curry other functions

insert image description here
insert image description here

export function curry(fn:Function){
    
      curry是:输入函数,返回函数
     const fnArgsLength = fn.length // 传入函数的参数长度
     let args: any[] = []
     
     // ts中,独立的函数,this 仅仅需要声明类型,并不是参数,而且要放到第一位
     function calc(this: any,...newArys:any[]){
    
    
        // 积累参数
        arg = [
            ...args, ...newArgs
        ]
        中间状态,当前积累的参数,如果小于传入函数参数长度的话,就返回一个函数
        if(args.length < fnArgsLength){
    
    
           // 参数不够,返回函数
           return calc
        }else{
    
    
           如果参数够了,=甚至是>了当前函数参数的长度,那就执行返回结果
           // 参数够了,返回执行结果
           执行参数结果,使用apply来执行,将this传入,将参数做一个截断,传入参数长度多少就截取多少
           return fn.apply(this,arg.slice(0, fnArgsLength))
        }
     }
     return calc
}

function add(a:number,b:number,c:number):number{
    
    
     return a+b+c
}
const curryAdd = curry(add)
const res = curryAdd(10)(20)(30)
console.log(res) // 结果 60

insert image description here
insert image description here

8. What is the principle of instanceof, please express it in code (very important!!!)

insert image description here
insert image description here

 /**
  * 自定义 instanceof 方法
  * @param instance instance 就是实例
  * @param origin 就是class or function
 */
 // 传入两个参数一个是 instance实例,any类型。 第二个是origin。返回boolean类型
export function myInstanceof(instance: any, origin: any): boolean {
    
    
  if (instance == null) return false // 如果instance 是null undefined 就返回 false

  const type = typeof instance // 判断instance 的类型
  // 如果不是 object对象 并且 不是 function函数
  if (type !== 'object' && type !== 'function') {
    
    
    // 值类型; (所有的值类型,进行 instanceof 都是 false
    return false
  }

  let temInstance = instance // 使用临时变量赋值 instance,为了防止修改 instance
  while (temInstance) {
    
     // 只要有 temInstance
    // 判断 当前实例的隐式原型 是否全等于 class或function 的显示原型
    if (temInstance.__proto__ === origin.prototype) {
    
    
      比如 instance是个数组,origin是个 Array的构造函数,那就匹配上了
      return true // 匹配上了
    }
    // 未匹配上
    temInstance = temInstance.__proto__ // 顺着原型链,往上找
    比如图上 new Foo() 未匹配上,会往上走到 Foo 圆圈哪里再进行匹配,此时就匹配上了
  }

  // 原型链结束了,还没匹配上,返回 false
  return false
}

// 功能测试
console.log(myInstanceof({
    
    },Object))
console.log(myInstanceof([],Object))
console.log(myInstanceof([],Array))
console.log(myInstanceof({
    
    }, Array))
console.log(myInstanceof('abc',String))

insert image description here

9. Handwritten function bind

insert image description here

insert image description here
insert image description here
insert image description here

insert image description here
Defined on the Function prototype
insert image description here

10. Handwritten function call and apply

insert image description here
insert image description here
insert image description here
If content == null, the window is printed.
insert image description here

  • new Object('abc') will judge to generate String('abc') object;
  • new Object(true) will judge to generate a Boolean(true) object

handwritten call

// 自定义 call
// @ts-ignore 取消文件下一行的错误提示。   ...args传入的是零散的参数
Function.prototype.customCall = function (context: any, ...args: any[]) {
    
    
  if (context == null) context = globalThis // 如果 call == null,打印的是window。
  // 值类型,变对象类型
  if (typeof context !== 'object') context = new Object(context)

  const fnKey = Symbol() // 不会出现属性名称的覆盖,是唯一的
  context[fnKey] = this // this就是当前的函数

  const res = context[fnKey](...args) // 绑定了 this

  delete context[fnKey] // 清理掉 fn ,防止污染

  return res
}

// 测试
function fn(this: any, a: any, b: any, c: any) {
    
    
  console.log(this, a, b, c)
}

// @ts-ignore
fn.customCall({
    
     x: 100 }, 10, 20, 30)

handwritten apply

// 自定义 apply
// @ts-ignore 取消文件下一行的错误提示。       args传入的是数组
Function.prototype.customApply = function (context: any, args: any[] =[]) {
    
    
  if (context == null) context = globalThis // 如果 apply == null,打印的是window。
  // 值类型,变对象类型
  if (typeof context !== 'object') context = new Object(context)

  const fnKey = Symbol() // 不会出现属性名称的覆盖,是唯一的
  context[fnKey] = this // this就是当前的函数

  const res = context[fnKey](...args) // 绑定了 this

  delete context[fnKey] // 清理掉 fn ,防止污染

  return res
}

// 测试
function fn(this: any, a: any, b: any, c: any) {
    
    
  console.log(this, a, b, c)
}

// @ts-ignore
fn.customApply({
    
     x: 200 }, [100, 200, 300])

insert image description here

11. Handwritten EventBus custom events

insert image description here

insert image description here

Use filter to filter to write

 // 手写 EventBus 
class EventBus {
    
    
  /**
   * {
   *    "key1":[
   *       { fn: fn1, isOnce: false},
   *       { fn: fn2, isOnce: false},
   *       { fn: fn3, isOnce: true},
   *    ]
   *    "key2":[] // Object是无序的,需要使用 数组是有序的
   *    "key3":[]
   * }
   */
  private events: {
    
     // Array<里面是对象{}> 数组
    [key: string]: Array<{
    
     fn: Function, isOnce: boolean }>
  }

  // 构造函数
  constructor() {
    
    
    this.events = {
    
    }
  }

  // 绑定。 第一个参数 是type ,第二个参数是 函数 , 第三个参数 默认值为false
  on(type: string, fn: Function, isOnce: boolean = false) {
    
    
    const events = this.events // 获取 this.events
    if (events[type] == null) {
    
     // 如果
      events[type] = [] // 初始化 key 的 fn 数组
    }
    events[type].push({
    
     fn, isOnce: false })
  }

  // 只执行一次,就解绑
  once(type: string, fn: Function) {
    
    
    this.on(type, fn, true)
  }

  // 解绑
  off(type: string, fn?: Function) {
    
    
    // 如果 fn 没有值, 可以根据 type 解绑所有函数
    if (!fn) {
    
    
      // 解绑所有  type 的函数
      this.events[type] = []
    } else {
    
    
      // 解绑 单个 fn
      const fnList = this.events[type]
      // 如果 type的函数有值是个数组,重新赋值
      if (fnList) {
    
    
        // 如果 单个 type 的 fn 不等于 当前的fn, 那就过滤出来。
        // 如果 等于 那就不要了
        this.events[type] = fnList.filter(item => item.fn !== fn)
      }
    }
  }

  // 触发
  emit(type: string, ...args: any[]) {
    
     // ...args 多个参数
    const fnList = this.events[type] // 触发这个事件,将这个类型的事件 全部获取出来
    if (fnList == null) return

    // 注意, 过滤的前提是遍历
    this.events[type] = fnList.filter(item => {
    
    
      const {
    
     fn, isOnce } = item // 在这个item里面找到 fn isOnce
      fn(...args) // 触发 fn

      // once 执行一次就要呗过滤掉
      if (!isOnce) return true
      return false;
    })
  }
}

insert image description here

Split and save on and once events to implement EventBus

class EventBus {
    
    
  // { key1: [fn1,fn2], key2:[fn1,fn2]}
  private events: {
    
     [key: string]: Array<Function> }
  private onceEvents: {
    
     [key: string]: Array<Function> }
  // 构造函数
  constructor() {
    
    
    this.events = {
    
    } // 赋值为空对象
    this.onceEvents = {
    
    } // 赋值为空对象
  }

  // on 绑定
  on(type: string, fn: Function) {
    
    
    const events = this.events
    if (events[type] == null) events[type] = []
    events[type].push(fn)
  }

  // 只执行一次就解绑
  once(type: string, fn: Function) {
    
    
    const onceEvents = this.onceEvents
    if (onceEvents[type] == null) onceEvents[type] = []
    onceEvents[type].push(fn)
  }

  // off 解绑
  off(type: string, fn?: Function) {
    
    
    if (!fn) {
    
    
      // 解绑所有事件
      this.events[type] = []
      this.onceEvents[type] = []
    } else {
    
    
      // 解绑单个事件
      const fnList = this.events[type]
      const onceFnList = this.onceEvents[type]
      if (fnList) {
    
    
        this.events[type] = fnList.filter(curFn => curFn !== fn)
      }
      if (onceFnList) {
    
    
        this.onceEvents[type] = onceFnList.filter(curFn => curFn !== fn)
      }
    }
  }

  // 触发 emit
  emit(type: string, ...args: any[]) {
    
    
    const fnList = this.events[type]
    const onceFnList = this.events[type]

    if (fnList) {
    
    
      fnList.forEach(f => f(...args))
    }
    if (onceFnList) {
    
    
      onceFnList.forEach(f => f(...args))
      // once 执行一次就删除
      this.onceEvents[type] = []
    }
  }
}

insert image description here

总体来说这两个 代码 都可以实现,具体使用哪个 看个人理解代码的能力

12. Realize LRU cache with js (to be added later)

insert image description here

13. Handwritten js deep copy, consider Map, Set, circular reference

insert image description here
insert image description here
insert image description here
insert image description here

Deep copy - only simple arrays and objects are considered

insert image description here

function cloneDeep(obj: any) {
    
    
  if (typeof obj !== 'object' || obj == null) return obj

  let result: any
  if (obj instanceof Array) {
    
    
    result = []
  } else {
    
    
    result = {
    
    }
  }

  for (let key in obj) {
    
    
    if (obj.hasOwnProperty(key)) {
    
    
      result[key] = cloneDeep(obj[key]) // 递归调用
    }
  }
  return result
}

// 功能测试 
// const a: any = {
    
    
//   set: new Set([10, 20, 30]),
//   map: new Map([['x', 10], ['y', 20]])
// }
// // a.self = a
// console.log(cloneDeep(a)) // 无法处理 Map set 和循环引用

interface Person {
    
    
  name: string,
  age: number,
  hobbies: string[]
}

const person1: Person = {
    
    
  name: 'Alice',
  age: 30,
  hobbies: ['reading', 'cooking']
}

const person2 = cloneDeep(person1)
person2.hobbies.push('swimming')

console.log(person1.hobbies) // ['reading', 'cooking']
console.log(person2.hobbies) // ['reading', 'cooking', 'swimming']

Deep copy, consider Object Array Map Set

insert image description here

/**
 * 深拷贝
 * @param map weakmap 为了避免循环引用, 弱引用。
 * 不影响存在里面对象,垃圾销毁垃圾回收,不会导致内存泄漏
 */
export function cloneDeep(obj: any, map = new WeakMap()): any {
    
    
  if (typeof obj !== 'object' || obj == null) return obj

  //避免循环引用
  const objFromMap = map.get(obj)
  if (objFromMap) return objFromMap // 如果有值直接返回

  // target 经过很多深拷贝处理,返的结果。
  let target: any = {
    
    } // target是存储结果。
  map.set(obj, target)

  // Map 处理
  if (obj instanceof Map) {
    
    
    target = new Map() // 重新赋值
    obj.forEach((v, k) => {
    
     // val , key
      const v1 = cloneDeep(v, map)
      const k1 = cloneDeep(k, map)
      target.set(k1, v1)
    })
  }

  // Set 处理
  if (obj instanceof Set) {
    
    
    target = new Set()
    obj.forEach(v => {
    
     // 只有 val
      const v1 = cloneDeep(v, map)
      target.add(v1) // 使用 add() 方法向 Set 对象添加元素。
    })
  }

  // Array 处理 
  if (obj instanceof Array) {
    
    
    // map 可以返回一个新的数组
    target = obj.map(item => cloneDeep(item, map))
  }

  // Object 处理
  for (const key in obj) {
    
    
    // 对象的key,一版是字符串,是值类型,不需要深拷贝
    const val = obj[key]
    const val1 = cloneDeep(val, map) // 只拷贝val就可以
    target[key] = val1
  }
  return target
}
// 功能测试
const a: any = {
    
    
  set: new Set([10, 20, 30]),
  map: new Map([['x', 10], ['y', 20]]),
  info: {
    
    
    city: '北京'
  },
  fn: () => {
    
     console.info(100) }
}
a.self = a
console.log(cloneDeep(a))

insert image description here
insert image description here
insert image description here

Supplement new set and new map

insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/weixin_46426412/article/details/130477784