No15.精选前端面试题,享受每天的挑战和学习

简介: No15.精选前端面试题,享受每天的挑战和学习

什么是Object.defineProperty?说下参数,返回值,以及提供代码案例进行说明

Object.defineProperty 是 JavaScript 中的一个方法,用于定义或修改对象的属性

它允许我们精确地控制属性的特性、值和行为。

该方法的语法如下:

Object.defineProperty(obj, prop, descriptor)

其中,参数的含义如下:

  • obj:要在其上定义属性的对象。
  • prop:要定义或修改的属性的名称。
  • descriptor:描述符对象,用于定义或修改属性的特性。

返回值:被传递给函数的对象。

下面是一个示例说明,展示了如何使用 Object.defineProperty 来定义或修改对象的属性:

// 定义一个空对象
const person = {};
// 使用 Object.defineProperty 定义属性
Object.defineProperty(person, 'name', {
  value: 'John',
  writable: false, // 不可写
  enumerable: true, // 可枚举
  configurable: false // 不可配置
});
console.log(person.name); // 输出: "John"
person.name = 'Mike'; // 无法修改属性的值,因为 writable 被设置为 false
console.log(person.name); // 输出: "John"
// 修改属性的特性
Object.defineProperty(person, 'age', {
  value: 25,
  writable: true,
  enumerable: false, // 不可枚举
  configurable: true
});
console.log(person.age); // 输出: 25
// 遍历对象的属性
for (let key in person) {
  console.log(key); // 只输出 "name"
}
// 删除属性
delete person.age; // 无法删除属性,因为 configurable 被设置为 false
console.log(person.age); // 输出: 25

在上面的示例中,我们首先使用 Object.defineProperty 定义了一个名为 name 的属性,并指定了它的特性。然后,我们尝试修改该属性的值,但由于 writable 被设置为 false,所以修改无效。随后,我们使用 Object.defineProperty 修改了现有属性 age 的特性,将它设置为不可枚举。最后,我们尝试删除该属性,但由于 configurable 被设置为 false,所以删除操作也无效。

通过使用 Object.defineProperty,我们可以在对象上创建或修改属性,并且能够精确地控制属性的行为和特性。

说下订阅/发布模式(subscribe & publish),应用,特点,给出代码案例

订阅/发布模式(Subscribe & Publish),也被称为观察者模式(Observer Pattern),是一种常见的软件设计模式。它用于实现对象间的一对多依赖关系,当一个对象(被观察者)发生改变时,它的所有观察者都会收到通知并自动更新。

应用:

  • 在前端开发中,订阅/发布模式常用于实现事件系统或消息传递机制
  • 在异步编程中,可以使用订阅/发布模式来处理回调函数和事件的处理

特点:

  • 解耦性:被观察者和观察者之间相互不依赖,可以独立进行扩展或修改。
  • 松散耦合:被观察者和观察者之间通过订阅/发布的方式进行通信,彼此之间没有直接的引用关系。
  • 可重用性:一个被观察者可以拥有多个观察者,而观察者也可以同时订阅多个被观察者。
  • 灵活性:可以随时增加或移除观察者,以及动态地通知观察者。

以下是一个简单的订阅/发布模式的示例代码:

// 创建一个事件管理器
const eventManager = {
  events: {},
  subscribe(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  },
  publish(event, data) {
    if (!this.events[event]) {
       return;
    }
    this.events[event].forEach(callback => {
      callback(data);
    });
  },
  unsubscribe(event, callback) {
    if (!this.events[event]) {
      return;
    }
    const index = this.events[event].indexOf(callback);
    if (index !== -1) {
      this.events[event].splice(index, 1);
    }
  }
};
// 创建观察者
const observer1 = data => {
  console.log('Observer 1:', data);
};
const observer2 = data => {
  console.log('Observer 2:', data);
};
// 订阅事件
eventManager.subscribe('event1', observer1);
eventManager.subscribe('event1', observer2);
// 发布事件
eventManager.publish('event1', 'Hello, subscribers!');
// 输出:
// Observer 1: Hello, subscribers!
// Observer 2: Hello, subscribers!
// 取消订阅
eventManager.unsubscribe('event1', observer2);
// 再次发布事件
eventManager.publish('event1', 'Hello again!');
// 输出:
// Observer 1: Hello again!

在示例中,我们首先创建了一个事件管理器 eventManager 对象。它包含了 subscribe 订阅方法、publish 发布方法和 unsubscribe 取消订阅方法。通过调用 subscribe 方法,我们可以将观察者函数注册到特定的事件上。然后,通过调用 publish 方法,我们可以向所有订阅了该事件的观察者们发送通知。最后,我们可以使用 unsubscribe 方法来取消特定事件上的观察者订阅。

