【面试题】2024前端面试真题之JS篇(1)

  1. NodeList 等 DOM 集合类型
接收可迭代对象的原生语言特性包括
  1. for-of 循环
  2. 数组解构
  3. 扩展操作符
  4. Array.from()
  5. 创建Set
  6. 创建Map
  7. Promise.all()接收由Promise组成的可迭代对象
  8. Promise.race()接收由Promise组成的可迭代对象
  9. yield*操作符,在生成器中使用
迭代器协议

迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象

迭代器 API 使用 next()方法在可迭代对象中遍历数据,每次成功调用 next(),都会返回一个 IteratorResult 对象,其中包含迭代器返回的下一个值。

next()方法返回的迭代器对象 IteratorResult 包含两个属性

  1. done
    • 一个布尔值,表示是否还可以再次调用 next()取得下一个值
  2. value
    • 包含可迭代对象的下一个值

每个迭代器都表示对可迭代对象的一次性有序遍历

手写一个迭代器
function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length
        ? { value: array[nextIndex++], done: false }
        : { value: undefined, done: true };
    },
  };
}

代码测试

var it = makeIterator(["a", "b"]);

it.next(); // { value: "a", done: false }
it.next(); // { value: "b", done: false }
it.next(); // { value: undefined, done: true }


设计模式的分类

总体来说设计模式分为三大类:(C5S7B11)

  1. 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
  2. 结构型模式,共七种:适配器模式装饰器模式代理模式、外观模式、桥接模式、组合模式、享元模式。
  3. 行为型模式,共十一种:策略模式、模板方法模式、观察者模式/发布订阅模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

手写单例模式(创建模式)

let CreateSingleton = (function(){
    let instance;
    return function(name) {
        if (instance) {
            return instance;
        }
        this.name = name;
        return instance = this;
    }
})();
CreateSingleton.prototype.getName = function() {
    console.log(this.name);
}


代码测试

let Winner = new CreateSingleton('Winner');
let Looser = new CreateSingleton('Looser');

console.log(Winner === Looser); // true
console.log(Winner.getName());  // 'Winner'
console.log(Looser.getName());  // 'Winner'


手写观察者模式(行为模式)

// 定义observe
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);


const observable = obj => new Proxy(obj, {
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    // notify
    queuedObservers.forEach(observer => observer());
    return result;
  }
});


代码测试


obj = observable({
  name:'789'
})

observe(function test(){
  console.log('触发了')
})

obj.name ="前端柒八九"
// 触发了
// 前端柒八九

手写发布订阅 (行为模式)

class Observer {
  caches = {}; // 事件中心
  
  // eventName事件名-独一无二, fn订阅后执行的自定义行为
  on (eventName, fn){ 
    this.caches[eventName] = this.caches[eventName] || [];
    this.caches[eventName].push(fn);
  }
  
  // 发布 => 将订阅的事件进行统一执行
  emit (eventName, data) { 
    if (this.caches[eventName]) {
      this.caches[eventName]
      .forEach(fn => fn(data));
    }
  }
  // 取消订阅 => 若fn不传, 直接取消该事件所有订阅信息
  off (eventName, fn) { 
    if (this.caches[eventName]) {
      const newCaches = fn 
        ? this.caches[eventName].filter(e => e !== fn) 
        : [];
      this.caches[eventName] = newCaches;
    }
  }

}

代码测试

ob = new Observer();

l1 = (data) => console.log(`l1_${data}`)
l2 = (data) => console.log(`l2_${data}`)

ob.on('event1',l1)
ob.on('event1',l2)

//发布订阅
ob.emit('event1',789) 
// l1_789
// l2_789

// 取消,订阅l1
ob.off('event1',l1)

ob.emit('event1',567)
//l2_567

观察者模式 VS 发布订阅模式

【面试题】2024前端面试真题之JS篇(1)_第1张图片

  1. 从表面上看:
    • 观察者模式里,只有两个角色 —— 观察者 + 被观察者
    • 而发布订阅模式里,却不仅仅只有发布者和订阅者两个角色,还有一个经常被我们忽略的 —— {经纪人|Broker}
  2. 往更深层次讲:
    • 观察者和被观察者,是松耦合的关系
    • 发布者和订阅者,则完全不存在耦合
  3. 从使用层面上讲:
    • 观察者模式,多用于单个应用内部
    • 发布订阅模式,则更多的是一种{跨应用的模式|cross-application pattern} ,比如我们常用的消息中间件

WebGL和canvas的关系

  • Canvas就是画布,只要浏览器支持,可以在canvas上获取2D上下文3D上下文,其中3D上下文一般就是WebGL,当然WebGL也能用于2D绘制,并且WebGL提供硬件渲染加速,性能更好。
  • 但是 WEBGL 的支持性caniuse还不是特别好,所以在不支持 WebGL 的情况下,只能使用 Canvas 2D api,注意这里的降级不是降到 Canvas,它只是一个画布元素,而是降级使用 浏览器提供的 Canvas 2D Api,这就是很多库的兜底策略,如 Three.jsPIXI 等

CommonJS和ES6 Module的区别

  1. CommonJS 是同步加载模块,ES6是异步加载模块
    • CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。
    • 浏览器加载 ES6 模块是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本
  2. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
    • CommonJS

你可能感兴趣的:(前端,面试,javascript)