手撕笔试题

1-事件委托
let ul = document.querySelector("ul")
 console.log(ul)
 ul.onclick = function (e) {
   //当点击某"li"标签时,该标签内容拼接"."符号。
   //e.target双向绑定
   console.log(e.target)
   e.target.innerHTML += "."
 }
2-数组去重
//数组去重
  const _deleteRepeat = array => {
    // 补全代码
    // let set = new Set(array)
    // console.log(set)
    // return Array.from(new Set(array))
    return [...new Set(array)]

  }
  console.log(_deleteRepeat([-1, 1, 2, 2]))
            // [-1,1,2]
3-将数组中的数字小到大排序后返回(快速排序)

快速排序的思想:

const _quickSort = array => {

    // 补全代码
    //递归实现快速排序
    let len = array.length
    if (len <= 1) return array
    // //
    let mid = Math.floor(len / 2)//数组长度的一半
    //splice(start:number,deletenum:number),得到的是数组,删除元素,会改变原数组
    // slice(start:number,end:number),得到的是数组,不会改变原数组
    // console.log(array.splice(mid, 1)[0])
    // console.log(array.slice(mid, mid + 1))
    let left = [], right = []
    let midValue = array.splice(mid, 1)[0]
    for (let a of array) {
      console.log(a)
      a < midValue ? left.push(a) : right.push(a)
    }
    // console.log(left, "y", right)
    return _quickSort(left).concat(midValue,_quickSort(right))
  }
  console.log(_quickSort([0, -1, 1, -2, 2]))
            // [-2,-1,0,1,2]
4-全排列

以数组的形式返回字符串参数的所有排列组合。
注意:

  1. 字符串参数中的字符无重复且仅包含小写字母
  2. 返回的排列组合数组不区分顺序
5-实现Array.map相同功能的_map函数
  //为Array类添加一个_map函数
  //本身操作的就是调用函数的数组,函数传入的参数是对数组修改的函数
  //箭头函数和普通函数:箭头函数中this是window,普通函数this才能得到调用的数组本身
  //map会修改数组本身吗?不会
  //fn函数处理的是数组的每个元素
  Array.prototype._map = function (fn) {
    //console.log(this)
    let res = []
    for (let a of this) {
      res.push(fn(a))
    }
    return res

  }
  console.log([1, 2]._map(i => i * 2))
6-实现Array.filter
  //[1,2]._filter(i => i>1)
  //filter会改变原数组吗?不会
  Array.prototype._filter = function (fn) {
    let res = []
    for (let a of this) {
      if (fn(a))
        res.push(a)
    }
    return res

  }
  console.log([1, 2]._filter(i => i > 1))//[2]
7-实现Array.reduce
  //reduce计算数组元素的总和,传入两个参数:第一个参数回调函数,第二个initValue
  //对于空数组不执行回调函数
  //回调函数的参数
  //参数:total初始值或是计算结束之后的返回值;currentValue当前元素(item)
  //currentIndex:非必须(index),arr:调用函数的数组对象(this)
  //改变原数组吗?不
  Array.prototype._reduce = function (fn) {
    // console.log(arguments)
    let sum = arguments[1] ? arguments[1] : 0;
    // forEach可以直接遍历item,index
    this.forEach((item, index) => {
      sum = fn(sum, item, index, this)
    })
    return sum
  }
  console.log([1, 2, 3]._reduce((left, right) => left + right))
8-实现对象的浅拷贝Object.assign
	const _shallowClone = target => {
    //   // 参数可能包含函数、正则、日期、ES6新对象
    //   //浅拷贝:基本数据类型直接拷贝,引用数据类型只拷贝一层
    //   //引用数据类型包括
    //   //null、undefined
    //   //日期,正则,
    //对象数组
    if (target === null || typeof target === "undefined"||typeof target !== "object") 
    	return target
    let type = Object.prototype.toString.call(target)
    if (type == "[Object Date]" || type == "[Object RegExp]" || type == "[Object Function]") 
   		 return target;
    let res = type = "[Object Array]" ? [] : {}
    //Object.keys(target)可以获取target自身的所有的可枚举属性,target是数组对象,得到的是下标
    Object.keys(target).forEach((item, index) => {
      console.log(item, "y", target[item])
      res[item] = target[item]
    })
    return res

  }
  let arr = ["q", "w", "e"]
  // let arr = {
  //   name: "yyy",
  //   age: 20
  // }
  console.log(_shallowClone(arr))
