当前位置: 首页 > news >正文

【jsvue】联合gtp仿写一个简单的vue框架,以此深度学习JavaScript

用 gtp 学习 Vue 生命周期的原理

lifecycle.js

function Vue(options) {// 将选项保存到实例的 $options 属性中this.$options = options;// 若存在 beforeCreate 钩子函数,则调用之if (typeof options.beforeCreate === 'function') {options.beforeCreate.call(this);}// 判断并保存 data 数据对象this._data = typeof options.data === 'function' ? options.data() : options.data;// 将 data 对象中的属性代理到 Vue 实例上this._proxyData();// 若存在 created 钩子函数,则调用之if (typeof options.created === 'function') {options.created.call(this);}// 执行挂载操作this.$mount(options.el);
}Vue.prototype.$mount = function(el) {// 将目标元素保存到实例的 $el 属性中this.$el = document.querySelector(el);// 若存在 beforeMount 钩子函数,则调用之if (typeof this.$options.beforeMount === 'function') {this.$options.beforeMount.call(this);}// 调用 render 方法渲染模板this.render();// 若存在 mounted 钩子函数,则调用之if (typeof this.$options.mounted === 'function') {this.$options.mounted.call(this);}
};Vue.prototype._proxyData = function() {var self = this;// 遍历 data 对象的属性,并将其代理到 Vue 实例上Object.keys(this._data).forEach(function(key) {Object.defineProperty(self, key, {get: function() {return self._data[key];},set: function(newValue) {self._data[key] = newValue;// 若存在 beforeUpdate 钩子函数,则调用之if (typeof self.$options.beforeUpdate === 'function') {self.$options.beforeUpdate.call(self);}// 重新渲染模板self.render();// 若存在 updated 钩子函数,则调用之if (typeof self.$options.updated === 'function') {self.$options.updated.call(self);}}});});
};Vue.prototype.render = function() {// 调用 render 函数生成模板字符串,并更新目标元素的内容if (typeof this.$options.render === 'function') {this.$el.innerHTML = this.$options.render.call(this);}
};// 使用示例
var app = new Vue({el: '#app',  // Vue 实例挂载的目标元素data: {      // 数据对象message: 'Hello, Vue!'    // 文本数据},beforeCreate: function() {console.log('beforeCreate hook');},created: function() {console.log('created hook');},beforeMount: function() {console.log('beforeMount hook');},mounted: function() {console.log('mounted hook');},beforeUpdate: function() {console.log('beforeUpdate hook');},updated: function() {console.log('updated hook');},render: function() {return '<p>' + this.message + '</p>';}
});

注解:
this.$options.beforeMount.call(this);与 this.$options.beforeMount();有什么区别:

  • call(this) 的作用是将当前对象(this)作为参数传递给 beforeMount 方法,使得在 beforeMount 方法内部可以通过 this 访问到当前对象的上下文
  • 直接调用了 beforeMount 方法,没有指定上下文 

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Vue</title></head><body><div id="app"></div><script src="./lifecycle.js"></script></body>
</html>

在浏览器查看渲染结果,并在控制台查看日志输出

另外,我们可以在控制输入 app.message = 'ChatGPT' 来验证数据绑定以及页面更新机制

效果图:

