前端入门到入土?(二)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 前端入门到入土?(二)

前言

后序我会更新一系列的前端面试题,感兴趣的可以关注一手

vue2和vue3的响应式有什么区别?

vue2

Vue 2 的响应式原理是通过使用 Object.defineProperty() 方法来劫持对象的属性,从而实现对数据的监听和响应。

分为以下几点

1.数据劫持

  • 在 Vue 初始化过程中,会遍历 data 中的所有属性,并使用 Object.defineProperty() 方法将它们转换为 getter 和 setter。通过这种方式,Vue 实现了对数据属性的劫持。
var data = { msg: 'Hello, Vue!' };
Object.defineProperty(data, 'msg', {
  get() {
    console.log('获取数据');
    return val;
  },
  set(newVal) {
    console.log('设置数据');
    val = newVal;
  },
});


在上述示例中,我们通过 Object.defineProperty() 方法定义了一个名为 ‘msg’ 的属性,并为它提供了 getter 和 setter。当我们读取 ‘msg’ 属性时,会执行 get() 函数;当我们修改 ‘msg’ 属性时,会执行 set() 函数。


2.依赖收集


  • 每个属性的 getter 都会在初始化时被调用,当获取到该属性的值时,会触发对应的 getter 函数。在 getter 函数中,Vue 会将当前正在获取的属性与 Watcher 进行关联,将 Watcher 添加到依赖列表中。
var dep = new Dep();
var watcher = new Watcher();
Object.defineProperty(data, 'msg', {
  get() {
    if (Dep.target) {
      dep.addSub(Dep.target);
    }
    return val;
  },
  set(newVal) {
    val = newVal;
    dep.notify();
  },
});


在上述示例中,我们定义了一个名为 ‘dep’ 的依赖管理器,以及一个名为 ‘watcher’ 的监听器。当 ‘msg’ 属性被获取时,会判断当前是否存在正在监听的 Watcher 对象,如果存在则将该 Watcher 添加到 ‘dep’ 的订阅列表中。


3.派发更新


  • 当修改了被劫持的属性值时,会触发对应的 setter 函数。在 setter 函数中,Vue 会通知依赖列表中的所有 Watcher 对象进行更新操作。这样,所有依赖该属性的 Watcher 都会得到通知并执行相应的更新操作。


var Dep = function() {
  this.subs = [];
};
Dep.prototype.addSub = function(sub) {
  this.subs.push(sub);
};
Dep.prototype.notify = function() {
  for (var i = 0; i < this.subs.length; i++) {
    this.subs[i].update();
  }
};


在上述示例中,我们定义了一个名为 ‘Dep’ 的依赖管理器,并添加了添加订阅者和通知订阅者更新的方法。当属性值发生改变时,会调用 ‘Dep’ 的 notify() 方法,遍历依赖列表并触发每个 Watcher 对象的 update() 方法。


!!!值得注意的是:Vue 2 的响应式原理仅适用于初始化过程中已经存在的属性,无法监听新添加的属性或删除的属性。如果需要监听动态添加或删除的属性,可以使用 Vue.set() 或 Vue.delete() 进行操作。

vue3

Vue 3 的响应式原理是使用 Proxy 对象实现的。Proxy 是 ES6 引入的一个功能,它可以拦截并自定义对象的操作。


在 Vue 3 中,当你创建一个响应式对象时,Vue 内部会使用 Proxy 对象来包装这个对象。Proxy 对象通过拦截对响应式对象的访问,使得 Vue 可以追踪到对响应式对象的修改,并触发相应的更新。


在 Vue 3 中,使用 reactive() 函数和 Proxy 对象来创建响应式对象。具体而言,当你通过 reactive() 函数将一个普通对象转换为响应式对象时,Vue 会使用 Proxy 对象对这个对象进行包装。


响应式对象的创建:


import { reactive } from 'vue';
const state = reactive({
  count: 0,
  name: 'John',
});


上述代码中,以 reactive() 函数将普通对象 { count: 0, name: ‘John’ } 转换为一个响应式对象 state。现在,当你修改 state 中的属性时,Vue 会捕获到这个操作,并触发相应的更新。


如何触发更新?


当你修改了响应式对象的属性时,Vue 会根据依赖收集器(Dependency Tracking)中的关联关系,将相关的代码块进行重新执行,进而更新视图。


依赖收集器的建立:


在 Vue 3 中,可以使用 effect() 函数来建立依赖收集器。effect() 函数接收一个函数作为参数,这个函数内部可能会访问响应式对象的属性。当响应式对象的属性发生变化时,与其相关联的 effect() 函数会重新执行。


示例:


import { reactive, effect } from 'vue';
const state = reactive({
  count: 0,
});
effect(() => {
  console.log('Count changed:', state.count);
});


