<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<atom:link href="https://server.amfishers.com/feed" rel="self" type="application/rss+xml"/>
<title>Fisher's E-Garden</title>
<link>https://server.amfishers.com</link>
<description>Hi 😊</description>
<language>zh-CN</language>
<copyright>© Fisher </copyright>
<pubDate>Sat, 04 Apr 2026 17:22:04 GMT</pubDate>
<generator>Mix Space CMS (https://github.com/mx-space)</generator>
<docs>https://mx-space.js.org</docs>
<image>
    <url>https://server.amfishers.com/api/v2/objects/avatar/xx3l5g2e7sp438cag2.png</url>
    <title>Fisher's E-Garden</title>
    <link>https://server.amfishers.com</link>
</image>
<item>
    <title>面向 JavaScript 开发人员的 Python</title>
    <link>https://server.amfishers.com/posts/technology/py-js</link>
    <pubDate>Thu, 02 Apr 2026 12:31:37 GMT</pubDate>
    <description>title: 面向 JavaScript 开发人员的 Python
author: Valentin</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/py-js'>https://server.amfishers.com/posts/technology/py-js</a></blockquote>
      <hr>
<h2>title: 面向 JavaScript 开发人员的 Python
author: Valentino Gagliardi
url: <a href="https://www.valentinog.com/blog/python-for-js/">https://www.valentinog.com/blog/python-for-js/</a>
hostname: valentinog.com
description: 为 JavaScript 开发人员提供的 Python 搭便车指南。享受！
sitename: Valentino Gagliardi&#39;s Blog
date: 2019-10-14
tags: [&#39;JavaScript&#39;, &#39;Python&#39;, &#39;前端开发&#39;, &#39;网页开发&#39;]</h2>
<h1>面向 JavaScript 开发人员的 Python</h1>
<p>JavaScript 是我的面包和黄油，但我一点也不讨厌其他编程语言。我一直很喜欢 <strong>Python</strong>，多年来我一直使用它，从脚本到 Flask 和 Django 的 API 应用程序。</p>
<p>在这篇文章中，我将引导您对这两种语言进行 10,000 英尺的比较。</p>
<p>要继续学习，您至少需要对 JavaScript 及其怪癖有<strong>基本的了解</strong>。</p>
<p>您可以在浏览器控制台或 Node.js REPL 中尝试 JavaScript 代码示例。对于 Python，您可以使用 <a href="https://docs.python.org/3.6/tutorial/interpreter.html">Python REPL</a>。代码示例里出现 <code>&gt;&gt;&gt;</code> 即表示 REPL。</p>
<p>享受阅读的乐趣！</p>
<h2>Python 和 JavaScript 中的算术运算符</h2>
<p>让我们从算术开始吧！</p>
<p>Python 和 JavaScript 或多或少共享相同的算术运算符。除了（无双关语）<strong>除法运算符</strong>之外，Python 还有一个<strong>整除运算符</strong>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td>加法</td>
<td>+</td>
<td>+</td>
</tr>
<tr>
<td>减法</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>乘法</td>
<td>*</td>
<td>*</td>
</tr>
<tr>
<td>指数</td>
<td>**</td>
<td>**</td>
</tr>
<tr>
<td>除法</td>
<td>/</td>
<td>/</td>
</tr>
<tr>
<td>整除</td>
<td>//</td>
<td>n/a</td>
</tr>
<tr>
<td>取模</td>
<td>%</td>
<td>%</td>
</tr>
</tbody></table>
<p><strong>底除法返回两个数字相除的整数商</strong>。考虑以下 Python 示例：</p>
<p><code>&gt;&gt;&gt; 89 / 4</code></p>
<p># 输出：22.25</p>
<p>要获得整数而不是浮点数，我们可以使用<strong>向下除法</strong>（<code>//</code> 在 JavaScript 中是注释）：</p>
<p><code>&gt;&gt;&gt; 89 // 4</code></p>
<p># 输出：22</p>
<p>在 JavaScript 中可用 <code>Math.floor</code> 得到同样结果：</p>
<p><code>Math.floor(89 / 4)</code></p>
<p>// 输出：22</p>
<p><strong>Python 的算术</strong>运算符<strong>不仅仅对数字进行运算</strong>。例如，您可以使用<strong>字符串乘法</strong>来重复模式：</p>
<p><code>&gt;&gt;&gt; &quot;a&quot; * 9</code></p>
<p># 输出：&#39;aaaaaaaaa&#39;</p>
<p>或者<strong>加法</strong>也可以连接简单的字符串：</p>
<p><code>&gt;&gt;&gt; &quot;a&quot; + &quot;aa&quot;</code></p>
<p># 输出：&#39;aaa&#39;</p>
<p>对于其他一切，Python 都会引发 TypeError。这意味着<strong>你不能将数字和字符串相加</strong>：</p>
<p><code>&gt;&gt;&gt; &quot;a&quot; + 9</code></p>
<p># 类型错误：只能将 str （不是“int”）连接到 str</p>
<p><strong>也不划分它们</strong>（除了没有意义之外）：</p>
<p><code>&gt;&gt;&gt; &quot;a&quot; / 9</code></p>
<p># 类型错误：/ 不支持的操作数类型：“str”和“int”</p>
<p>在这方面，由于<strong>臭名昭著的类型强制</strong>，<strong>JavaScript</strong> 在外部观察者眼中完全是一团糟。不仅<strong>JavaScript的算术运算符可以自由地将数字转换为字符串</strong>：</p>
<p><code>&quot;a&quot; + 9</code></p>
<p>// 输出：“a9”</p>
<p>它们<strong>在无效算术运算的情况下不会引发任何错误</strong>：</p>
<p><code>&quot;a&quot; / 9</code></p>
<p>// 输出：NaN</p>
<p>相反，我们得到 <code>NaN</code>——由无效算术运算产生的特殊 JavaScript 值，难以处理，直到 ECMAScript 2015 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN">Number.isNaN</a>。</p>
<h2>Python 和 JavaScript 中的自增和自减运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td>自增</td>
<td>n/a</td>
<td>++</td>
</tr>
<tr>
<td>自减</td>
<td>n/a</td>
<td>--</td>
</tr>
</tbody></table>
<p>JavaScript 有一个递增和一个递减运算符。两者都可以使用<strong>前缀</strong>（在数字之前）：</p>
<p><code>var a = 34;</code></p>
<p>++a</p>
<p>或 <strong>后缀</strong>（在数字之后）：</p>
<p><code>var a = 34;</code></p>
<p>一个++</p>
<p>在第一种情况（<strong>前缀</strong>）中，<strong>运算符递增数字并返回新数字</strong>：</p>
<p><code>var a = 34;</code></p>
<p>++a</p>
<p>// 返回 35</p>
<p>在第二种情况（<strong>后缀</strong>）中，<strong>运算符递增数字，但返回原始数字</strong>：</p>
<p><code>var a = 34;</code></p>
<p>一个++</p>
<p>// 返回 34</p>
<p>// 增加到 35</p>
<p><strong>同样的规则也适用于减运算符</strong>。</p>
<p><strong>相反，Python 中不存在递减/递增运算符这样的东西</strong>。相反，您必须使用<strong>赋值运算符</strong>。这是 Python 中的增量赋值：</p>
<p><code>&gt;&gt;&gt; a = 34</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>a += 1</p>
</blockquote>
</blockquote>
</blockquote>
<p># a 现在 35</p>
<p>这是一个减量赋值：</p>
<p><code>&gt;&gt;&gt; a = 35</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>a -= 2</p>
</blockquote>
</blockquote>
</blockquote>
<p># a 现在是 33</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators">JavaScript 也有赋值运算符</a>。</p>
<h2>Python 和 JavaScript 中的比较运算符</h2>
<p>JavaScript 和 Python 具有相同的比较运算符，除了 <strong>三等号</strong>，它象征着 <strong>JavaScript 奇怪的强制规则</strong>。</p>
<p>关于这个主题有大量文献，我不会过多打扰您。以下是并列的 Python 和 JavaScript 比较运算符：</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td>大于</td>
<td>&gt;</td>
<td>&gt;</td>
</tr>
<tr>
<td>小于</td>
<td>&lt;</td>
<td>&lt;</td>
</tr>
<tr>
<td>大于等于</td>
<td>&gt;=</td>
<td>&gt;=</td>
</tr>
<tr>
<td>小于或等于</td>
<td>&lt;=</td>
<td>&lt;=</td>
</tr>
<tr>
<td>相等</td>
<td>==</td>
<td>==</td>
</tr>
<tr>
<td>严格相等（三等号）</td>
<td>n/a</td>
<td>===</td>
</tr>
<tr>
<td>不等于</td>
<td>!=</td>
<td>!=</td>
</tr>
<tr>
<td>严格不相等</td>
<td>n/a</td>
<td>!==</td>
</tr>
</tbody></table>
<p>准确地说，Python 还有 ** is 运算符**（此处未讨论），对我来说，它更多地属于身份运算符家族。</p>
<p>这里重要的是 <strong>Python 在比较值时是可预测的</strong>：</p>
<p><code>&gt;&gt;&gt; 9 == &quot;9&quot;</code></p>
<p># 输出：假</p>
<p>另一方面，每次涉及<em>抽象比较</em>运算符时，JavaScript 都会执行一次转换：</p>
<p><code>9 == &quot;9&quot;</code></p>
<p>// 输出：真</p>
<p>这里<strong>第一个运算符 9 在比较之前被转换为字符串</strong>。为了避免转换，您必须使用“<strong>严格比较运算符</strong>”，也称为<strong>三等于</strong>：</p>
<p><code>9 === &quot;9&quot;</code></p>
<p>// 输出：假</p>
<h2>Python 和 JavaScript 中的逻辑运算符</h2>
<p>现在我们讨论了算术和比较运算符，让我们看看它们的同伴：<strong>逻辑运算符</strong>。哦，我的朋友，我还记得高中时的布尔代数。你？</p>
<p>以下是 Python 和 JavaScript 中最常见的逻辑运算符：</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td>逻辑与</td>
<td>and</td>
<td>&amp;&amp;</td>
</tr>
<tr>
<td>逻辑或</td>
<td>or</td>
<td></td>
</tr>
<tr>
<td>逻辑非</td>
<td>not</td>
<td>!</td>
</tr>
</tbody></table>
<p><strong>当您想要根据表达式的结果在代码中执行（或不执行）某些操作时，逻辑运算符非常有用</strong>。假设我们只想在 2019 年大于 1900 时打印“I am Cool”。以下是在 Python 中使用 <strong>逻辑运算符 and</strong> 执行此操作的方法：</p>
<p><code>&gt;&gt;&gt; 2019 &gt; 1900 and print(&quot;I am cool&quot;)</code></p>
<p># 输出：“我很酷”</p>
<p><strong>和</strong>表示：仅当<strong>左侧的内容为</strong>true**时才执行右侧的内容。 JavaScript 中的相同逻辑映射为：</p>
<p><code>2019 &gt; 1900 &amp;&amp; console.log(&quot;I am cool&quot;)</code></p>
<p><strong>或逻辑运算符的工作方式相反</strong>。 <strong>或</strong>表示：仅当<strong>左侧的内容为</strong>假**时才执行右侧的内容。下面是一个 Python 示例：</p>
<p><code>&gt;&gt;&gt; 2019 &gt; 1900 or print(&quot;I am cool&quot;)</code></p>
<p># 输出：真</p>
<p>结果是<code>True</code></p>
<p>因为2019年大于1900所以评估就到此为止。 JavaScript 中的逻辑如下：</p>
<p><code>2019 &gt; 1900 || console.log(&quot;I am cool&quot;)</code></p>
<p>最后但并非最不重要的一点是<strong>逻辑否定</strong>，当您想要<strong>翻转表达式的结果</strong>时很有用。例如，即使左侧给定的表达式为 <strong>false</strong>，我们也可以打印“I am Cool”。如何？使用 Python 中的 <strong>not</strong> 运算符：</p>
<p><code>&gt;&gt;&gt; not 2019 &gt; 151900 and print(&quot;I am cool&quot;)</code></p>
<p># 输出：“我很酷”</p>
<p>2019 显然小于 151900，但 <strong>逻辑非</strong> 翻转了结果，因此仍然评估正确的表达式。下面的例子应该更容易理解：</p>
<p><code>&gt;&gt;&gt; not False and print(&quot;I am cool&quot;)</code></p>
<p># 输出：“我很酷”</p>
<p><strong>JavaScript 中的逻辑否定使用感叹号</strong>：</p>
<p><code>!false &amp;&amp; console.log(&quot;I am cool&quot;)</code></p>
<h2>Python 和 JavaScript 中的基本数据类型</h2>
<p>在计算机编程中，<strong>数据类型</strong>是您可以处理的**“形状”**。 <strong>大多数编程语言都有一组基本数据类型，如字符串、数字和布尔值</strong>。</p>
<p>Python 和 JavaScript 也不例外。以下概述了两种语言中可用的最重要的<strong>基本数据类型</strong>（n/a 代表不适用）。</p>
<table>
<thead>
<tr>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
<th>Python 中是否可变</th>
<th>JavaScript 中是否可变</th>
</tr>
</thead>
<tbody><tr>
<td>float</td>
<td>Number</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>int</td>
<td>BigInt</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>int</td>
<td>n/a</td>
<td>否</td>
<td>n/a</td>
</tr>
<tr>
<td>string</td>
<td>String</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>boolean</td>
<td>Boolean</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>None</td>
<td>Null</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>n/a</td>
<td>Undefined</td>
<td>n/a</td>
<td>否</td>
</tr>
<tr>
<td>n/a</td>
<td>Symbol</td>
<td>n/a</td>
<td>否</td>
</tr>
</tbody></table>
<p>JavaScript 有八种类型，其中七种称为<strong>原语</strong>（对象本身就是一种类型）。从表中您可以注意到，Python 和 JavaScript 基本类型都是<strong>不可变的</strong>。例如，在 <strong>Python 中，我们将字符串称为 unicode 字符的不可变序列</strong>。</p>
<p>与大多数基本类型一样，Python 字符串也有常见操作的方法：</p>
<p><code>&gt;&gt;&gt; name = &quot;caty&quot;</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>name.capitalize()</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>name.center(40)</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>name.count(&quot;t&quot;)</p>
</blockquote>
</blockquote>
</blockquote>
<h2>还有更多！</h2>
<p>由于字符串是不可变的，因此字符串操作的结果始终是一个新字符串。</p>
<p>现在数字。在 JavaScript 中，整数和浮点数没有区别，它们只是一个 <code>Number</code> 数据类型。<strong>在 Python 中，有整数和浮点数</strong>。</p>
<p>JavaScript 最近获得了 <code>BigInt</code>，用于表示非常大的数字的原始类型。相反，Python 似乎使用单个 int 类型来处理小整数和大整数。</p>
<p>如果不提及典型的 <strong>boolean</strong> 那就太失职了，在 Python 中它可以假设 <code>False</code> 或 <code>True</code>。</p>
<p>关于<strong>特殊值</strong>的重要说明。Python 用 <code>None</code> 表示空值；JavaScript 中对应的是 <code>null</code>。</p>
<p>同样在 Python 中也没有 <code>undefined</code> 的概念；也没有与 JavaScript 的 <code>Symbol</code> 相当的类型（相当深奥的原语）。</p>
<h2>Python 和 JavaScript 中的正则表达式</h2>
<p><strong>正则表达式</strong>是针对文本进行模式匹配的强大工具。为了在 Python 中使用正则表达式，我们使用 <code>re</code> 模块。</p>
<p>要创建新模式，我们可以使用 <code>re.compile</code> 编译正则表达式：</p>
<p><code>import re</code></p>
<p>regex = re.compile(r&quot;\d\d\d\d&quot;)</p>
<p><code>re.compile</code> 对于复杂的正则表达式特别有用，因为它可以加快速度。</p>
<p>有了正则表达式后，可用 <code>.search()</code> 在一段文本上匹配：</p>
<p><code>import re</code></p>
<p>regex = re.compile(r&quot;\d\d\d\d&quot;)</p>
<p>text = &quot;Your id is 4933&quot;</p>
<p>match = regex.search(text)</p>
<p>这里我们用 <code>\d\d\d\d</code> 搜索文本中的四个连续数字。若匹配成功，结果是一个 match 对象，带有 <code>.start()</code> 和 <code>.end()</code> 两个方法。</p>
<p>这些方法分别返回已找到模式的文本部分的开始和结束索引**：</p>
<p><code>import re</code></p>
<p>regex = re.compile(r&quot;\d\d\d\d&quot;)</p>
<p>text = &quot;Your id is 4933&quot;</p>
<p>match = regex.search(text)</p>
<p>start, end = match.start(), match.end()</p>
<p># 开始是 11，结束是 15</p>
<p>有了这些索引，我们现在可以提取匹配项：</p>
<p><code>import re</code></p>
<p>regex = re.compile(r&quot;\d\d\d\d&quot;)</p>
<p>text = &quot;Your id is 4933&quot;</p>
<p>match = regex.search(text)</p>
<p>start, end = match.start(), match.end()</p>
<p>found = text[start:end] # 4933</p>
<p>在 JavaScript 中可用字面量或 <code>RegExp</code> 构造函数达到同样效果：</p>
<p><code>const regex = new RegExp(/\d\d\d\d/);</code></p>
<p>我们还可以将标志传递给构造函数。这里我们构建一个全局正则表达式：</p>
<p><code>const regex = new RegExp(/\d\d\d\d/, &quot;g&quot;);</code></p>
<p>现在给定要匹配的文本，可用 <code>.exec()</code> 与 <code>lastIndex</code> 在字符串中多次匹配，或更好的是使用新的 <code>String.prototype.matchAll()</code>，返回 <a href="https://www.valentinog.com/blog/generator/#iterables-and-iterators">迭代器</a>：</p>
<p><code>const regex = new RegExp(/\d\d\d\d/, &quot;g&quot;);</code></p>
<p>const text = &quot;Your 7795 id is 4933&quot;;</p>
<p>const match = text.matchAll(regex);</p>
<p>const found = [...match].map((el) =&gt; el[0]);</p>
<p>// [&#39;7795&#39;，&#39;4933&#39;]</p>
<h2>Python 数据类型和 JavaScript：不变性和变量</h2>
<p>您可能从上表中注意到，<strong>大多数基本 Python 数据类型都是不可变的</strong>。 <strong>JavaScript在实践中似乎更轻松</strong>。在浏览器控制台或 Node.js REPL 中尝试以下示例。数字？ <strong>看起来</strong>可变：</p>
<p><code>var a = 34;</code></p>
<p>++a</p>
<p>// 返回 35</p>
<p>布尔值？ <strong>看起来</strong>也是可变的：</p>
<p><code>var x = false;</code></p>
<p>x++;</p>
<p>// 返回 0 并且 x 变为 1</p>
<p>无效的？再次，<strong>似乎</strong>是可变的：</p>
<p><code>var x = null;</code></p>
<p>x++;</p>
<p>// 返回 0 并且 x 变为 1</p>
<p><strong>别被愚弄了。这里改变的不是底层原语</strong>，而是分配给变量的**值。</p>
<p><strong>最后两个带有 boolean 和 null 的示例是类型强制的情况。引擎将这两个值转换为相应的数字表示</strong>，并且变量被分配新值。</p>
<p>参见 <a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Another_Example_Step-by-step">this example on MDN for more</a>。</p>
<h2>Python 和 JavaScript 中的复杂数据类型</h2>
<p><strong>复杂数据类型是一种更复杂的形状</strong>，与字符串和数字等简单基元相反。在Python中，我们可以命名<strong>列表、字典、集合和元组</strong>。</p>
<p>相反，在 JavaScript 中，区别稍微不太明显，因为 <code>Object</code></p>
<p>是最顶层的复杂类型和其他子类型，例如 <code>Array</code></p>
<p>和<code>Set</code></p>
<p>是其“祖先”的特殊版本（<code>Function</code></p>
<p>也是一个对象）。</p>
<p>以下是 Python 和 JavaScript 中复杂数据类型的细分：</p>
<table>
<thead>
<tr>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
<th>Python 中是否可变</th>
<th>JavaScript 中是否可变</th>
</tr>
</thead>
<tbody><tr>
<td>list</td>
<td>Array</td>
<td>是</td>
<td>是</td>
</tr>
<tr>
<td>dictionary</td>
<td>Object</td>
<td>是</td>
<td>是</td>
</tr>
<tr>
<td>set</td>
<td>Set</td>
<td>是</td>
<td>是</td>
</tr>
<tr>
<td>tuple</td>
<td>n/a</td>
<td>否</td>
<td>n/a</td>
</tr>
</tbody></table>
<p>正如你所看到的 <strong>JavaScript 中的数组和对象总是可变的</strong>，所以 <code>Object</code></p>
<p>。除非使用外部库，否则无法真正保护对象（<code>Object.freeze</code></p>
<p>是浅的）。不过，未来有计划将 <a href="https://github.com/rricard/proposal-const-value-types">immutable types</a> 添加到 JavaScript 中。</p>
<p>另一方面，Python 是一种<strong>不可变的复杂类型，称为元组</strong>（而列表、字典和集合是可变的）。让我们更详细地了解 Python 复杂类型。</p>
<h2>Python 数据类型：列表和元组</h2>
<p>Python 中的列表是元素的集合，就像 JavaScript 数组一样。这是一个 Python 列表：</p>
<p><code>&gt;&gt;&gt; my_list = [&quot;vale&quot;, 98, &quot;caty&quot;, None]</code></p>
<p><strong>列表操作总是会改变原始列表</strong>：</p>
<p><code>&gt;&gt;&gt; my_list = [&quot;a&quot;, None, 44, True, &quot;f&quot;]</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>my_list.append(44)</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_list.remove(&#39;f&#39;)</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>print(my_list)</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：[“a”，无，44，真，44]</p>
<p>相反，元组是不可变的，实际上它只有两个只读操作（索引和计数）：</p>
<p><code>&gt;&gt;&gt; my_tuple = (&quot;vale&quot;, &quot;Italy&quot;, 105)</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>my_tuple.count(&quot;Italy&quot;) # 1</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_tuple.index(105) # 2</p>
</blockquote>
</blockquote>
</blockquote>
<p>请注意，<strong>元组包含在圆括号中</strong>。</p>
<p>我真的很喜欢 Python 如何<strong>使用加法运算符将两个列表连接在一起</strong>：</p>
<p><code>&gt;&gt;&gt; my_list = [&quot;a&quot;, None, 44, True, &quot;f&quot;]</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>another_list = [&quot;b&quot;, None, 89, False, &quot;x&quot;]</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_list + another_list</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：[“a”，无，44，True，44，“b”，无，89，False，“x”]</p>
<p>但是<strong>不敢用 JavaScript 尝试这个技巧</strong>，你会感到惊讶：</p>
<p><code>var my_list = [&quot;a&quot;, null, 44, true, &quot;f&quot;]</code></p>
<p>var another_list = [&quot;b&quot;, null, 89, false, &quot;x&quot;]</p>
<p>result = my_list + another_list</p>
<p>// 结果是：“a,,44,true,fb,,89,false,x”</p>
<p>与 <a href="https://www.ecma-international.org/ecma-262/10.0/index.html#sec-addition-operator-plus-runtime-semantics-evaluation">JavaScript spec goes</a> 一样，当操作数都是非字符串时（如本示例所示），加法运算符会将其操作数转换为字符串。注意，<strong>Python 列表和元组不能连接在一起</strong>：</p>
<p><code>&gt;&gt;&gt; my_tuple = (&quot;vale&quot;, &quot;Italy&quot;, 105)</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>my_list = [&quot;a&quot;, None, 44, True, &quot;f&quot;]</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_tuple + my_list</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出类型错误：只能将元组（不是“列表”）连接到元组</p>
<h2>Python 数据类型：字典和 JavaScript 对象</h2>
<p>JavaScript 的对象是键/值对的<strong>容器</strong>，也是其他专用对象<strong>的</strong>支柱：</p>
<p><code>var obj = {</code></p>
<p>姓名：“约翰”，</p>
<p>年龄：33</p>
<p>};</p>
<p>“JavaScript 中几乎所有东西都是对象”不仅仅是一种说法。这是事实。数组、函数、集​​合等等都只是 JavaScript 对象。</p>
<p><strong>Python 有类似的东西，称为字典</strong>（或简称 dict），但它只是一个容器，而不是基本构建块：</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<p>字典中的值可以通过它们的键访问或更改：</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict[&quot;name&quot;]</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict[&quot;city&quot;] = &quot;Florence&quot;</p>
</blockquote>
</blockquote>
</blockquote>
<p>Python 引发 <code>KeyError</code></p>
<p>当您访问不存在的密钥时：</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict[&quot;not_here&quot;]</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：KeyError：&#39;not_here&#39;</p>
<p><code>.get()</code></p>
<p>方法是直接键访问的更安全的替代方法，因为它不会引发，并且让我们为不存在的键指定默认值：</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict.get(&quot;not_here&quot;, &quot;not found&quot;)</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：“未找到”</p>
<p>其他只读操作为<code>.items()</code></p>
<p>，或 <code>.keys()</code></p>
<p>:</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict.keys() # [&#39;name&#39;, &#39;city&#39;, &#39;age&#39;]</p>
</blockquote>
</blockquote>
</blockquote>
<p>您还可以使用 <code>.clear()</code> 从字典中删除元素或完全清除它</p>
<p>:</p>
<p><code>&gt;&gt;&gt; my_dict = {</code></p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict.pop(&quot;name&quot;) # returns &#39;John&#39; and removes it</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_dict.clear() # my_dict is empty now</p>
</blockquote>
</blockquote>
</blockquote>
<p>列表、元组、字典和集合是<strong>集合或序列</strong>，因为它们保存一定数量的元素，并公开<strong>与它们交互的通用操作</strong>。</p>
<h2>没有开关，没有派对</h2>
<p>“Python 中没有开关？我应该怎么做”……几年前你就可以听到我的声音。你没看错<strong>没有</strong> <code>switch</code></p>
<p><strong>在Python中</strong>。 Java 程序员喜欢它，JavaScript 开发人员也喜欢它。</p>
<p><code>switch</code></p>
<p>语句是 JavaScript 中的常见习惯用法。考虑以下示例：</p>
<p><code>function getUrlConf(host) {</code></p>
<p>switch (host) {</p>
<p>案例“<a href="http://www.example-a.dev%E2%80%9D%EF%BC%9A">www.example-a.dev”：</a></p>
<p>return &quot;firstApp.urls&quot;;</p>
<p>案例“www-example-b.dev”：</p>
<p>return &quot;secondApp.urls&quot;;</p>
<p>案例“<a href="http://www.example-c.dev%E2%80%9D%EF%BC%9A">www.example-c.dev”：</a></p>
<p>return &quot;thirdApp.urls&quot;;</p>
<p>默认：</p>
<p>return &quot;Sorry, no match&quot;;</p>
<p>}</p>
<p>}</p>
<p>getUrlConf(&quot;www-example-b.dev&quot;);</p>
<p>函数必须检查主机字符串以根据主机值返回相应的配置。配<code>switch</code></p>
<p>我们比较值<code>switch (host)</code></p>
<p>在 <code>case</code> 中</p>
<p>条款<code>case &quot;www.example-a.dev&quot;:</code></p>
<p>。对于每个 <code>case</code></p>
<p>我们返回一个值。 <code>default</code></p>
<p>子句确保在没有匹配项的情况下返回默认值。</p>
<p>Python 中没有 <code>switch</code></p>
<p>：使用字典可以得到相同的结果：</p>
<p><code>def get_url_conf(host):</code></p>
<p>mapping = {</p>
<p>&quot;<a href="http://www.example-a.dev">www.example-a.dev</a>&quot;: &quot;firstApp.urls&quot;,</p>
<p>&quot;www-example-b.dev&quot;: &quot;secondApp.urls&quot;,</p>
<p>&quot;<a href="http://www.example-c.dev">www.example-c.dev</a>&quot;: &quot;thirdApp.urls&quot;</p>
<p>}</p>
<p>return mapping.get(host, &quot;Sorry, no match&quot;)</p>
<p>如果你问我的话，就干净多了。如果您更喜欢的话，还有 <a href="https://www.valentinog.com/blog/switch/">same pattern works for JavaScript</a>。</p>
<h2>JavaScript 对象传播/合并，Python 字典传播/合并</h2>
<p>ECMAScript 2018 添加了“分解”JavaScript <strong>对象</strong>的功能，也称为 <strong>“传播”</strong>。此语法<strong>对于保持对象不变（或克隆它们）特别方便</strong>：</p>
<p><code>const initial = {</code></p>
<p>不要触摸：“我的布雷尔”</p>
<p>};</p>
<p>const next = { ...initial, dontTouch: &quot;just a copy&quot; };</p>
<p>// initial.dontTouch 是“我的 breil”</p>
<p>// next.dontTouch 是“只是一个副本”</p>
<p>或者<strong>将它们合并在一起</strong>：</p>
<p><code>const a = {</code></p>
<p>姓名：“朱莉安娜”，</p>
<p>年龄：33</p>
<p>};</p>
<p>const b = {</p>
<p>姓氏：“克莱恩”，</p>
<p>城市：“旧金山”</p>
<p>};</p>
<p>const movie = {</p>
<p>书名：《高堡里的男人》</p>
<p>};</p>
<p>const all = { ...a, ...b, ...movie };</p>
<p>console.log(all);</p>
<p>/*</p>
<p>输出：</p>
<p>{</p>
<p>名称：“朱莉安娜”，</p>
<p>年龄：33，</p>
<p>姓氏：“克莱恩”，</p>
<p>城市：“旧金山”，</p>
<p>书名：《高堡里的人》</p>
<p>}</p>
<p>*/</p>
<p>在对象传播之前，使用 <code>Object.assign</code> 实现了相同的结果</p>
<p>:</p>
<p><code>const initial = {</code></p>
<p>不要触摸：“我的布雷尔”</p>
<p>};</p>
<p>const next = Object.assign({}, initial, { dontTouch: &quot;just a copy&quot; });</p>
<p>有几种方法可以在 <strong>Python</strong> 中获得相同的结果：一种方法涉及遍历 <code>dict.update()</code></p>
<p>我不会在这里介绍。</p>
<p><strong>字典解包看起来更像是 JavaScript 的对象传播</strong>，我更喜欢它。这是第一个例子：</p>
<p><code>initial = {&quot;dont_touch&quot;: &quot;my breil&quot;}</code></p>
<p>next = {**initial, &quot;dont_touch&quot;: &quot;just a copy&quot;}</p>
<p>这里是<code>initial</code></p>
<p>被传播到 <code>next</code></p>
<p>，“dont_touch”的值会覆盖原始值，同时保留 <code>initial</code></p>
<p>。要<strong>合并两个或多个字典</strong>，我们可以这样做：</p>
<p><code>a = {&quot;name&quot;: &quot;Juliana&quot;, &quot;age&quot;: 33}</code></p>
<p>b = {&quot;surname&quot;: &quot;Crain&quot;, &quot;city&quot;: &quot;San Francisco&quot;}</p>
<p>movie = {&quot;title&quot;: &quot;The man in the high castle&quot;}</p>
<p>all = {**a, **b, **movie}</p>
<p>不幸的是，字典解包有一些限制，导致 Python 添加<strong>字典的联合运算符</strong>。所以从 <strong>Python 3.9 开始你可以做 union</strong>：</p>
<p><code>a = {&quot;name&quot;: &quot;Juliana&quot;, &quot;age&quot;: 33}</code></p>
<p>b = {&quot;surname&quot;: &quot;Crain&quot;, &quot;city&quot;: &quot;San Francisco&quot;}</p>
<p>movie = {&quot;title&quot;: &quot;The man in the high castle&quot;}</p>
<p>all = a | b | movie  # Dict union!</p>
<p>print(all)</p>
<p>”“”</p>
<p>输出</p>
<p>{&#39;name&#39;: &#39;Juliana&#39;, &#39;age&#39;: 33, &#39;surname&#39;: &#39;Crain&#39;, &#39;city&#39;: &#39;San Francisco&#39;, &#39;title&#39;: &#39;The man in the high castle&#39;}</p>
<p>”“”</p>
<p>整洁的！更多<a href="https://www.python.org/dev/peps/pep-0584/">info here</a>。</p>
<h2>Python 数据类型：Set 和 JavaScript Set</h2>
<p><strong>JavaScript 的 Set 是一种方便的数据结构</strong>，可用于存储<strong>唯一值</strong>。 Set 可以包含原始类型（甚至为 null 和未定义）或对对象的引用：</p>
<p><code>const mySet = new Set();</code></p>
<p>mySet.add( &quot;aString&quot; )</p>
<p>mySet.add( null )</p>
<p>mySet.add( NaN )</p>
<p>mySet.add(1)</p>
<p>mySet.add(1)</p>
<p>// Output: Set { &#39;aString&#39;, null, NaN, 1 }</p>
<p>除了添加元素、检查它们是否存在或循环遍历之外，您对 JavaScript Set 没有什么可以做的。 Set 有以下方法：</p>
<ul>
<li>.添加</li>
<li>.清除</li>
<li>.删除</li>
<li>.条目</li>
<li>.forEach</li>
<li>.有</li>
<li>.keys</li>
<li>.尺寸</li>
<li>.values</li>
</ul>
<p>Python 的 Set 的工作原理大致相同。您可以在其中添加<strong>独特</strong>元素或也检查它们：</p>
<p><code>&gt;&gt;&gt; my_set = set()</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>my_set.add( &quot;aString&quot; )</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set.add( None )</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set.add( 1 )</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set.add( 2 )</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set.add( 1 )</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set</p>
</blockquote>
</blockquote>
</blockquote>
<p># Output: {None, 2, &#39;aString&#39;, 1}</p>
<p>然而，与 JavaScript 的主要区别在于 <strong>Python 有更多有用的数学集合运算方法</strong>，如“差”、“交”、“issubset”、“issuperset”、“union”等。</p>
<p>在 Python 中声明 Set 也有文字形式：</p>
<p><code>&gt;&gt;&gt; my_set = { None, &quot;caty&quot;, &quot;venice&quot;, 84}</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>another_set = { &quot;and&quot;, &quot;mouse&quot;, 44, &quot;a&quot; }</p>
</blockquote>
</blockquote>
</blockquote>
<p>正如您可能已经猜到的那样，<strong>两种语言中的设置对于删除重复项确实很有用</strong>。在Python中可以做一些不错的事情，比如<strong>union</strong>：</p>
<p><code>&gt;&gt;&gt; my_set | another_set</code></p>
<p># Output: {&#39;and&#39;, &#39;mouse&#39;, None, &#39;venice&#39;, &#39;caty&#39;, 44, 84, &#39;a&#39;}</p>
<p>或<strong>交叉点</strong>：</p>
<p><code>&gt;&gt;&gt; my_set = { None, &quot;caty&quot;, &quot;venice&quot;, 84, &quot;common_element&quot; }</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>another_set = { &quot;and&quot;, &quot;mouse&quot;, 44, &quot;a&quot;, &quot;common_element&quot; }</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_set &amp; another_set</p>
</blockquote>
</blockquote>
</blockquote>
<p># Output: {&#39;common_element&#39;}</p>
<p>值得一提的是，集合在 JavaScript 和 Python 中都是可变的，但集合内的单个元素仍然是不可变的。</p>
<h2>Python 和 JavaScript 中的成员资格运算符</h2>
<p>“这个元素是否存在于另一个元素内部”？ <strong>会员运营商</strong>知道答案。 Python 和 JavaScript 都有一个名为 <strong>in</strong> 的成员运算符：</p>
<table>
<thead>
<tr>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td><code>in</code></td>
<td><code>in</code></td>
</tr>
</tbody></table>
<p>在 Python 中，您可以对几乎任何数据类型使用 <strong>in</strong>。例如，您可以检查字符是否出现在字符串中：</p>
<p><code>&gt;&gt;&gt; &quot;o&quot; in &quot;Florence&quot;</code></p>
<p># 输出：真</p>
<p>它也适用于列表、元组和字典：</p>
<p><code>&gt;&gt;&gt; my_list = [&quot;vale&quot;, 98, &quot;caty&quot;, None]</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>98 in my_list # Output: True</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>my_tuple = (&quot;vale&quot;, &quot;Italy&quot;, 105)</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>&quot;italy&quot; in my_tuple # Output: False</p>
</blockquote>
</blockquote>
</blockquote>
<p>my_dict = {</p>
<p>“姓名”：“约翰”，</p>
<p>“城市”：“罗马”，</p>
<p>“年龄”：44</p>
<p>}</p>
<p>my_dict 中的“age” # 输出：True</p>
<p>相反，在 <strong>JavaScript 中</strong>，<strong>in 运算符****无论是在字符串上还是在数组上都不能直观地工作</strong>：</p>
<p><code>&quot;a&quot; in [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]</code></p>
<p>// 输出：假</p>
<p>“佛罗伦萨”中的“o”</p>
<p>// 输出：类型错误：无法使用“in”运算符在佛罗伦萨搜索“o”</p>
<p>它对字符串没有用，并且<strong>不搜索数组中的实际元素</strong>。它寻找的是<strong>数组索引</strong>：</p>
<p><code>1 in [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]</code></p>
<p>// 输出：真</p>
<p>考虑到 Array 是 Object 的子类型，并且将其想象为具有以下形状的对象更正确，这是有道理的：</p>
<p><code>var myArr = {</code></p>
<p>0：“一”，</p>
<p>1：“b”，</p>
<p>2：“c”</p>
<p>};</p>
<p>回顾一下，JavaScript 中的 <strong>in</strong> 仅适用于对象键，如果给定键存在于对象中**，则返回 true：</p>
<p><code>var my_obj = {&quot;name&quot;: &quot;John&quot;, &quot;city&quot;: &quot;Rome&quot;, &quot;age&quot;: 44}</code></p>
<p>my_obj 中的“名称”</p>
<p>// 输出：真</p>
<h2>实例操作符：免责声明</h2>
<p>“谁创建了这个对象”？ <strong>实例操作员</strong>尝试回答这个问题。现在，在你对我大喊大叫之前，让我先澄清一下。 <strong>下表只是我对一个更复杂的故事的心理表征</strong>：</p>
<table>
<thead>
<tr>
<th>PYTHON</th>
<th>JAVASCRIPT</th>
</tr>
</thead>
<tbody><tr>
<td><code>isinstance()</code></td>
<td><code>instanceof</code></td>
</tr>
<tr>
<td><code>type()</code></td>
<td><code>typeof</code></td>
</tr>
</tbody></table>
<p>正如您将看到的，在这个问题上不可能将 Python 和 JavaScript 1 对1 映射，因为 Python 是真正面向对象的，而 <strong>JavaScript 是基于原型的</strong>。</p>
<p>如果您了解一点 JavaScript，您就会知道“类”是一种幻觉，每次我们谈论 JavaScript 中的类时，我们都在撒谎。</p>
<p>但让我们用一些例子来揭开我的表格的神秘面纱。</p>
<h2>Python 类、isinstance 和 JavaScript instanceof</h2>
<p>考虑一个 Python 类，并由它创建一个新对象：</p>
<p><code>class Person:</code></p>
<p>def <strong>init</strong>(self, name, age):</p>
<p>self.name = 姓名</p>
<p>自我年龄 = 年龄</p>
<p>def print_details(self):</p>
<p>details = f&quot;Name: {self.name} - Age: {self.age}&quot;</p>
<p>print(details)</p>
<p>tom = Person(&quot;Tom&quot;, 89)</p>
<p>tom.print_details()</p>
<p>汤姆是什么？在面向对象编程中，我们说它是一个<strong>类实例</strong>，即<strong>从类蓝图构造的新对象</strong>。 Python 中的 <strong>isinstance</strong> （它是一个函数，而不是一个运算符）如果一个对象似乎是由给定的类构建的，则返回 true。所以在我们的例子中：</p>
<p><code>&gt;&gt;&gt; isinstance(tom, Person)</code></p>
<p># 输出：真</p>
<p>那么用 JavaScript 来代替呢？这是同一个类：</p>
<p><code>class Person {</code></p>
<p>constructor(name, age) {</p>
<p>这个.name = 名称</p>
<p>this.age = 年龄</p>
<p>}</p>
<p>printDetails() {</p>
<p>const details = <code>Name: ${this.name} - Age: ${this.age}</code></p>
<p>console.log(details)</p>
<p>}</p>
<p>}</p>
<p>const tom = new Person(&quot;Tom&quot;, 44)</p>
<p>汤姆现在怎么样了？让我们来看看：</p>
<p><code>console.log(tom instanceof Person)</code></p>
<p>// 输出：真</p>
<p>并非严格的「实例」：<code>tom</code> 只是通过原型链连到 <code>Person.prototype</code> 的<strong>普通对象</strong>，同时也连到 <code>Object</code>：</p>
<p><code>console.log(tom instanceof Object)</code></p>
<p>// 输出：真</p>
<p>因此 <strong>JavaScript 的 <code>instanceof</code></strong> 在对象「看起来」由某类构造时返回 true，<strong>并不是因为严格意义上的实例</strong>，而只是因为 <code>tom</code> 通过原型链连到了 <code>Person.prototype</code>。</p>
<p>我尝试比较两种语言的实例运算符，这是我能想到的最好的结果。我认为 <strong>Python 的 isinstance() 和 JavaScript instanceof 相似只是因为它们的行为</strong>，但这仍然是一个危险的比较。</p>
<p>如果是这样，您可能会想，为什么要引入 isinstance() 呢？这导致使用下一节......</p>
<h2>Python 中的 type() 和 JavaScript 中的 typeof</h2>
<p>任何时候你想<strong>检查 JavaScript 中给定值的类型，typeof</strong> 都是你的朋友：</p>
<p><code>typeof &quot;alex&quot; // &quot;string&quot;</code></p>
<p>typeof 9 //“数字”</p>
<p>typeof [1,2] // “对象”</p>
<p><strong>当我们想要检查函数是否存在时，JavaScript 中的 typeof 很方便</strong>，例如：</p>
<p><code>if (typeof window.futureStuff === &quot;undefined&quot;) {</code></p>
<p>window.futureStuff = function () {</p>
<p>// 做事</p>
<p>}</p>
<p>}</p>
<p>来自 JavaScript 的您可能希望在 Python 中使用类似的运算符。 <strong>type()</strong> 函数可能是您的首选，因为它似乎与 JavaScript 的 typeof 相关。但是 <strong>type()</strong> 返回不同的东西：</p>
<p><code>&gt;&gt;&gt; type(tom)</code></p>
<p># 输出：&lt;class &#39;person.Person&#39;&gt;</p>
<blockquote>
<blockquote>
<blockquote>
<p>type(&#39;ahh&#39;)</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：&lt;类&#39;str&#39;&gt;</p>
<p>不太方便。 <strong>isinstance() 非常适合这里的工作</strong>，这就是我在上一节中引入它的原因。它的工作原理如下：</p>
<p><code>&gt;&gt;&gt; isinstance(9, int)</code></p>
<p># 输出：真</p>
<blockquote>
<blockquote>
<blockquote>
<p>isinstance(tom, Person)</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：真</p>
<blockquote>
<blockquote>
<blockquote>
<p>isinstance(&quot;caty&quot;, str)</p>
</blockquote>
</blockquote>
</blockquote>
<p># 输出：真</p>
<p><strong>当您需要根据另一个已知类型检查值时 <strong>isinstance()</strong> 很有用</strong>。然而，<strong>可能存在您需要模仿 typeof</strong> 的情况。在这种情况下，您仍然可以通过根据内置类型检查对象来使用 Python 的类型函数：</p>
<p><code>&gt;&gt;&gt; type(9) is int</code></p>
<p># 输出：真</p>
<h2>Python中如何处理异常：什么是异常？</h2>
<p>如果程序能一直运行良好就好了。但现实世界有点疯狂。如果一个程序可能会失败，那么它肯定会失败。</p>
<p>考虑一个简单的 Python 函数。这里可能会出现什么问题？</p>
<p><code>def divide(a, b):</code></p>
<p>result = a / b</p>
<p>return result</p>
<p>divide(89, 6)</p>
<p>divide(89, &quot;6&quot;)</p>
<p>divide(89, 2)</p>
<p>将代码保存在文件中（我将其命名为 <code>exceptions.py</code></p>
<p>）并运行它。你会看到很多东西，更重要的是，一个<code>TypeError</code></p>
<p>:</p>
<p><code>TypeError: unsupported operand type(s) for /: &#39;int&#39; and &#39;str&#39;</code></p>
<p>它来自对divide的第二次调用，我们试图将一个数字和一个字符串相除，这在Python中是无效的（在JavaScript中也是如此）。程序停止，永远不会到达第三个函数调用。</p>
<p>Python 在这里所做的是<strong>引发异常</strong>，即一个异常事件会导致我们的代码崩溃。</p>
<p>所以<strong>异常是严重的错误，大多数时候可以停止程序</strong>。我们如何<strong>处理异常</strong>决定了失败的程序和可以自行恢复的程序之间的区别。</p>
<h2>处理 Python 和 JavaScript 中的同步异常</h2>
<p>如果我们处于<strong>同步世界</strong>，那么在处理异常方面，Python 和 JavaScript 非常相似。</p>
<p>在Python中有<code>try/except</code></p>
<p>。 <code>try</code></p>
<p>块应该处理代码的“快乐路径”，而 <code>except</code></p>
<p>将拦截实际的异常。</p>
<p>前面的示例可以重构为：</p>
<p><code>def divide(a, b):</code></p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError:</p>
<p>print(&quot;Oops!&quot;)</p>
<p>divide(89, 6)</p>
<p>divide(89, &quot;6&quot;)</p>
<p>divide(89, 2)</p>
<p>请注意，您应该指定除 <code>TypeError</code> 之外的错误类型</p>
<p>在我们的例子中。</p>
<p><code>try/except</code></p>
<p>或多或少意味着：尝试此代码，如果失败<strong>拦截错误</strong>并执行其他操作。</p>
<p>现在程序打印“Oops!”，但是<strong>它不再停止</strong>。所有函数调用（除了出错的函数调用）都会继续运行。</p>
<p>您发现了如何<strong>在 Python 中处理异常</strong>！ JavaScript 怎么样？</p>
<p>考虑以下示例 (JavaScript)：</p>
<p><code>function find(member, target) {</code></p>
<p>return member in target;</p>
<p>}</p>
<p>find(&quot;a&quot;, &quot;siena&quot;);</p>
<p>这是对<code>in</code>的无效使用</p>
<p>运算符（仅适用于对象）。</p>
<p>运行代码，您应该看到：</p>
<p><code>TypeError: Cannot use &#39;in&#39; operator to search for &#39;a&#39; in siena</code></p>
<p>好的 JavaScript，很公平。为了处理错误，JavaScript 中有 <code>try/catch</code></p>
<p>。 <code>try</code></p>
<p>尝试快乐的道路，而<code>catch</code></p>
<p>处理问题。</p>
<p>我们可以将代码重写为：</p>
<p><code>function find(member, target) {</code></p>
<p>try {</p>
<p>return member in target;</p>
<p>} catch (err) {</p>
<p>console.log(&quot;Oops!&quot;);</p>
<p>}</p>
<p>}</p>
<p>find(&quot;a&quot;, &quot;siena&quot;);</p>
<p>var result = find(&quot;city&quot;, { name: &quot;Jane&quot;, city: &quot;London&quot; });</p>
<p>console.log(result);</p>
<p>现在程序打印“哎呀！”、“true”，并且<strong>不再停止</strong>。</p>
<p>注意参数<code>err</code></p>
<p>？让我们在下一节中看看如何使用它。</p>
<p>嘘。查看 <a href="https://www.valentinog.com/blog/error/">&quot;A mostly complete guide to error handling in JavaScript&quot;</a> 以获取有关错误和异常的深入指南。</p>
<h2>如何处理异常：在 Python 和 JavaScript 中使用错误消息</h2>
<p>处理异常固然很棒，但打印“Oops”却并非如此。最好打印<strong>错误消息</strong>。</p>
<p>在JavaScript中，我们可以使用<code>catch</code>的参数</p>
<p>，大多数时候叫<code>error</code></p>
<p>或<code>err</code></p>
<p>作为一个惯例。它包含实际的<strong>异常对象</strong>。</p>
<p>反过来，几乎每个异常都有一个名为 <code>message</code> 的属性</p>
<p>，与实际的文本错误。前面的 JavaScript 示例变为：</p>
<p><code>function find(member, target) {</code></p>
<p>try {</p>
<p>return member in target;</p>
<p>} catch (err) {</p>
<p>console.log(err.message);</p>
<p>}</p>
<p>}</p>
<p>find(&quot;a&quot;, &quot;siena&quot;);</p>
<p>var result = find(&quot;city&quot;, { name: &quot;Jane&quot;, city: &quot;London&quot; });</p>
<p>console.log(result);</p>
<p>打印：</p>
<p><code>Cannot use &#39;in&#39; operator to search for &#39;a&#39; in siena</code></p>
<p>真的</p>
<p>比“哎呀”好多了。</p>
<p>在Python中，你可以用<code>as</code>做同样的事情</p>
<p>:</p>
<p><code>def divide(a, b):</code></p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError as err:</p>
<p>print(err)</p>
<p>这个例子不言而喻：拦截<code>TypeError</code></p>
<p>并创建一个名为 <code>err</code> 的绑定</p>
<p>for convenience. Then print the error.</p>
<h2>在 Python 和 JavaScript 中引发自己的异常</h2>
<p>与编程中的几乎任何事物一样，即使对于最简单的事物，术语也是模糊的。</p>
<p>以术语<strong>抛出</strong>为例。当我们开发人员需要终止程序并说“呃，这不好，让我们停止”时，在 JavaScript 中通常会说“抛出”。</p>
<p>错误可能是 JavaScript 引擎抛出的，也可能是开发人员在检查无效值时故意抛出的。</p>
<p>我们也可以<strong>说“引发”而不是抛出，并将错误称为“异常”</strong>。你为什么会提出或抛出错误？再次考虑 JavaScript 示例。我们知道<code>in</code></p>
<p>运算符仅适用于对象。</p>
<p>如果我们检查参数 <strong>target</strong>，当它是字符串时，我们可以 <strong>抛出</strong> 错误。方法如下：</p>
<p><code>function find(member, target) {</code></p>
<p>if (typeof target === &quot;string&quot;)</p>
<p>throw TypeError(&quot;Target must be an object, got string&quot;);</p>
<p>try {</p>
<p>return member in target;</p>
<p>} catch (err) {</p>
<p>console.log(err.message);</p>
<p>}</p>
<p>}</p>
<p>现在调用该函数：</p>
<p><code>find(&quot;a&quot;, &quot;siena&quot;);</code></p>
<p>添加 throw 的最终效果是该函数的使用者将得到错误：</p>
<p><code>Error: Target must be an object, got string</code></p>
<p>这是预期的，如果目标是字符串，我们希望停止执行，因此代码永远不会到达 <code>try</code></p>
<p>堵塞。</p>
<p>现在让我们回到Python。我们留下了这段代码：</p>
<p><code>def divide(a, b):</code></p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError as err:</p>
<p>print(err)</p>
<p>这里我们可以在相除之前检查两个参数是否都是数字，然后抛出错误。 <code>throw</code></p>
<p>Python 中的对应项是 <code>raise</code></p>
<p>:</p>
<p><code>def divide(a, b):</code></p>
<p>if isinstance(a, str) or isinstance(b, str):</p>
<p>raise TypeError(&quot;预期，得到对象&quot;)</p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError as err:</p>
<p>print(err)</p>
<p>当调用该函数时：</p>
<p><code>divide(1, &quot;2&quot;)</code></p>
<p>你应该看到：</p>
<p><code>TypeError: Expected in, got object</code></p>
<p>注意这次使用<code>TypeError</code></p>
<p>for creating a custom error message. If you want you can also extend <code>Exception</code></p>
<p>创建您自己的自定义异常：</p>
<p><code>class CustomError(Exception):</code></p>
<p>pass</p>
<p>def divide(a, b):</p>
<p>if isinstance(a, str) or isinstance(b, str):</p>
<p>raise CustomError(&quot;预期，得到对象&quot;)</p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError as err:</p>
<p>print(err)</p>
<p>divide(1, &quot;2&quot;)</p>
<p>作为 <code>raise</code> 的替代品</p>
<p>我们也可以使用<code>assert</code></p>
<p>，方便开发中的调试：</p>
<p><code>def divide(a, b):</code></p>
<p>断言 isinstance(a, str), &quot;预期 int，得到对象&quot;</p>
<p>断言 isinstance(a, str), &quot;预期 int，得到对象&quot;</p>
<p>try:</p>
<p>return a / b</p>
<p>except TypeError as err:</p>
<p>print(err)</p>
<p>divide(1, &quot;2&quot;)</p>
<h2>使用 reStructuredText 编写 Python 代码文档</h2>
<p>在 <strong>JavaScript 中，我们使用 JSDoc</strong> 来添加类、函数参数、函数返回值等的文档。下面是 JSDoc 带注释的函数的示例：</p>
<p><code>/**</code></p>
<ul>
<li><p>将数字提高到指数</p>
</li>
<li><p>@param {number} value - 要提高的基数</p>
</li>
<li><p>@param {number} exponent - 指数</p>
</li>
<li><p>@return {number} - 指数幂</p>
</li>
</ul>
<p>*/</p>
<p>function poooow(value, exponent) {</p>
<p>return value ** exponent;</p>
<p>}</p>
<p>请注意参数和返回上的“number”类型。通过添加这些类型提示，您可以帮助 IDE 在您使用该函数时为您提供帮助（无双关语）。同样的概念也适用于 Python。</p>
<p><strong>如何在Python中添加代码文档</strong>？实际上有很多方法，但<strong>reStructuredText是推荐的方法之一</strong>。 reStructuredText 是纯文本，可以嵌入到 Python 文档字符串中。</p>
<p><strong>Docstring 只是一个恰好存在于 Python 函数或模块内部的字符串，并充当代码的文档</strong>。为了给您提供一些背景信息，这里有一个 Python 函数内的 Docstring 示例：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>”“”</p>
<p>return string * count</p>
<p>当您决定添加<strong>参数和返回值的文档</strong>时，reStructuredText 就会发挥作用。这是我们的示例，使用 reStructuredText 进行了丰富：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>:param count: 重复次数</p>
<p>:return: 字符串重复N次</p>
<p>”“”</p>
<p>return string * count</p>
<p>我知道，<strong>文档可能看起来多余</strong>，但如果您决定尝试静态类型，reStructuredText 可以<strong>大放异彩</strong>。首先，有一点类型理论。</p>
<h2>一点类型理论：动态类型与静态类型</h2>
<p><strong>Python 和 JavaScript 是动态语言</strong>。也就是说，它们给予程序员几乎绝对的自由。例如，在 JavaScript 中，变量可能首先包含字符串，然后更改为包含布尔值。 JavaScript 引擎不会抱怨。 （但是，您可以使用 <strong>const</strong> 防止重新分配基本类型）。</p>
<p>Python 也做同样的事情。考虑以下示例：</p>
<p><code>&gt;&gt;&gt; name = &quot;Caty&quot;</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>name = True</p>
</blockquote>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<blockquote>
<p>print(name)</p>
</blockquote>
</blockquote>
</blockquote>
<p>真的</p>
<p>变量 <strong>name</strong> 最初是字符串类型，但后来更改为布尔类型。大多数时候<strong>通过自律，你可以驯服动态打字并在晚上睡觉</strong>。在某些情况下，动态类型可能是不允许的，或者风险太大（想想金融系统）。</p>
<p>与动态类型相反，<strong>静态类型</strong>意味着为每个变量分配一个<strong>固定类型</strong>，因此变得<strong>更难以意外更改类型</strong>。</p>
<p>然而，<strong>静态类型是一种不同的野兽</strong>，学习它可能是一个<strong>痛苦的过程，特别是对于初学者来说</strong>。</p>
<p>幸运的是，在 JavaScript 和 Python 中，我们都可以使用<strong>文档来“逐步打字”</strong>。</p>
<p>让我们在下一节中了解如何<strong>在 Python 中使用 reStructuredText 添加类型</strong>。</p>
<h2>使用 reStructuredText 在 Python 中逐步输入</h2>
<p>借助 reStructuredText，您可以熟悉 Python 中的静态类型，而无需在代码中添加实际类型。</p>
<p>除了“:param”和“:return”等常见标签之外，reStructuredText还有**:type<strong>和</strong>:rtype**，分别用于<strong>为参数和返回值添加类型</strong>。</p>
<p>如果您想跟随代码进行操作，那么现在是创建并激活 Python 虚拟环境的好时机（在下一节中，我们还需要安装 mypy）：</p>
<p><code>mkdir docs_and_typings &amp;&amp; cd $_</code></p>
<p>python3 -m venv venv</p>
<p>源 venv/bin/activate</p>
<p>为了说明该示例，请在项目文件夹中创建一个名为 <strong>my_str_utils.py</strong> 的新文件，其中包含以下函数：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>:param count: 重复次数</p>
<p>:return: 字符串重复N次</p>
<p>”“”</p>
<p>return string * count</p>
<p>现在让我们使用 :type 和 :rtype** 在 reStructuredText 中添加 **类型：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>：类型字符串：str</p>
<p>:param count: 重复次数</p>
<p>：类型计数：int</p>
<p>:return: 字符串重复N次</p>
<p>:r 类型：str</p>
<p>”“”</p>
<p>return string * count</p>
<p>这是<strong>渐进式打字</strong>：您现在拥有一个类型化函数，而没有静态类型系统的认知负担。 <strong>大多数 IDE 都能够读取 reStructuredText 类型</strong>，例如在 PyCharm 中 <strong>当参数的类型与实际参数的类型不匹配时，您会收到警告</strong>：</p>
<p>同样在 Pycharm 中，通过单击函数名称并按 Ctrl+Q（或 MacO 上的 F1），您可以获得实际的类型提示：</p>
<p>这些提示与我们将在下一节中看到的“<strong>真实类型提示</strong>”相同（大多数时候，即使没有 :rtype，PyCharm 也能够通过检查 return 语句来推断返回类型）。</p>
<p>在 JavaScript 中，我们可以使用 <a href="https://www.valentinog.com/blog/jsdoc/">JSDoc types</a> 获得相同的效果。</p>
<h2>Python 和 JavaScript 中的静态类型</h2>
<p>我之前给出的渐进打字的定义有点模糊。确实，<strong>您可以通过文档字符串中的代码文档了解静态类型</strong>。</p>
<p><strong>但是渐进类型的更严格解释是：在代码中逐渐添加真实类型的过程</strong>。现在我所说的“类型”是指可以使用工具检查的类型注释。</p>
<p>JavaScript 有 <strong>TypeScript</strong>：JavaScript 之上的一层，您可以插入其中。 <a href="https://www.valentinog.com/blog/typescript/">TypeScript is an actual language on its own</a>，但可以逐渐适应任何 JavaScript 代码库。</p>
<p><strong>Python</strong> 也是如此：近年来它获得了 <a href="https://www.python.org/dev/peps/pep-0484/">an optional type system based on &quot;type hints&quot;</a>。在这里，我们将在 30,000 英尺的高度看到 Python 类型提示。 <strong>一旦掌握了基础知识</strong>希望<strong>您将能够将类型应用到您的Python代码中</strong>。让我们采用上一节中的 <strong>string_repeat</strong> ：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>：类型字符串：str</p>
<p>:param count: 重复次数</p>
<p>：类型计数：int</p>
<p>:return: 字符串重复N次</p>
<p>:r 类型：str</p>
<p>”“”</p>
<p>return string * count</p>
<p>这次我们将去掉 reStructuredText 类型：</p>
<p><code>def string_repeat(string, count):</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>:param count: 重复次数</p>
<p>:return: 字符串重复N次</p>
<p>”“”</p>
<p>return string * count</p>
<p>此时 IDE 将失去所有提示。但是如果您还记得上一节中的“真实”类型提示就像“参数：类型”，那么将它们添加到函数签名中应该很容易：</p>
<p><code>def string_repeat(string: str, count: int):</code></p>
<p># 忽略</p>
<p>该样式与 TypeScript 使用的样式类似。您还可以使用 <strong>-&gt; type</strong> 键入返回值：</p>
<p><code>def string_repeat(string: str, count: int) -&gt; str:</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>:param count: 重复次数</p>
<p>:return: 字符串重复N次</p>
<p>”“”</p>
<p>return string * count</p>
<p>对代码进行类型注释后，您可以使用名为 <strong>mypy</strong> 的工具检查其正确性，这是我们下一节的主题。</p>
<h2>使用 mypy 检查类型</h2>
<p><strong>mypy</strong> 是一个 <strong>Python 类型检查器</strong>。要在测试项目中安装 mypy，请确保激活虚拟环境，然后运行：</p>
<p><code>pip install mypy</code></p>
<p>打开 <strong>my_str_utils.py</strong> 并尝试将 <strong>string_repeat</strong> 与 float 而不是 int 一起使用：</p>
<p><code>def string_repeat(string: str, count: int) -&gt; str:</code></p>
<p>”“”</p>
<p>重复字符串 N 次</p>
<p>:param string: 要重复的字符串</p>
<p>:param count: 重复次数</p>
<p>:return: 字符串重复N次</p>
<p>”“”</p>
<p>return string * count</p>
<p>string_repeat(&#39;hello&#39;, 15.6)</p>
<p>IDE 会警告您，但您也可以<strong>对 Python 脚本使用 mypy</strong>：</p>
<p><code>mypy my_str_utils.py</code></p>
<p>mypy 也会警告你：</p>
<p><code>my_str_utils.py:11: error: Argument 2 to &quot;string_repeat&quot; has incompatible type &quot;float&quot;; expected &quot;int&quot;</code></p>
<p>在 1 个文件中发现 1 个错误（检查了 1 个源文件</p>
<p>与编译为“普通”JavaScript 的 TypeScript 不同，<strong>mypy 不会生成任何代码，它只是检查其类型</strong>。</p>
<h2>面向 JavaScript 开发人员的 Python：更进一步</h2>
<p>您可能感兴趣的其他文章：</p>
<p>感谢您的阅读并继续关注此博客！</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/py-js#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">69ce61a955b8ebcb73daa3a9</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue 2（含 &lt;2.6）如何升级兼容 Composition API 原理</title>
    <link>https://server.amfishers.com/posts/technology/vue2-update-composition-api</link>
    <pubDate>Mon, 01 Dec 2025 07:54:04 GMT</pubDate>
    <description>本文详细说明本项目如何在 Vue 2（包括低于 2.6 的版本）上通过插件注入与运行时适配，提供与 </description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue2-update-composition-api'>https://server.amfishers.com/posts/technology/vue2-update-composition-api</a></blockquote>
      <blockquote>
<p>本文详细说明本项目如何在 Vue 2（包括低于 2.6 的版本）上通过插件注入与运行时适配，提供与 Vue 3 Composition API 接近的开发体验。内容覆盖安装入口、启用机制、运行时上下文桥接、响应式与计算/侦听适配、插槽与生命周期、兼容策略、执行时序、常见问题与限制，以及关键代码索引。
阅读本文时，请配合 composition-api 源码食用  <a href="https://github.com/vuejs/composition-api">https://github.com/vuejs/composition-api</a></p>
</blockquote>
<h2>一、背景与总体思路</h2>
<ul>
<li>目标：在不依赖 Vue 3 内核（Proxy/Effect）的前提下，让 Vue 2 应用可以使用 <code>setup()</code>、<code>ref/reactive/computed/watch</code> 等 Composition API。</li>
<li>总体方法：通过 <code>Vue.use(Plugin)</code> 安装插件，在全局混入与选项合并层面“接入” Vue 2 的组件初始化流程，同时复用 Vue 2 的 <code>Observer/Dep/Watcher</code> 作为底层响应式机制。</li>
<li>关键桥接：构造 Vue3-like 的“当前实例上下文”（<code>getCurrentInstance()</code> 等），并将返回的 <code>setup</code> 对象或函数正确注入到 Vue 2 的渲染/实例属性中。</li>
</ul>
<h2>二、安装入口与引入即用</h2>
<ul>
<li>主入口导出并安装插件：<ul>
<li><code>src/index.ts:15</code> 导出 <code>Plugin</code>；<code>src/index.ts:25</code> 在浏览器存在 <code>window.Vue</code> 时自动执行 <code>window.Vue.use(Plugin)</code>。</li>
<li>CommonJS 入口：<code>index.js:3-6</code> 按 <code>NODE_ENV</code> 指向 dev/prod 构建文件。</li>
</ul>
</li>
<li>安装对象与执行：<ul>
<li><code>src/install.ts:80-82</code> 定义 <code>Plugin.install(Vue)</code>；内部调用 <code>install(Vue)</code> 完成注册。</li>
</ul>
</li>
<li>为什么“引入文件即可生效”：<ul>
<li>当以 CDN 或打包方式引入入口文件，若全局存在 <code>Vue</code>，会自动 <code>Vue.use(Plugin)</code>；否则在应用入口手动 <code>Vue.use(Plugin)</code> 即完成接入。</li>
</ul>
</li>
</ul>
<h2>三、启用机制：setup 合并策略 + 全局混入</h2>
<ul>
<li>选项合并策略：<ul>
<li><code>src/install.ts:64-74</code> 为 <code>setup</code> 设置合并规则，支持父子组件的 <code>setup</code> 共存与返回对象的融合，约束执行顺序与一致性。</li>
</ul>
</li>
<li>全局混入注入：<ul>
<li><code>src/mixin.ts:30-42</code> 通过 <code>Vue.mixin</code> 在 <code>beforeCreate</code> 阶段调用 <code>functionApiInit</code>，将 Composition API 接入每个组件实例。</li>
<li>保持渲染上下文：<code>src/mixin.ts:53-59</code> 包装 <code>render</code>，在渲染时激活当前组件实例上下文。</li>
<li>执行顺序控制：<code>src/mixin.ts:75-85</code> 重写 <code>data</code> 解析顺序，保证 <code>setup</code> 先于 <code>data</code> 执行，以避免低版本 Vue 的选项时序差异导致行为不一致。</li>
</ul>
</li>
<li><code>setup</code> 返回值处理：<ul>
<li>返回函数：作为渲染函数使用（<code>src/mixin.ts:106-114</code>），直接参与 VNode 生成。</li>
<li>返回对象：对 <code>ref/reactive/function</code> 等进行自动解包与保护，并挂载到实例上（<code>src/mixin.ts:115-147</code>）。</li>
</ul>
</li>
<li>局部响应式绑定：<ul>
<li>为包含响应式子项（如数组）的对象执行局部 <code>defineReactive</code>，减小副作用面（<code>src/mixin.ts:161-183</code>）。</li>
</ul>
</li>
</ul>
<h2>四、运行时上下文桥接（Vue2 → Vue3 风格）</h2>
<ul>
<li>当前实例管理与暴露：<ul>
<li><code>getCurrentInstance()</code>：<code>src/runtimeContext.ts:232-234</code>。</li>
<li>激活/恢复实例：<code>src/runtimeContext.ts:104-110,261-268</code>，确保生命周期与渲染期间上下文一致。</li>
</ul>
</li>
<li>Vue3-like 实例描述：<ul>
<li>将 Vue2 vm 映射为 <code>ComponentInternalInstance</code> 近似结构（<code>src/runtimeContext.ts:241-320</code>）。</li>
</ul>
</li>
<li>安装状态与多实例防护：<ul>
<li>已安装判定与重复安装警告：<code>src/runtimeContext.ts:45-48,72-83</code>；<code>src/install.ts:43-49</code>。</li>
<li>版本校验提示：<code>src/install.ts:52-62</code>。</li>
</ul>
</li>
</ul>
<h2>五、响应式适配：reactive/readonly/ref</h2>
<ul>
<li>复用 Vue2 响应式：<ul>
<li><code>observe/defineReactive</code> 作为响应式基石（<code>src/reactivity/reactive.ts:231-249</code>）。</li>
<li>访问控制与自动解包：<code>defineAccessControl/proxy</code>（<code>src/reactivity/reactive.ts:52-114</code>），在读取时自动解包 <code>ref</code>，在写入只读对象时进行拦截。</li>
<li>原始对象关联与跳过标记：通过 <code>__ob__</code>、<code>SKIPFLAG/rawSet</code> 标识（<code>src/reactivity/reactive.ts:160-176,251-281</code>）。</li>
</ul>
</li>
</ul>
<h2>六、计算属性与侦听（computed/watch/watchEffect）</h2>
<ul>
<li>computed 适配：<ul>
<li>有 vm：直接用 Vue2 <code>Watcher</code> 构建 lazy 计算，提供 <code>evaluate/depend</code>（<code>src/apis/computed.ts:26-57</code>）。</li>
<li>无 vm/SSR：创建“宿主组件”承载 <code>computed</code>（<code>src/apis/computed.ts:62-83</code>）。</li>
</ul>
</li>
<li>watch / watchEffect：<ul>
<li>基于 <code>$watch(getter, callback, { immediate, deep, sync })</code>（<code>src/apis/watch.ts:379-387</code>）。</li>
<li>补丁清理：劫持 <code>teardown</code> 注入副作用清理（<code>src/apis/watch.ts:192-200,402-407</code>），避免内存泄漏与残留订阅。</li>
</ul>
</li>
</ul>
<h2>七、插槽与生命周期</h2>
<ul>
<li>插槽代理：<ul>
<li>将 Vue2 插槽转换为函数式访问，使其更接近 Vue3 的 <code>slots</code> 使用范式（<code>src/utils/instance.ts:161-180</code>、<code>src/utils/helper.ts:41-55</code>）。</li>
</ul>
</li>
<li>生命周期钩子：<ul>
<li>统一包装调用并维护当前实例上下文（<code>wrapHookCall</code>），各 <code>onMounted/onUpdated/...</code> 以同样方式暴露（<code>src/apis/lifecycle.ts:33-58</code>）。</li>
</ul>
</li>
</ul>
<h2>八、对 Vue&lt;2.6 的兼容策略</h2>
<ul>
<li>不依赖 Vue3 内核：完全复用 Vue2 的 <code>Observer/Dep/Watcher</code>。</li>
<li>能力缺失的场景下提供回退：通过宿主组件或代理机制补足（例如无 vm 的 <code>computed</code>）。</li>
<li>插槽与 <code>scopedSlots</code> 的差异用代理函数化统一访问，屏蔽低版本差异。</li>
<li><code>setup</code> 专属合并与时序控制，避免低版本选项解析导致的执行顺序问题。</li>
<li>严格的安装/多实例防护，降低复杂构建/微前端场景下上下文错配的风险。</li>
</ul>
<h2>九、典型执行时序（组件创建）</h2>
<ol>
<li>应用引入插件，自动或手动 <code>Vue.use(Plugin)</code>（<code>src/index.ts:25</code>）。</li>
<li>全局混入生效，组件在 <code>beforeCreate</code> 进入 <code>functionApiInit</code>（<code>src/mixin.ts:30-42</code>）。</li>
<li>包装渲染与数据解析，保证 <code>setup</code> 优先执行（<code>src/mixin.ts:53-59,75-85</code>）。</li>
<li>构造 <code>SetupContext</code> 并执行 <code>setup</code>：<ul>
<li>返回函数 → 设为 <code>render</code>（<code>src/mixin.ts:106-114</code>）。</li>
<li>返回对象 → 自动解包并挂载为实例属性（<code>src/mixin.ts:115-147</code>）。</li>
</ul>
</li>
<li>如返回值包含响应式子项，进行局部 <code>defineReactive</code>（<code>src/mixin.ts:161-183</code>）。</li>
<li>生命周期钩子按需调用，期间激活当前实例上下文（<code>src/apis/lifecycle.ts:33-58</code>、<code>src/runtimeContext.ts:104-110</code>）。</li>
</ol>
<h2>十、常见问题与限制</h2>
<ul>
<li>必须先安装：未 <code>Vue.use(Plugin)</code> 就使用 API 会触发断言/警告（<code>src/runtimeContext.ts:50-57</code>）。</li>
<li>重复安装与多 Vue 构造：会给出警告，避免上下文错配（<code>src/install.ts:43-49</code>、<code>src/runtimeContext.ts:72-83</code>）。</li>
<li>行为差异：由于底层是 Vue2 的响应式系统，个别边界行为与 Vue3 可能不完全一致（例如深层 Proxy 行为、依赖收集的粒度）。</li>
<li>SSR/无实例：<code>computed/watch</code> 会走宿主组件或降级路径，性能与时序需关注。</li>
</ul>
<h2>十一、关键代码索引（含行号）</h2>
<ul>
<li>入口与安装：<ul>
<li><code>src/index.ts:15,25</code>；<code>index.js:3-6</code></li>
<li>插件安装：<code>src/install.ts:64-78,80-82</code></li>
</ul>
</li>
<li>运行时上下文：<ul>
<li>安装状态与校验：<code>src/runtimeContext.ts:45-48,72-83</code></li>
<li>当前实例与映射：<code>src/runtimeContext.ts:104-110,232-234,241-320,261-268</code></li>
</ul>
</li>
<li>混入与 setup 注入：<ul>
<li><code>src/mixin.ts:30-42,53-59,65-73,75-85,87-159,161-183</code></li>
</ul>
</li>
<li>响应式适配：<ul>
<li><code>src/reactivity/reactive.ts:52-114,160-176,231-249,251-281</code></li>
</ul>
</li>
<li>computed/watch：<ul>
<li><code>src/apis/computed.ts:26-57,62-83</code></li>
<li><code>src/apis/watch.ts:192-200,379-387,402-407</code></li>
</ul>
</li>
<li>插槽代理：<ul>
<li><code>src/utils/instance.ts:161-180</code>；<code>src/utils/helper.ts:41-55</code></li>
</ul>
</li>
<li>生命周期：<ul>
<li><code>src/apis/lifecycle.ts:33-58</code></li>
</ul>
</li>
</ul>
<h2>十二、快速使用指南</h2>
<ul>
<li>安装：在入口文件中执行 <code>import Plugin from &#39;...&#39; ; Vue.use(Plugin)</code>。</li>
<li>组件：<ul>
<li>使用 <code>setup(props, ctx)</code> 返回对象或渲染函数；对象中使用 <code>ref/reactive/computed</code> 等 API。</li>
<li>在 <code>onMounted/onUpdated/...</code> 中编写副作用逻辑，<code>watch</code>/<code>watchEffect</code> 根据需要侦听与清理。</li>
</ul>
</li>
</ul>
<h2>十三、总结</h2>
<ul>
<li>该插件通过安装与全局混入，将 Composition API 嵌入到 Vue 2 的组件初始化与响应式系统之中。</li>
<li>响应式与计算/侦听复用 Vue2 的 <code>Observer/Dep/Watcher</code>，并在缺失能力的场景下提供宿主/代理回退。</li>
<li>运行时上下文桥接保证了 <code>getCurrentInstance</code>、插槽、生命周期的可用与一致体验，从而实现“引入即用”的 Composition API 支持。</li>
</ul>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue2-update-composition-api#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">692d499c23fc271151500dd7</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>命运根本没有给我出题</title>
    <link>https://server.amfishers.com/notes/12</link>
    <pubDate>Tue, 25 Nov 2025 00:42:31 GMT</pubDate>
    <description>昨天晒太阳的时候，我突然意识到，既然我认识到命运不该被拟人化，命运既不给予也不剥夺，不是恩人也不是仇</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/notes/12'>https://server.amfishers.com/notes/12</a></blockquote>
      <p>昨天晒太阳的时候，我突然意识到，既然我认识到命运不该被拟人化，命运既不给予也不剥夺，不是恩人也不是仇人，那我也不该把它看成一个针对我的出题考官。命运只是发生，好事发生，坏事发生，相似的事情发生，陌生的事情发生。
没有出题人，没有考题，没有新答案，没有考官。本质上，是我看待命运的方式决定了我如何解释生活中发生的事情。想要弥补遗憾的执念困住了我自己。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/notes/12#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">6924fb7723fc2711514fdbd3</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>努力也是一种能力</title>
    <link>https://server.amfishers.com/notes/10</link>
    <pubDate>Tue, 14 Oct 2025 01:31:02 GMT</pubDate>
    <description>可是当我拿起单词表来，却发现连十分钟都不能安心的去背单词，各种破碎繁杂的思绪纷至沓来，让我想放下书本</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/notes/10'>https://server.amfishers.com/notes/10</a></blockquote>
      <p>可是当我拿起单词表来，却发现连十分钟都不能安心的去背单词，各种破碎繁杂的思绪纷至沓来，让我想放下书本，刷一下知乎，看一下朋友圈，逗逗狗狗。</p>
<p>突然惊觉，努力并不是一种选择，它是一种能力，它需要心神凝聚，需要很好的执行力，需要心静，需要专注，这些都是需要在漫长的生活中一点一滴培养和固化的。</p>
<p>一个人长久自律的努力即是一种修行</p>
<p>努力的方向或许每个人是不同的，或是钱财名利或是想赢或是梦想或是平淡生活，但努力这种能力是相通的，这种修行路漫漫其修远兮，需上下而求索。</p>
<p>努力本身并不能带来幸福，达成了什么，赢得了什么，这些努力的成果有时候甚至和你的初衷背道而驰。但是一个幸福的人无疑在生活中拥有很好的心性和智慧，而幸福的修行和努力的能力是殊途同归的，它们的内核是相通的。</p>
<p>我不愿眼里的神采追逐在手机屏幕上，我还要奔跑还要去看看这世界的大好河山。</p>
<p>我不愿手指的灵性委顿于零食键盘间，我还要写故事要画画要抚摸夜里穿越过亿万年的星光。</p>
<p>努力，修行，努力修行。</p>
<p>若有一天我匍匐在菩提树下，愿不是因为我疲懒无力。</p>
<p>而是我跨越千山万水终于归于原点的虔诚。</p>
<p>幸而此刻并不太晚，幸而永远不会太晚。</p>
<p>和自己争夺自己。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/notes/10#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68eda7d61a2382c1a867db32</guid>
  <category>notes</category>
false
 </item>
  <item>
    <title>Vue3系列 - 组件通信方式</title>
    <link>https://server.amfishers.com/posts/technology/vue-communication-methods</link>
    <pubDate>Fri, 03 Oct 2025 15:47:13 GMT</pubDate>
    <description>Vue3提供了多种组件间通信的方式，满足不同场景的需求。

主要的组件通信方式：

Props向下传</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-communication-methods'>https://server.amfishers.com/posts/technology/vue-communication-methods</a></blockquote>
      <p>Vue3提供了多种组件间通信的方式，满足不同场景的需求。</p>
<p>主要的组件通信方式：</p>
<ol>
<li><strong>Props向下传递</strong>：父组件通过props向子组件传递数据。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="2">
<li><strong>事件向上传递</strong>：子组件通过事件向父组件发送消息。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="3">
<li><p><strong>v-model双向绑定</strong>：在父子组件间建立双向数据绑定。</p>
</li>
<li><p><strong>依赖注入</strong>：使用<code>provide</code>和<code>inject</code>在祖先和后代组件间传递数据。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="5">
<li><p><strong>事件总线</strong>：在Vue3中，可以使用外部的事件库或创建一个空的Vue实例作为事件中心。</p>
</li>
<li><p><strong>Vuex/Pinia状态管理</strong>：对于复杂应用，可以使用状态管理库集中管理共享状态。</p>
</li>
<li><p><strong>组合式API</strong>：通过<code>setup</code>函数和组合式API，可以更灵活地组织和共享组件逻辑。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="8">
<li><strong>Refs引用</strong>：通过<code>ref</code>属性获取子组件实例，直接调用其方法或访问其数据。</li>
</ol>
<p>选择合适的通信方式取决于组件间的关系和通信的复杂度，合理使用这些方式可以构建出清晰、可维护的组件架构。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-communication-methods#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7c1e1a2382c1a867c94b</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue3系列 - 渲染优化技术</title>
    <link>https://server.amfishers.com/posts/technology/vue-render-optimization</link>
    <pubDate>Fri, 03 Oct 2025 15:45:50 GMT</pubDate>
    <description>Vue3采用了多种渲染优化技术来提高性能，这些技术主要体现在虚拟DOM的实现和响应式系统中。

主要</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-render-optimization'>https://server.amfishers.com/posts/technology/vue-render-optimization</a></blockquote>
      <p>Vue3采用了多种渲染优化技术来提高性能，这些技术主要体现在虚拟DOM的实现和响应式系统中。</p>
<p>主要的渲染优化技术：</p>
<ol>
<li><p><strong>虚拟DOM</strong>：Vue使用虚拟DOM来最小化实际DOM操作，只更新必要的部分。</p>
</li>
<li><p><strong>diff算法优化</strong>：Vue3改进了diff算法，通过静态提升、事件缓存等技术减少了比对开销。</p>
</li>
<li><p><strong>响应式系统</strong>：通过精确的依赖追踪，Vue只重新渲染依赖已更改数据的组件。</p>
</li>
<li><p><strong>编译优化</strong>：Vue3的模板编译器能够识别静态内容，减少运行时的工作量。</p>
</li>
<li><p><strong>异步更新队列</strong>：Vue将DOM更新操作缓存在队列中，然后一次性执行，避免不必要的计算和渲染。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="6">
<li><strong>计算属性缓存</strong>：计算属性只有在其依赖项变化时才会重新计算。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="7">
<li><strong>组件实例复用</strong>：通过<code>key</code>属性，Vue可以在列表渲染中复用组件实例，减少创建和销毁的开销。</li>
</ol>
<p>这些优化技术共同作用，使Vue能够在处理复杂UI时保持高性能。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-render-optimization#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7bd31a2382c1a867c935</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue3系列 - 自定义指令的实现</title>
    <link>https://server.amfishers.com/posts/technology/vue-directive</link>
    <pubDate>Thu, 02 Oct 2025 15:44:59 GMT</pubDate>
    <description>Vue3中的自定义指令允许开发者直接操作DOM元素，为框架增加了更多的灵活性。

自定义指令的核心实</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-directive'>https://server.amfishers.com/posts/technology/vue-directive</a></blockquote>
      <p>Vue3中的自定义指令允许开发者直接操作DOM元素，为框架增加了更多的灵活性。</p>
<p>自定义指令的核心实现：</p>
<ol>
<li><p><strong>指令钩子函数</strong>：指令定义了一系列的钩子函数，对应元素的不同生命周期。</p>
<ul>
<li><code>bind</code>：指令第一次绑定到元素时调用</li>
<li><code>inserted</code>：被绑定元素插入父节点时调用</li>
<li><code>update</code>：所在组件的VNode更新时调用</li>
<li><code>componentUpdated</code>：指令所在组件的VNode及其子VNode全部更新后调用</li>
<li><code>unbind</code>：指令与元素解绑时调用</li>
</ul>
</li>
<li><p><strong>指令注册</strong>：可以全局注册或组件内注册。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="3">
<li><p><strong>指令参数</strong>：每个钩子函数接收以下参数：</p>
<ul>
<li><code>el</code>：指令所绑定的元素</li>
<li><code>binding</code>：包含指令的各种属性的对象</li>
<li><code>vnode</code>：Vue编译生成的虚拟节点</li>
<li><code>oldVnode</code>：上一个虚拟节点（仅在update和componentUpdated钩子中可用）</li>
</ul>
</li>
<li><p><strong>动态参数</strong>：Vue3支持动态指令参数，可以根据组件实例数据动态改变。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><p>自定义指令为处理DOM操作提供了强大的工具，特别适合于需要直接操作DOM的场景，如管理焦点、滚动行为、或集成第三方库。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-directive#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7b8a1a2382c1a867c91f</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue3系列 - 组件生命周期的执行顺序</title>
    <link>https://server.amfishers.com/posts/technology/vue-apiLifecycle</link>
    <pubDate>Wed, 01 Oct 2025 15:43:12 GMT</pubDate>
    <description>Vue3中组件生命周期钩子的实现位于src/v3/apiLifecycle.ts，它定义了组件从创建</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-apiLifecycle'>https://server.amfishers.com/posts/technology/vue-apiLifecycle</a></blockquote>
      <p>Vue3中组件生命周期钩子的实现位于<code>src/v3/apiLifecycle.ts</code>，它定义了组件从创建到销毁的各个阶段。</p>
<p>生命周期钩子的执行顺序：</p>
<ol>
<li><p><strong>创建阶段</strong>：</p>
<ul>
<li><code>onBeforeMount</code>：组件挂载到DOM前调用</li>
<li><code>onMounted</code>：组件挂载到DOM后调用</li>
</ul>
</li>
<li><p><strong>更新阶段</strong>：</p>
<ul>
<li><code>onBeforeUpdate</code>：组件更新前调用</li>
<li><code>onUpdated</code>：组件更新后调用</li>
</ul>
</li>
<li><p><strong>销毁阶段</strong>：</p>
<ul>
<li><code>onBeforeUnmount</code>：组件卸载前调用</li>
<li><code>onUnmounted</code>：组件卸载后调用</li>
</ul>
</li>
<li><p><strong>特殊钩子</strong>：</p>
<ul>
<li><code>onActivated</code>：被keep-alive缓存的组件激活时调用</li>
<li><code>onDeactivated</code>：被keep-alive缓存的组件停用时调用</li>
<li><code>onErrorCaptured</code>：捕获后代组件错误时调用</li>
<li><code>onRenderTracked</code>：跟踪虚拟DOM重新渲染时调用</li>
<li><code>onRenderTriggered</code>：虚拟DOM重新渲染被触发时调用</li>
</ul>
</li>
</ol>
<p>生命周期钩子的实现机制：</p>
<pre><code class="language-undefined">[object Object]</code></pre><p>在父子组件嵌套的情况下，生命周期钩子的执行顺序是：</p>
<ul>
<li>创建：父beforeCreate -&gt; 父created -&gt; 父beforeMount -&gt; 子beforeCreate -&gt; 子created -&gt; 子beforeMount -&gt; 子mounted -&gt; 父mounted</li>
<li>更新：父beforeUpdate -&gt; 子beforeUpdate -&gt; 子updated -&gt; 父updated</li>
<li>销毁：父beforeUnmount -&gt; 子beforeUnmount -&gt; 子unmounted -&gt; 父unmounted</li>
</ul>
<p>理解生命周期钩子的执行顺序对于正确管理组件状态和资源非常重要。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-apiLifecycle#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7b1d1a2382c1a867c908</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue3系列 - 响应式系统的限制</title>
    <link>https://server.amfishers.com/posts/technology/vue-reactive-limit</link>
    <pubDate>Wed, 01 Oct 2025 15:41:36 GMT</pubDate>
    <description>Vue3的响应式系统虽然强大，但也存在一些限制，这些限制主要体现在reactive.ts和相关文件中</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-reactive-limit'>https://server.amfishers.com/posts/technology/vue-reactive-limit</a></blockquote>
      <p>Vue3的响应式系统虽然强大，但也存在一些限制，这些限制主要体现在<code>reactive.ts</code>和相关文件中。</p>
<p>主要限制包括：</p>
<ol>
<li><strong>数组索引和长度变化</strong>：虽然Vue可以检测到通过索引设置数组元素的变化，但这种操作不是响应式的最佳实践。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="2">
<li><p><strong>新增属性</strong>：对于已创建的响应式对象，直接添加新属性不会触发更新，需要使用<code>Vue.set</code>或扩展运算符创建新对象。</p>
</li>
<li><p><strong>删除属性</strong>：同样，直接删除属性也不会触发更新，需要使用<code>Vue.delete</code>。</p>
</li>
<li><p><strong>Map和Set</strong>：在Vue2兼容模式下，不支持Map和Set等集合类型的响应式。</p>
</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="5">
<li><strong>原始值包装</strong>：原始值（如字符串、数字）需要通过<code>ref</code>包装才能变成响应式。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="6">
<li><strong>深层嵌套对象</strong>：过深的对象嵌套可能导致性能问题，因为Vue会递归地将每个嵌套对象转换为响应式。</li>
</ol>
<p>了解这些限制有助于我们更好地使用Vue的响应式系统，避免常见的陷阱。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-reactive-limit#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7af31a2382c1a867c8f2</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  <item>
    <title>Vue3系列 - 模板引用（Refs）的实现</title>
    <link>https://server.amfishers.com/posts/technology/vue-ref</link>
    <pubDate>Tue, 30 Sep 2025 15:40:41 GMT</pubDate>
    <description>Vue3中的模板引用（Refs）允许我们直接访问DOM元素或子组件实例，其实现主要在src/v3/r</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://server.amfishers.com/posts/technology/vue-ref'>https://server.amfishers.com/posts/technology/vue-ref</a></blockquote>
      <p>Vue3中的模板引用（Refs）允许我们直接访问DOM元素或子组件实例，其实现主要在<code>src/v3/reactivity/ref.ts</code>中。</p>
<p>模板引用的核心实现：</p>
<ol>
<li><strong>Ref接口</strong>：定义了具有响应式<code>value</code>属性的对象。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="2">
<li><strong>ref函数</strong>：创建一个包装对象，使原始值变成响应式。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="3">
<li><strong>createRef实现</strong>：内部使用<code>defineReactive</code>来实现响应式。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="4">
<li><strong>isRef函数</strong>：检查一个值是否为ref对象。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><ol start="5">
<li><strong>unref函数</strong>：如果参数是ref则返回其<code>.value</code>，否则返回参数本身。</li>
</ol>
<pre><code class="language-undefined">[object Object]</code></pre><p>模板引用为访问底层DOM和组件实例提供了便捷的方式，同时保持了Vue响应式系统的一致性。</p>

      <p style='text-align: right'>
      <a href='https://server.amfishers.com/posts/technology/vue-ref#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68ea7a971a2382c1a867c8dc</guid>
  <category>posts</category>
<category>Technology</category>
 </item>
  
</channel>
</rss>