用 gtp 学习 Vue 模板语法和指令的原理

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"></div><script>// 定义 Vue 类function Vue(options) {// 保存选项为实例的属性this.$options = options;// 判断传入的 data 是函数还是对象,并保存到 _data 属性上this._data = typeof options.data === 'function' ? options.data() : options.data;// 调用编译模板的方法this._compileTemplate();}// 原型方法:编译模板Vue.prototype._compileTemplate = function () {var self = this;// 获取模板字符串var template = this.$options.template || '';// 定义一个函数用于对表达式进行求值var evalExpression = function (expression) {// 使用 with 关键字将 data 对象的属性添加到作用域中,并求解表达式with (self._data) return eval(expression);}// 将模板中的双括号表达式替换成 data 对应属性的值var compiledTemplate = template.replace(/\{\{(.*?)\}\}/g, function (match, expression) {var value = evalExpression(expression);return value !== undefined ? value : '';});// 获取目标元素,并将编译后的模板插入其中var element = document.querySelector(this.$options.el);element.innerHTML = compiledTemplate.trim();// 处理带有 v-model 属性的元素,实现数据的双向绑定element.querySelectorAll('[v-model]').forEach(function (element) {var value = element.getAttribute('v-model');element.value = self._data[value];element.addEventListener('input', function (event) {self._data[value] = event.target.value;});});// 处理带有 v-text 属性的元素,实现数据的单向绑定element.querySelectorAll('[v-text]').forEach(function (element) {var value = element.getAttribute('v-text');element.textContent = self._data[value];// 使用 defineProperty 方法定义 data 对象对应属性的 getter 和 setterObject.defineProperty(self._data, value, {get: function () {return this[value]},set: function (newValue) {element.textContent = newValue;}});});};// 使用示例var app = new Vue({el: '#app',  // Vue 实例挂载的目标元素data: {      // 数据对象message: 'Hello, Vue!',    // 文本数据inputValue: 'ChatGPT'      // 输入数据},template:     // 模板字符串`<div><p>{{ message }}</p><input v-model="inputValue" type="text"><p v-text="inputValue"></p></div>`});</script>
</body></html>

效果图:

注解:

  • js中with 语句的作用

with语句的作用是简化代码,使得可以在该作用域内直接访问对象的属性和方法,而无需重复使用对象名字的前缀

var person = {name: 'Alice',age: 25,greet: function() {console.log('Hello, ' + this.name + '!');}
};with (person) {console.log(name);  // 直接访问属性,输出: Aliceconsole.log(age);   // 直接访问属性,输出: 25greet();            // 直接调用方法,输出: Hello, Alice!
}
  • template.replace(/\{\{(.*?)\}\}/g, function (match, expression) { ... })

是一个正则表达式替换的方法,用于处理模板中的双花括号表达式 {{expression}},回调函数接收两个参数:

  match:匹配到的整个字符串,即 {{expression}}

  expression:匹配到的表达式,即 expression

 用 gtp 学习 Vue 数据监听和计算属性的原理

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"></div><script>// 定义 Vue 类function Vue(options) {// 将 data、computed 和 watch 选项保存到实例中this._data = options.data;this._computed = options.computed;this._watch = options.watch;// 数据代理this._proxyData();// 创建计算属性this._createComputed();// 创建监听器this._createWatchers();}// 数据代理,将 data 中的属性代理到 Vue 实例上,实现直接访问和修改数据Vue.prototype._proxyData = function () {var self = this;Object.keys(this._data).forEach(function (key) {Object.defineProperty(self, key, {get: function () {return self._data[key];},set: function (newValue) {self._data[key] = newValue;}});});};// 创建计算属性Vue.prototype._createComputed = function () {var self = this;var computed = this._computed || {};Object.keys(computed).forEach(function (key) {Object.defineProperty(self, key, {get: function () {return computed[key].call(self);}});});};// 创建监听器Vue.prototype._createWatchers = function () {var self = this;var watch = this._watch || {};Object.keys(watch).forEach(function (key) {var callback = watch[key];var value = self._data[key];Object.defineProperty(self._data, key, {get: function () {return value;},set: function (newValue) {value = newValue;callback.call(self, newValue);}});});};// 使用示例// 创建一个 Vue 实例var app = new Vue({// 初始化数据data: {message: 'Hello, Vue!',firstName: 'John',lastName: 'Doe'},// 定义计算属性computed: {fullName: function () {return this.firstName + ' ' + this.lastName;}},// 定义监听器watch: {message: function (newValue) {console.log('Message changed:', newValue);}}});console.log(app.message);       // 输出: Hello, Vue!app.message = 'Hello, Vue.js!'; // 输出: Message changed: Hello, Vue.js!console.log(app.message);       // 输出: Hello, Vue.js!console.log(app.fullName);      // 输出: John Doeapp.message = 'New message';    // 输出: Message changed: New message</script>
</body></html>