这样,当我们发布一个事件时,所有订阅了该事件的观察者都会自动接收到通知并执行相应的操作。这种订阅/发布模式的设计可以帮助我们实现松散耦合、高度可扩展和灵活的应用程序结构。

双向绑定是如何实现的

双向绑定(Two-Way Binding)是一种实现数据模型和用户界面之间的同步更新的机制。它使得当数据模型发生变化时,用户界面自动更新,同时也允许用户通过界面进行操作并将更改反映回数据模型。

双向绑定的实现方式有多种,以下是其中两种常见的方法:

  1. 观察者模式(Observer Pattern):在这种实现方式中,通过观察者模式来建立数据模型和界面之间的联系。当数据模型的属性发生变化时,触发一个事件或通知所有相关的观察者。这些观察者监听并响应这些事件,并更新用户界面上的相应部分。同时,当用户在界面上进行了修改时,也会触发相应的事件或通知观察者,从而更新数据模型中的属性。
  2. 数据绑定框架(Data Binding Framework):现代的前端框架,如Angular、React和Vue等,提供了内置的双向数据绑定机制。这些框架通过使用虚拟DOM(Virtual DOM)或其他技术,可以自动追踪数据模型的变化,并在必要的时候更新用户界面。它们通常提供了专门的语法或指令,用于声明和操作双向绑定关系。当数据模型发生变化时,框架会自动更新相应的界面元素;而用户在界面上的交互操作也会被框架捕获并反映回数据模型中。

双向绑定的实现要点:

  • 在数据模型和用户界面之间建立连接,使它们能够相互感知和响应变化。
  • 监听数据模型的变化或用户界面的交互事件,并触发相应的更新操作。
  • 确保更新操作是高效的,避免不必要的重复计算和渲染。

通过使用双向绑定,我们可以在开发过程中更方便地管理数据和界面的同步更新,减少手动处理更新逻辑的工作量,提高开发效率。然而,在使用双向绑定的同时,我们也需要注意避免滥用,合理选择适合的场景和工具,并考虑其对性能、维护性和可扩展性的影响。

说下vue的双向绑定原理和机制

Vue.js 是一种流行的前端框架,它采用了基于数据驱动的双向绑定机制。Vue的双向绑定原理和机制如下:

  1. 数据劫持(Data Observation):Vue 使用了一个名为 “响应式系统” 的机制来实现双向绑定。在创建 Vue 实例时,Vue 会对数据对象进行递归遍历,使用 Object.defineProperty 方法将对象的属性转化为“可观察”对象。这样,当访问这些属性时,Vue 能够跟踪到这些属性的读取与修改操作。
  2. 模板解析(Template Parsing):Vue 使用模板语法来声明用户界面,通过解析模板语法,Vue 将模板转换为虚拟DOM(Virtual DOM)结构。在模板中,通过使用指令(如 v-model)或插值表达式({{}})绑定数据到界面元素上。
  3. 响应式更新(Reactive Updates):当数据对象的属性被访问时,Vue 能够感知到这一访问操作,并建立一个依赖关系。当属性的值发生变化时,Vue 能够通知所有相关的依赖项进行更新。
  4. 依赖追踪(Dependency Tracking):Vue 使用了一个 Watcher 监听器来追踪属性的依赖关系。每个依赖项都维护一个属于自己的 Watcher 实例,Watcher 实例会存储依赖项以及相关的更新函数。当属性的值发生变化时,关联的 Watcher 实例会被通知,然后触发相应的更新函数。
  5. 批量异步更新(Batched Asynchronous Updates):Vue 采用了批量异步更新的策略,即将对数据的多次修改合并为一次更新操作,避免频繁地更新界面,提高性能。Vue 使用事件循环机制,在下一个事件循环中对所有的 Watcher 进行更新。

通过上述机制,Vue 实现了数据模型和用户界面之间的双向绑定。当数据模型发生变化时,Vue 能够追踪到这些变化,并自动更新相关的界面元素。同时,当用户在界面上进行操作时,Vue 也能够捕获并反映回数据模型中。

需要注意的是,双向绑定不是无所不在的,只有在受到 Vue 监听的数据属性上才会实现双向绑定。而且,Vue 仅在指令或插值表达式中使用 v-model 时才会进行双向绑定,其他情况下,Vue 并未实现双向绑定。

说下数据劫持