上述代码中,我们通过 effect() 函数创建了一个依赖收集器。在 effect() 函数内部,我们访问了 state.count 属性。当 state.count 属性发生变化时,在控制台输出相应的消息。


响应式对象的属性访问和更新:


使用响应式对象的属性与普通对象类似,可以通过点符号或方括号来访问和更新属性的值。

示例:


console.log(state.count); // 访问 count 属性的值
state.count = 1; // 修改 count 属性的值


上述代码中,我们访问了响应式对象 state 的 count 属性,并将其修改为新的值。


!!!需要注意的是,响应式系统只能追踪到在初始化过程中访问过的属性。如果后续新增属性需要响应式,可以使用 Vue.set() 方法或者直接赋值一个新的响应式对象。


vue2和vue3的响应式的区别?

1.Proxy vs Object.defineProperty:


  • Vue 2 使用了 Object.defineProperty 来实现响应式系统,它可以拦截对属性的读取和修改操作。
  • Vue 3 使用了更强大的原生 JavaScript API Proxy 来实现响应式系统,它可以拦截更多类型的操作,包括新增和删除属性。


2.性能优化:


  • Vue 2 每个组件实例都有独立的观察者(Watcher),当数据变化时,会遍历所有观察者进行更新,这在大规模数据变动时可能导致性能问题。
  • Vue 3 使用基于 Proxy 的跟踪机制,可以精确追踪响应式对象的依赖,只更新与依赖相关的部分,提高了性能。


3.依赖收集:


  • Vue 2 通过在 getter 中收集依赖,在 setter 中触发依赖更新。它使用了一个全局的依赖管理器 Dep 来维护依赖关系。
  • Vue 3 使用了一个更轻量级的依赖收集器,它是基于 Proxy 和 Map 数据结构来构建的。每个响应式对象都有一个关联的 Map,用于存储属性和对应的依赖。


4.生命周期钩子:


  • Vue 2 中,可以在 beforeUpdate 生命周期钩子中执行一些副作用操作。但在 setup() 函数中无法执行副作用操作,需要使用 created 钩子。
  • Vue 3 中,setup() 函数是组件的入口点,可以在其中执行副作用操作,而且没有 beforeUpdate 钩子。


5.Computed 和 Watch:


  • Vue 2 中的计算属性(computed)和侦听器(watch)是通过定义在 computed 和 watch 选项中的函数来实现的。
  • Vue 3 中的计算属性(computed)和侦听器(watch)可以直接在 setup() 函数中使用,而不需要特定的选项。


6.总结


总的来说,Vue 3 的响应式系统经过重新设计和优化,使用了 Proxy 来取代 Object.defineProperty,提供了更好的性能和更广泛的拦截能力。它还引入了更轻量级的依赖收集器,并对生命周期钩子和计算属性、侦听器做了一些改进。这些变化使得 Vue 3 更加高效、灵活和易用。

作用域,作用域链?

作用域


  • 作用域(Scope)是指在程序中定义变量的区域,这些变量在该区域内可被访问。作用域规定了变量的可见性和生命周期。


作用域链


  • 作用域链(Scope Chain)是指在一个嵌套的函数中,每个函数都有自己的作用域,并且可以访问上层函数中定义的变量。当访问一个变量时,解释器会先在当前函数的作用域中查找该变量,如果找不到,则继续向上一层作用域查找,直至找到变量或抵达全局作用域。


作用域链的执行机制


  • 具体来说,当一个函数被创建时,会创建一个保存变量和函数声明的内部对象,称为“活动对象”(Activation Object)。函数执行时,会创建一个称为“执行环境”(Execution Context)的内部对象,它包含了当前执行中的代码所需的全部信息,包括变量、函数等。
  • 在作用域链中,每个执行环境都有一个关联的“变量对象”(Variable Object),它用于存储该执行环境中定义的变量和函数。执行环境的变量对象作为作用域链的一部分,形成了一个链式结构。
  • 当访问一个变量时,解释器首先在当前执行环境的变量对象中查找,如果找不到,则沿着作用域链向上一级执行环境的变量对象中查找,直到找到变量或抵达全局执行环境。如果在最顶层的全局执行环境中也找不到该变量,则视为未定义


作用域链的底层原理是什么?

1.词法环境(Lexical Environment):


  • 词法环境是一个存储变量和函数声明的数据结构,每个词法环境关联着一个特定的执行上下文(Execution Context)。
    每次函数创建时,都会生成一个新的词法环境,并将其绑定到这个函数的执行上下文中。
    词法环境以嵌套的方式组成了作用域链,形成了一个链式结构。每个词法环境都有一个指向父级词法环境的引用,这样就形成了一条从内到外的链接关系。


2.标识符解析(Identifier Resolution):


  • 当访问一个变量时,解释器会在当前词法环境的变量记录中搜索该变量。如果找不到该变量,则会沿着作用域链向上一级词法环境查找,直到找到变量或抵达全局词法环境。如果在最顶层的全局词法环境中也找不到该变量,则视为未定义。