9-实现简单深拷贝,参数类型以及参数中的属性类型都只有基本数据类型,数组和对象三种类型,不需要考虑循环引用
  function checkType(target) {
    return Object.prototype.toString.call(target).slice(8, -1)
  }
  const _sampleDeepClone = target => {
    // 补全代码
    //无需考虑循环引用的问题
    //参数对象和参数对象的每个数据项的数据类型范围仅在数组、普通对象({})、基本数据类型中]
    // [Object Array]
    //使用递归实现深拷贝
    const type = checkType(target)
    let newTarget = type == "Array" ? [] : {}
    //Object.keys遍历对象自身可枚举属性,for in遍历对象以及原型链上的可枚举属性
    //如果是数组或对象类型接着向上递归,否则直接返回被newTarget[prop]接收
    if (type == "Array" || type == "Object") {
      for (let prop in target) {
        //target.hasOwnProperty(prop)保证一层层遍历
        // newTarget[prop]=target.hasOwnProperty(prop)?target[prop]:_sampleDeepClone(prop)
        if (target.hasOwnProperty(prop)) {
          console.log("prop", prop, "target[prop]", target[prop])
          newTarget[prop] = _sampleDeepClone(target[prop])
        }
      }
      return newTarget
    } else {
      return target
    }
  }
  let arr = {
    name: "yyy",
    age: 21,
    obj: {
      name: "syc",
      age: 70,
      obj2: {
        play: "good"
      }
    }
  }
  console.log(_sampleDeepClone(arr))
10-复杂深拷贝,

循环引用:一个对象包含对另一个对象的引用,而另一个对象也包含对第一个对象的引用。解决循环引用需要记录已访问属性或者使用弱引用。
使用 new WeakMap() 初始化一个对象 memo 作为记录表,以确保不会无限制地复制相同的对象。如果当前的 memo 已经注册过该对象,则返回 memo 中的新的副本;否则,就新建一个数组或者对象,进行递归复制,同时在 memo 中记录原文件及其副本。

function checkType(param) {
    return Object.prototype.toString.call(param).slice(8, -1)
  }
  const _completeDeepClone = (target, map = new Map()) => {
    // 补全代码
    //需要考虑函数、正则、日期、ES6新对象
    //考虑循环引用
    if (target === null || typeof target !== "object") return target
    //函数,正则,日期
    //如果是es6新对象,函数,正则,日期,直接返回参数对象对应的构造函数生成的实例对象
    const type = checkType(target)
    if (type == "Function") return new Function(target)
    if (type == "Date") return new Date(target.getTime())
    if (type == "RegExp") return new RegExp(target)
    if(type=="Set")return new Set(target)
    if(type=="Map")return new Map(target)
    //
    const constructor=target.constructor
    // const constructor = target.constructor
    // if(/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return new constructor(target)
    if(/^(Function|Date|RegExp|Set|Map)$/i.test(constructor.name))return new constructor(target)
    //数组,对象
    //map,set
    //如果出现循环引用,直接返回引用
    //如果从map中可以获取当前参数对象,循环引用,直接返回;如果不能获取,将当前参数对象加入map标记
    if (map.has(target)) return map.get(target)
    else map.set(target, true)
    //
    let newTarget = type === "Array" ? [] : {}
    //前面已经判断过非[]{}的直接返回了
    for (let prop in target) {
      if (target.hasOwnProperty(prop))
        newTarget[prop] = _completeDeepClone(target[prop], map)
    }
  }
  // let a = new Map()
  // a.set("name", "yyy")
  // console.log(checkType(a))
const _completeDeepClone = (target, map = new Map()) => {
    //基本数据类型,null,undefined
    if (target === null || typeof target !== "object") return target
    //解决循环引用
    if (map.has(target)) return map.get(target)
    //函数、正则、日期、ES6新对象
    const constructor = target.constructor
    console.log(constructor.name)
    console.log("ok", /^(Function|Date|RegExp|Map|Set)$/ig.test(constructor.name))
    let newTarget;

    if (/^(Function|Date|RegExp|Map|Set)$/ig.test(constructor.name))
      //根据参数对象对应的构造函数得到实例对象
      newTarget = new constructor(target)
    map.set(target, newTarget)
    //Map,Set,Symbol
    //Array.from处理可迭代对象
    if (constructor == "Map") {
      Array.from(target, (key, val) => { newTarget.set(_completeDeepClone(key, map), _completeDeepClone(val, map)) })
    } else if (constructor == "Set") {
      Array.from(target, key => { newTarget.add(_completeDeepClone(key, map)) })
    } else if (constructor == "Symbol") {
      newTarget = Symbol(target.description)
    } else {
     //数组和对象
     // 然而,如果输入对象非常大或太嵌套,则可能导致堆栈溢出。
      newTarget = (Array.isArray(target)) ? [] : {}
      for (let prop in target) {
        if (target.hasOwnProperty(prop))
          newTarget[prop] = _completeDeepClone(target[prop], map)
      }
    }
    return newTarget



  }
11-发布订阅模式
  1. 同一名称事件可能有多个不同的执行函数
  2. 通过"on"函数添加事件
  3. 通过"emit"函数触发事件