数据劫持(Data Observation)是 Vue.js 实现双向绑定的一部分,它通过劫持(或拦截)对象的属性访问操作,以实现对属性的观察和响应。Vue 使用 Object.defineProperty 方法来实现数据劫持。

下面是一个简单的示例代码,演示了数据劫持的实现:

// 定义一个对象
const data = { name: 'Alice', age: 25 };
// 对象属性的变化需要被观察和响应
function observe(obj) {
  // 遍历对象的所有属性
  for (let key in obj) {
    let value = obj[key];
    // 创建一个专门用于属性观察的Dep对象
    const dep = new Dep();
    // 使用 Object.defineProperty 对属性进行劫持
    Object.defineProperty(obj, key, {
      get() {
        // 收集依赖,将观察者添加到Dep中
        if (Dep.target) {
          dep.addSub(Dep.target);
        }
        return value;
      },
      set(newValue) {
        if (value !== newValue) {
          value = newValue;
          // 属性变化时,通知Dep中的所有观察者进行更新
          dep.notify();
        }
      }
    });
  }
}
// 添加一个全局变量,用于存储当前的观察者(Watcher)
Dep.target = null;
// 依赖对象,用于存储相关的观察者(Watcher)
class Dep {
  constructor() {
    this.subs = []; // 存储观察者的数组
  }
  // 添加观察者
  addSub(sub) {
    this.subs.push(sub);
  }
  // 通知所有观察者进行更新
  notify() {
    for (let sub of this.subs) {
      sub.update();
    }
  }
}
// 观察者(Watcher)对象
class Watcher {
  constructor(obj, key, callback) {
    this.obj = obj;
    this.key = key;
    this.callback = callback;
    // 将当前观察者指定为全局的Dep.target
    Dep.target = this;
    this.value = this.obj[this.key]; // 触发属性的getter,收集依赖
    Dep.target = null; // 重置Dep.target
  }
  // 更新回调函数
  update() {
    const newValue = this.obj[this.key];
    this.callback(newValue);
  }
}
// 对 data 对象进行观察
observe(data);
// 创建一个观察者,并传入更新回调函数
const watcher = new Watcher(data, 'name', (newValue) => {
  console.log('Name changed:', newValue);
});
// 修改 data 对象的 name 属性
data.name = 'Bob'; // 输出:Name changed: Bob

在上面的示例中,我们定义了一个对象 data,其中有一个属性 name。通过调用 observe 函数来对 data 对象进行观察,该函数会遍历对象的所有属性,并使用 Object.defineProperty 劫持属性的访问操作。

在属性的 getter 中,我们会将观察者(Watcher)添加到属性的依赖列表中。在属性的 setter 中,如果属性的值发生变化,我们会通知所有依赖该属性的观察者进行更新。

然后,我们创建了一个观察者(Watcher)对象 watcher,并传入一个更新回调函数。通过修改 data 对象的 name 属性,我们可以看到控制台输出了更新后的值。

这就是数据劫持的基本原理,它允许我们追踪对象属性的访问和修改,从而实现了双向绑定的能力。


相关文章
|
12天前
|
Web App开发 前端开发 Linux
「offer来了」浅谈前端面试中开发环境常考知识点
该文章归纳了前端开发环境中常见的面试知识点,特别是围绕Git的使用进行了详细介绍,包括Git的基本概念、常用命令以及在团队协作中的最佳实践,同时还涉及了Chrome调试工具和Linux命令行的基础操作。
「offer来了」浅谈前端面试中开发环境常考知识点
|
2天前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
11 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
2月前
|
存储 XML 移动开发
前端大厂面试真题
前端大厂面试真题
|
1月前
|
网络协议 算法 数据库
|
2月前
|
前端开发 Java 编译器
【前端学java】如何从前端视角快速学习Maven
【8月更文挑战第12天】如何从前端视角快速学习Maven
44 2
【前端学java】如何从前端视角快速学习Maven
|
2月前
|
前端开发 JavaScript API
前端框架Vue------>第二天学习(1)插槽
这篇文章介绍了Vue框架中插槽(slot)的概念和用法,以及如何在组件中使用自定义事件进行父子组件间的通信。
前端框架Vue------>第二天学习(1)插槽
|
2月前
|
前端开发 算法 网络协议
如何学习计算机基础知识,打好前端和网络安全的基础
如何学习计算机基础知识,打好前端和网络安全的基础
39 4
|
2月前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
【8月更文挑战第18天】
40 2
|
2月前
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
31 0
|
2月前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
44 个 React 前端面试问题

热门文章

最新文章