效果图:

用 gtp 学习 Vue 事件处理和方法的原理

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"></div><script>// 定义事件总线类function EventBus() {this._events = {};}// 事件总线订阅方法,用于注册事件回调函数EventBus.prototype.on = function (eventName, callback) {if (!this._events[eventName]) {this._events[eventName] = [];}this._events[eventName].push(callback);};// 事件总线触发方法,用于触发事件并调用相应的回调函数EventBus.prototype.emit = function (eventName, payload) {if (this._events[eventName]) {this._events[eventName].forEach(function (callback) {callback(payload);});}};// 定义 Vue 类function Vue(options) {// 初始化数据this._data = typeof options.data === 'function' ? options.data() : options.data;// 记录方法this._methods = options.methods;// 创建事件总线实例this._eventBus = new EventBus();// 对数据进行代理,使得可以直接通过 this.xxx 访问和修改数据this._proxyData();// 对方法进行代理,使得可以通过 this.xxx 调用方法this._proxyMethods();}// 数据代理,将 data 中的属性添加到 Vue 实例中,实现直接访问和修改数据Vue.prototype._proxyData = function () {var self = this;Object.keys(this._data).forEach(function (key) {Object.defineProperty(self, key, {get: function () {return self._data[key];},set: function (newValue) {self._data[key] = newValue;}});});};// 方法代理,将 methods 中的方法添加到 Vue 实例中,实现通过 this.xxx 调用方法Vue.prototype._proxyMethods = function () {var self = this;var methods = this._methods;if (methods) {Object.keys(methods).forEach(function (key) {self[key] = methods[key].bind(self);});}};// 发布事件,触发相应的事件回调函数Vue.prototype.$emit = function (eventName, payload) {this._eventBus.emit(eventName, payload);};// 订阅事件,注册事件回调函数Vue.prototype.$on = function (eventName, callback) {this._eventBus.on(eventName, callback);};// 创建一个 Vue 实例var app = new Vue({// 初始化数据data: {message: 'Hello, Vue!'},// 定义方法methods: {greet: function () {this.$emit('greet', this.message);},updateMessage: function (newMessage) {this.message = newMessage;}},});// 注册 greet 事件的回调函数app.$on('greet', function (message) {console.log('Greet:', message);});// 调用 greet 方法,触发 greet 事件app.greet(); // 输出: Greet: Hello, Vue!// 调用 updateMessage 方法,修改 message 的值app.updateMessage('Hello, World!');// 再次调用 greet 方法,触发 greet 事件,并输出修改后的 messageapp.greet(); // 输出: Greet: Hello, World!</script>
</body></html>

用 gtp 学习 Vue 插槽(slot)的原理

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"></div><script>// 定义 Vue 构造函数function Vue(options) {this.$options = options;this._data = typeof options.data === 'function' ? options.data() : options.data;this._components = options.components || {};// 代理 data 属性到 Vue 实例上this._proxyData();// 编译模板this._compileTemplate();// 代理组件this._proxyComponents();}// 将 data 对象的属性代理到 Vue 实例上Vue.prototype._proxyData = function () {var self = this;Object.keys(this._data).forEach(function (key) {Object.defineProperty(self, key, {get: function () {return self._data[key];},set: function (newValue) {self._data[key] = newValue;}});});};// 编译模板Vue.prototype._compileTemplate = function () {var self = this;var el = this.$options.el;var template = this.$options.template || '';// 使用 evalExpression 函数执行模板中的表达式var evalExpression = function (expression) {with (self) return eval(expression);}// 替换模板中的双花括号表达式为对应的数据值var compiledTemplate = template.replace(/\{\{(.*?)\}\}/g, function (match, expression) {var value = evalExpression(expression);return value !== undefined ? value : '';});// 将编译后的模板插入目标元素中var element = el ? document.querySelector(el) : document.createElement('div');element.innerHTML = compiledTemplate.trim();this.$el = el ? element : element.childNodes[0];};// 代理组件Vue.prototype._proxyComponents = function () {var self = this;var components = this._components;// 遍历组件对象,创建组件实例并进行代理Object.keys(components).forEach(function (componentName) {var component = new Vue(components[componentName]);// 查询所有组件标签,并将子组件的内容替换到对应的插槽中self.$el.querySelectorAll(componentName).forEach(function (element) {component.$el.querySelectorAll('slot').forEach(function (slot) {slot.innerHTML = element.innerHTML;});element.innerHTML = component.$el.outerHTML;});});};// 使用示例var HelloComponent = {data: function () {return {name: 'John'};},template: `<div><h1>{{ name }}</h1><slot></slot></div>`};// 创建 Vue 实例var app = new Vue({el: '#app',data: {message: 'Hello, Vue!'},components: {HelloComponent},template: `<HelloComponent><p>{{ message }}</p></HelloComponent>`});</script>
</body></html>

