前端入门到入土?(二)

简介: 前端入门到入土?(二)

前言

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

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 属性来实现的,该属性指向该对象的原型。


后言

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


目录
相关文章
|
2月前
|
Web App开发 缓存 前端开发
前端性能优化:从入门到精通
【2月更文挑战第3天】
50 1
|
4月前
|
前端开发 JavaScript
前端JavaScript入门-day08-正则表达式
前端JavaScript入门-day08-正则表达式
37 0
|
5月前
|
前端开发
前端菜鸟之SASS入门笔记
前端菜鸟之SASS入门笔记
47 0
|
6月前
|
JSON 前端开发 JavaScript
前端AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(一)
前端AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(一)
522 0
|
13天前
|
移动开发 前端开发 JavaScript
CSS选择器 前端开发入门笔记(十)
CSS选择器 前端开发入门笔记(十)
19 1
|
13天前
|
前端开发 搜索推荐 数据安全/隐私保护
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
20 1
|
17天前
|
JavaScript 前端开发 API
游戏开发入门:Python后端与Vue前端的协同工作方式
【4月更文挑战第11天】使用Python后端(Flask或Django)和Vue.js前端开发游戏变得流行,能提高开发效率和可维护性。本文指导如何构建这样的项目,包括设置环境、创建虚拟环境、搭建后端API及前端Vue组件,强调前后端协作和API接口的重要性。这种架构促进团队合作,提升代码质量和游戏体验。
|
2月前
|
前端开发 JavaScript API
前端秘法番外篇----学完Web API,前端才能算真正的入门
前端秘法番外篇----学完Web API,前端才能算真正的入门
|
6月前
|
JSON JavaScript 前端开发
前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS进阶(四)完结撒花✿✿ヽ(°▽°)ノ✿
前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS进阶(四)完结撒花✿✿ヽ(°▽°)ノ✿
535 0
|
2月前
|
前端开发 JavaScript
从零开始学习前端开发:HTML、CSS、JavaScript入门指南
【2月更文挑战第1天】本文将带领读者从零开始学习前端开发,介绍HTML、CSS和JavaScript的基础知识与应用,帮助读者快速入门前端开发领域。
65 1