class EventEmitter {
    // 补全代码
    //发布-订阅模式是一种软件架构模式,多个组件将事件、消息传递给主题,中心类
    constructor(){
      this.events={}//使用events对象存储事件名称和事件处理函数
    }
    on(eventName,func){
      //eventName在事件对象中是否存在
      //key是eventName:String,value是存放事件处理函数的数组
      if(!this.events[eventName])
        this.events[eventName]=[]
      this.events[eventName].push(func)
    }
    emit(eventName,args){
      //执行事件处理函数
      const event=this.events[eventName]
      if(event){
        event.forEach((func)=>{
          //apply() 来调用与事件名称关联的每个函数,
          //并将提供的参数作为一个参数数组传递进去,以确保每个函数都会接收到这些参数并执行相应的操作。
          func.apply(null,args)//
        })
      }

    }

12-观察者模式(有误)

请补全JavaScript代码,完成"Observer"、"Observerd"类实现观察者模式。要求如下:

  1. 被观察者构造函数需要包含"name"属性和"state"属性且"state"初始值为"走路"
  2. 被观察者创建"setObserver"函数用于保存观察者们
  3. 被观察者创建"setState"函数用于设置该观察者"state"并且通知所有观察者
  4. 观察者创建"update"函数用于被观察者进行消息通知,该函数需要打印(console.log)数据,数据格式为:小明正在走路。其中"小明"为被观察者的"name"属性,"走路"为被观察者的"state"属性
    注意:
  5. "Observer"为观察者,"Observerd"为被观察者
          class Observerd {
    //主题对象,被观察者

    constructor(name) {
      this.name = name
      this.state = "走路"
      this.observers = []//存储观察这个被观察者的观察者对象们
    }
    //保存观察者们
    setObserver(observer) {
      // if (!this.observers[observer])
        this.observers.push(observer)

    }
    // 设置该观察者state并通知其他所有观察者
    setState(state) {
      this.state = state
      //通知观察者
      //this.notifyObservers()
        for(let observer of this.observers){
        observer.update(this)
      }

    }
      // this.observers.forEach(item=>{
      //   //箭头函数无法保证this是当前实例化的的被观察者对象
      //   item.update(this)
      // })
    }

  }

  class Observer {
    //被观察者的消息通知
    update(observered) {
      console.log(observered.name,"正在",observered.state)
     }

  }

13、Object.create只能改变新创建对象的属性,无法改变继承的原型对象上的属性

  const person = { name: "yyy" }
  const student = Object.create(person)
  student.age = 21
  delete student.person
  console.log(person.name)//yyy
  console.log(student.name)//yyy
  delete student.age
  console.log(student.age)//undefined
### OPPO硬件笔试题目分析 对于计算机硬件设计、电路以及微处理器相关的职位,通常会涉及一些基础理论知识和实际应用能力的考察。以下是可能涉及到的一些典型问题及其解答: #### 1. **触发器与时序逻辑** - 类似于联发科的笔试题,可能会要求考生写出特定触发器的状态方程并绘制波形图。例如,JK触发器的功能可以通过其特性表来推导状态转移方程[^1]。 ```plaintext Q(t+1) = J * !Q(t) + K' * Q(t) ``` 这类题目旨在测试应聘者对基本数字电路的理解程度。 #### 2. **序列检测器的设计** - 可能会有状态机的要求,比如设计一个能够同时检测两个不同二进制序列(如`101` 和 `110`)的有限状态机(FSM)。这类问题不仅考验候选人的组合逻辑设计技能,还评估他们处理复杂条件的能力。 #### 3. **编程能力考核** - Python 编程也是常见考点之一。可以预期到简单的算法实现或者数据结构操作方面的考题。例如编写函数解决经典的水壶倒油问题或其他类似的逻辑推理挑战。 #### 4. **MUX 实现方式** - 使用门电路构建多路复用器(Multiplexer, MUX),这是另一个可能出现的基础知识点。通过AND/OR gates加上控制信号线即可完成这一任务。 ```python def mux(a, b, sel): """Simple 2-to-1 Multiplexer implementation.""" return (a & ~sel) | (b & sel) print(mux(0b1010, 0b1111, 0)) # Output should be '1010' print(mux(0b1010, 0b1111, 1)) # Output should be '1111' ``` #### 5. **高级架构理解** - 对于更资深的角色,则需准备关于现代处理器体系结构的问题,像紫光国芯提到过的RISC-V指令集特点、总线协议差异(APB vs AHB vs AXI)等内容都属于潜在范围内的讨论主题[^2]。 --- ### 总结 上述内容涵盖了从初级到中级水平的技术要点,具体难度取决于目标岗位的具体职责描述和技术栈需求。建议复习相关教材并通过模拟练习巩固所学概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值