相关文章:

【jsvue】联合gtp仿写一个简单的vue框架,以此深度学习JavaScript

用 gtp 学习 Vue 生命周期的原理 lifecycle.js function Vue(options) {// 将选项保存到实例的 $options 属性中this.$options options;// 若存在 beforeCreate 钩子函数&#xff0c;则调用之if (typeof options.beforeCreate function) {options.beforeCreate.call(this);…...

linux centos7 系统之编程:求水仙花数

在Python编程中&#xff0c;有列表、元组和字典三类变量可以使用&#xff0c;方便数据的存储与处理&#xff0c;而bash中仅有字符串变量、数组、函数可用&#xff0c;方法运用上受到限制&#xff0c;这与bash基于C语言&#xff0c;注重语法结构的严谨有关。而Python等高级语言更…...

git中的cherry-pick和merge有些区别以及cherry-pick怎么用

git中的cherry-pick和merge在使用场景上有些区别: cherry-pick用于将另一个分支的某一次或几次commit应用到当前分支。它可以选择性地拉取代码修改。merge用于将两个分支合并成一个新分支。它会把整个分支上的所有修改都合并过来。 具体区别:cherry-pick通常用于将bug修复从发…...

【前端】CSS-Flex弹性盒模型布局

目录 一、前言二、Flex布局是什么1、任何一个容器都可以指定为Flex布局2、行内元素也可以使用Flex布局3、Webkit内核的浏览器&#xff0c;必须加上-webkit前缀 三、基本概念四、flex常用的两种属性1、容器属性2、项目属性 五、容器属性1、flex-direction①、定义②、语句1&…...

Android AAPT: error: resource color 异常原因处理

异常体现&#xff1a; Android resource linking failed ERROR:E:\software\Developer\APP\GaoDeTest2\app\src\main\res\values\themes.xml:3:5-9:13: AAPT: error: resource color/purple_500 (aka com.example.gaodetest2:color/purple_500) not found.ERROR:E:\software\De…...

C++std::function和std::bind()的概念

std::function&#xff1a; 一个通用的函数封装器&#xff0c;它允许你存储和调用任何可以被调用的东西&#xff0c;例如函数、函数指针、函数对象、Lambda 表达式等。 std::bind&#xff1a; 用于创建函数对象。一个可调用对象的绑定版本&#xff0c;可以提前绑定某些参数&am…...

QT Creator工具介绍及使用

一、QT的基本概念 QT主要用于图形化界面的开发&#xff0c; QT是基于C编写的一套界面相关的类库&#xff0c;如进程线程库&#xff0c;网络编程的库&#xff0c;数据库操作的库&#xff0c;文件操作的库等。 如何使用这个类库&#xff1a;类库实例化对象(构造函数) --> 学习…...

python爬虫13:pymysql库

python爬虫13&#xff1a;pymysql库 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生…...

权限管理 ACL、RBAC、ABAC的学习

ACL(Access Control List&#xff1a;访问控制列表) 最简单的一种方式&#xff0c;将权限直接与用户或用户组相关联&#xff0c;管理员直接给用户授予某些权限即可。 这种模型适用于小型和简单系统&#xff0c;权限一块较为简单&#xff0c;并且角色和权限的变化较少。 RBAC(R…...

python的re正则表达式

一、正在表达式的方法&#xff08;&#xff09;&#xff1a; re是Python中用于处理正则表达式的内置库&#xff0c;提供了许多有用的方法。以下是其中几个常用的方法&#xff1a; re.match(pattern, string): 尝试从字符串的开头匹配一个模式&#xff0c;如果匹配成功则返回匹…...

【算法与数据结构】700、LeetCode二叉搜索树中的搜索

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;二叉搜索树的性质&#xff1a;左节点键值 < 中间节点键值 < 右节点键值。那么我们根据此性质&am…...

SpringBoot v2.7.x+ 整合Swagger3入坑记?

目录 一、依赖 二、集成Swagger Java Config 三、配置完毕 四、解决方案 彩蛋 想尝鲜&#xff0c;坑也多&#xff0c;一起入个坑~ 一、依赖 SpringBoot版本&#xff1a;2.7.14 Swagger版本&#xff1a;3.0.0 <dependency><groupId>com.github.xiaoymin<…...

说说你了解的 CDC

分析&回答 什么是 CDC CDC,Change Data Capture,变更数据获取的简称&#xff0c;使用CDC我们可以从数据库中获取已提交的更改并将这些更改发送到下游&#xff0c;供下游使用。这些变更可以包括INSERT,DELETE,UPDATE等。用户可以在以下的场景下使用CDC&#xff1a; 使用f…...

SpingMvc入门

SpingMvc入门 1.MVC Spring的工作流程&#xff1a;2.sping mvc入门3.静态资源处理 前言 Spring MVC是一种基于Java的web应用开发框架&#xff0c;它采用了MVC&#xff08;Model-View-Controller&#xff09;设计模式来帮助开发者组织和管理应用程序的各个组件。 1.MVC Spring的…...

JVM的故事——类文件结构

类文件结构 文章目录 类文件结构一、概述二、无关性基石三、Class类文件的结构 一、概述 计算机是只认由0、1组成的二进制码的&#xff0c;不过随着发展&#xff0c;我们编写的程序可以被编译成与指令集无关、平台中立的一种格式。 二、无关性基石 对于不同平台和不同平台的…...

springboot自定义表格(动态合并单元格)

一、需求展示&#xff08;一个订单多个商品&#xff0c;商品数量不限订单行合并&#xff09; 二、技术选型&#xff08;jxls自定义模板&#xff09; <!-- 版本具体看官网Release&#xff0c;这里我们使用 2.13.0 --><dependency><groupId>org.jxls</group…...

C++零碎记录(二)

3. 调用其他类 3.1 类中有其他的类 #include <iostream> using namespace std;//点和圆关系案例//点类 class Point { public://设置xvoid setX(int x){m_X x;}//获取xint getX(){return m_X;}//设置yvoid setY(int y){m_Y y;}//获取yint getY(){return m_Y;}private…...

数学建模:回归分析

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 数学建模&#xff1a;回归分析 文章目录 数学建模&#xff1a;回归分析回归分析多元线性回归案例 多项式回归一元多项式回归多元二项式回归 非线性回归逐步回归 回归分析 多元线性回归 案例 首先进行回归分…...

数据库(一)

数据库 1.为什么要使用数据库 如果要存储数据&#xff0c;我们是可以使用文件来存储数据的&#xff0c;但是使用文件管理数据有很多缺点&#xff0c;比如&#xff1a; 不安全&#xff0c;不利于管理&#xff0c;查询&#xff0c;如果要存储大量的数据&#xff0c;使用文件管理…...

【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;首先我们要知道后序遍历数组的最后一个元素必然是根节点&#xff0c;然后根据根节点在中序遍历数组中的…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...