具体流程

在实际的查找过程中,当解释器遇到一个变量引用时,会根据当前的词法环境和作用域链进行标识符解析。如果在当前词法环境中找到了对应的变量,则返回该变量的值;否则,解释器会按照作用域链的顺序依次查找,直到找到变量或抵达全局词法环境。


需要注意的是,一旦变量被找到后,解释器会停止进一步的查找,这就是标识符解析的过程。通过作用域链的层层嵌套和标识符解析的机制,JavaScript 实现了变量在不同作用域中的访问和使用。

原型,原型链?

原型(Prototype):


  • 在 JavaScript 中,每个对象都有一个原型,它是一个对象或者 null。
    对象可以通过原型来共享属性和方法,当访问对象的属性或方法时,如果该对象自身没有找到对应的属性或方法,就会去原型中查找。
    通过原型,可以实现对象之间的属性和方法的共享,减少内存占用并提高代码的可维护性。


原型链(Prototype Chain):


  • 原型链是一种由原型对象组成的层级结构,用于查找对象的属性和方法。
  • 当访问对象的属性或方法时,如果该对象自身没有找到对应的属性或方法,就会沿着原型链向上查找,直到找到该属性或方法或者抵达原型链的顶端(即 Object.prototype)。
  • 原型链的形成是通过每个对象的 proto 属性来实现的,该属性指向该对象的原型。


后言

创作不易,要是本文章对广大读者有那么一点点帮助 不妨三连支持一下,您的鼓励就是博主创作的动力


目录
相关文章
|
1月前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
245 2
|
2月前
|
前端开发
【前端web入门第四天】02 CSS三大特性+背景图
本文详细介绍了CSS的三大特性:继承性、层叠性和优先级,并深入讲解了背景图的相关属性,包括背景属性、背景图的平铺方式、位置设定、缩放、固定以及复合属性。其中,继承性指子元素自动继承父元素的文字控制属性;层叠性指相同属性后定义覆盖前定义,不同属性可叠加;优先级涉及选择器权重,包括行内样式、ID选择器等。背景图部分则通过具体示例展示了如何设置背景图像的位置、大小及固定方式等。
256 91
|
7天前
|
编解码 前端开发 JavaScript
从入门到精通:揭秘前端开发中那些不为人知的优化秘籍!
前端开发是充满无限可能的领域,从初学者到资深专家,每个人都追求更快、更稳定、更用户体验友好的网页。本文介绍了四大优化秘籍:1. HTML的精简与语义化;2. CSS的优雅与高效;3. JavaScript的精简与异步加载;4. 图片与资源的优化。通过这些方法,可以显著提升网页性能和用户体验。
13 3
|
12天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
12天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
18 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
2月前
|
JavaScript 前端开发 小程序
一小时入门Vue.js前端开发
本文是作者关于Vue.js前端开发的快速入门教程,包括结果展示、参考链接、注意事项以及常见问题的解决方法。文章提供了Vue.js的基础使用介绍,如何安装和使用cnpm,以及如何解决命令行中遇到的一些常见问题。
一小时入门Vue.js前端开发
|
1月前
|
自然语言处理 资源调度 前端开发
前端大模型入门(四):不同文本分割器对比和效果展示-教你如何根据场景选择合适的长文本分割方式
本文详细介绍了五种Langchain文本分割器:`CharacterTextSplitter`、`RecursiveCharacterTextSplitter`、`TokenTextSplitter`、`MarkdownTextSplitter` 和 `LatexTextSplitter`,从原理、优缺点及适用场景等方面进行了对比分析,旨在帮助开发者选择最适合当前需求的文本分割工具,提高大模型应用的处理效率和效果。
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
前端大模型入门(三):编码(Tokenizer)和嵌入(Embedding)解析 - llm的输入
本文介绍了大规模语言模型(LLM)中的两个核心概念:Tokenizer和Embedding。Tokenizer将文本转换为模型可处理的数字ID,而Embedding则将这些ID转化为能捕捉语义关系的稠密向量。文章通过具体示例和代码展示了两者的实现方法,帮助读者理解其基本原理和应用场景。
190 1
|
1月前
|
人工智能 前端开发 JavaScript
前端大模型入门(二):掌握langchain的核心Runnable接口
Langchain.js 是 Langchain 框架的 JavaScript 版本,专为前端和后端 JavaScript 环境设计。最新 v0.3 版本引入了强大的 Runnable 接口,支持灵活的执行方式和异步操作,方便与不同模型和逻辑集成。本文将详细介绍 Runnable 接口,并通过实现自定义 Runnable 来帮助前端人员快速上手。
|
1月前
|
存储 JavaScript 前端开发
前端开发:Vue.js入门与实战
【10月更文挑战第9天】前端开发:Vue.js入门与实战