mirror of
https://github.com/ZiuChen/ZiuChen.github.io.git
synced 2025-12-18 17:04:16 +08:00
2013 lines
443 KiB
HTML
2013 lines
443 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en-US">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>JavaScript 高级教程 | ZiuChen</title>
|
||
<meta name="generator" content="VuePress 1.9.7">
|
||
<link rel="icon" href="/logo.png">
|
||
<script>
|
||
var _hmt = _hmt || [];
|
||
(function() {
|
||
var isDev = document.location.href.indexOf("localhost") !== -1
|
||
var isGitee = document.location.href.indexOf("gitee.io") !== -1
|
||
var hm1 = document.createElement("script");
|
||
hm1.src = "https://hm.baidu.com/hm.js?08b4ef50a9244e83e5a1bd5822442829"; // gitee
|
||
var hm2 = document.createElement("script");
|
||
hm2.src = "https://hm.baidu.com/hm.js?50bac15a1f238d1aa61f104a5fb6f5e0"; // github
|
||
var s = document.getElementsByTagName("script")[0];
|
||
if(isDev) return // 不上报
|
||
if (isGitee) s.parentNode.insertBefore(hm1, s);
|
||
else s.parentNode.insertBefore(hm2, s);
|
||
})();
|
||
</script>
|
||
</script>
|
||
<meta name="description" content="Unlimited Progress.">
|
||
|
||
<link rel="preload" href="/assets/css/0.styles.6874de37.css" as="style"><link rel="preload" href="/assets/js/app.292c8404.js" as="script"><link rel="preload" href="/assets/js/2.1a074358.js" as="script"><link rel="preload" href="/assets/js/15.12230d80.js" as="script"><link rel="prefetch" href="/assets/js/10.a20d5550.js"><link rel="prefetch" href="/assets/js/11.119bd5cb.js"><link rel="prefetch" href="/assets/js/12.bedd1642.js"><link rel="prefetch" href="/assets/js/13.a62e2a23.js"><link rel="prefetch" href="/assets/js/14.38ed7487.js"><link rel="prefetch" href="/assets/js/16.9fcf56ab.js"><link rel="prefetch" href="/assets/js/17.5dd592f6.js"><link rel="prefetch" href="/assets/js/18.712b8737.js"><link rel="prefetch" href="/assets/js/19.664bc08d.js"><link rel="prefetch" href="/assets/js/20.2f80ffd6.js"><link rel="prefetch" href="/assets/js/3.0b9cf30a.js"><link rel="prefetch" href="/assets/js/4.5f150161.js"><link rel="prefetch" href="/assets/js/5.23fbbca9.js"><link rel="prefetch" href="/assets/js/6.fc5837ce.js"><link rel="prefetch" href="/assets/js/7.74226b40.js"><link rel="prefetch" href="/assets/js/8.04651b4b.js"><link rel="prefetch" href="/assets/js/9.9b4eb9a0.js">
|
||
<link rel="stylesheet" href="/assets/css/0.styles.6874de37.css">
|
||
</head>
|
||
<body>
|
||
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="ZiuChen" class="logo"> <span class="site-name can-hide">ZiuChen</span></a> <div class="links"><!----> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">
|
||
首页
|
||
</a></div><div class="nav-item"><a href="/works/" class="nav-link">
|
||
开源作品
|
||
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人介绍" class="dropdown-title"><span class="title">个人介绍</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人介绍" class="mobile-dropdown-title"><span class="title">个人介绍</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/self/#技术栈" class="nav-link">
|
||
技术栈
|
||
</a></li><li class="dropdown-item"><!----> <a href="/self/#获得奖项" class="nav-link">
|
||
获得奖项
|
||
</a></li><li class="dropdown-item"><!----> <a href="/self/#相关链接" class="nav-link">
|
||
相关链接
|
||
</a></li></ul></div></div> <a href="https://github.com/ZiuChen/ZiuChen.github.io" target="_blank" rel="noopener noreferrer" class="repo-link">
|
||
GitHub
|
||
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">
|
||
首页
|
||
</a></div><div class="nav-item"><a href="/works/" class="nav-link">
|
||
开源作品
|
||
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="个人介绍" class="dropdown-title"><span class="title">个人介绍</span> <span class="arrow down"></span></button> <button type="button" aria-label="个人介绍" class="mobile-dropdown-title"><span class="title">个人介绍</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/self/#技术栈" class="nav-link">
|
||
技术栈
|
||
</a></li><li class="dropdown-item"><!----> <a href="/self/#获得奖项" class="nav-link">
|
||
获得奖项
|
||
</a></li><li class="dropdown-item"><!----> <a href="/self/#相关链接" class="nav-link">
|
||
相关链接
|
||
</a></li></ul></div></div> <a href="https://github.com/ZiuChen/ZiuChen.github.io" target="_blank" rel="noopener noreferrer" class="repo-link">
|
||
GitHub
|
||
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>JavaScript 高级教程</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/note/JavaScriptEnhanced.html#函数中this指向" class="sidebar-link">函数中this指向</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#如何改变this的指向" class="sidebar-link">如何改变this的指向</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#new-实例化一个函数" class="sidebar-link">new 实例化一个函数</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#使用-call-apply-bind" class="sidebar-link">使用 call apply bind</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#箭头函数" class="sidebar-link">箭头函数</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#严格模式" class="sidebar-link">严格模式</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#this面试题" class="sidebar-link">this面试题</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#原型与继承" class="sidebar-link">原型与继承</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#原型有什么作用" class="sidebar-link">原型有什么作用?</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#函数的显式原型" class="sidebar-link">函数的显式原型</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#object的原型" class="sidebar-link">Object的原型</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#原型链实现继承" class="sidebar-link">原型链实现继承</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#创建原型对象的方法" class="sidebar-link">创建原型对象的方法</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#对象方法补充" class="sidebar-link">对象方法补充</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#解读原型继承关系图" class="sidebar-link">解读原型继承关系图</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#构造函数的类方法" class="sidebar-link">构造函数的类方法</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#es6继承" class="sidebar-link">ES6继承</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#与function的异同" class="sidebar-link">与function的异同</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#定义访问器方法" class="sidebar-link">定义访问器方法</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#类的静态方法" class="sidebar-link">类的静态方法</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#extends实现继承" class="sidebar-link">extends实现继承</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#继承自默认类" class="sidebar-link">继承自默认类</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#类的混入mixin" class="sidebar-link">类的混入mixin</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#babel是如何转化es6的" class="sidebar-link">Babel是如何转化ES6的</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#浏览器运行原理" class="sidebar-link">浏览器运行原理</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#网页解析过程" class="sidebar-link">网页解析过程</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#浏览器对script元素的处理" class="sidebar-link">浏览器对script元素的处理</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#javascript-运行原理" class="sidebar-link">JavaScript 运行原理</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#js代码的执行" class="sidebar-link">JS代码的执行</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#javascript-v8引擎" class="sidebar-link">JavaScript V8引擎</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#javascript代码执行过程" class="sidebar-link">JavaScript代码执行过程</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#proxy与reflect" class="sidebar-link">Proxy与Reflect</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#监听对象方法" class="sidebar-link">监听对象方法</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#proxy" class="sidebar-link">Proxy</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#reflect" class="sidebar-link">Reflect</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#理解proxy与reflect中的receiver参数" class="sidebar-link">理解Proxy与Reflect中的receiver参数</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#promise详解" class="sidebar-link">Promise详解</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#异步代码" class="sidebar-link">异步代码</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#认识promise" class="sidebar-link">认识Promise</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#promise类方法" class="sidebar-link">Promise类方法</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#迭代器与生成器" class="sidebar-link">迭代器与生成器</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#异步处理" class="sidebar-link">异步处理</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#await-async-事件循环" class="sidebar-link">await async 事件循环</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#异步函数-async" class="sidebar-link">异步函数 async</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#await关键字" class="sidebar-link">await关键字</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#进程与线程" class="sidebar-link">进程与线程</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#javascript线程" class="sidebar-link">JavaScript线程</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#微任务与宏任务" class="sidebar-link">微任务与宏任务</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#事件循环-面试题" class="sidebar-link">事件循环 面试题</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#node事件循环" class="sidebar-link">Node事件循环</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#防抖与节流" class="sidebar-link">防抖与节流</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#防抖函数" class="sidebar-link">防抖函数</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#节流函数" class="sidebar-link">节流函数</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#深拷贝与浅拷贝" class="sidebar-link">深拷贝与浅拷贝</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#浅拷贝" class="sidebar-link">浅拷贝</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#深拷贝" class="sidebar-link">深拷贝</a></li><li class="sidebar-sub-header"><a href="/note/JavaScriptEnhanced.html#完整代码" class="sidebar-link">完整代码</a></li></ul></li><li><a href="/note/JavaScriptEnhanced.html#事件总线" class="sidebar-link">事件总线</a><ul class="sidebar-sub-headers"></ul></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="javascript-高级教程"><a href="#javascript-高级教程" class="header-anchor">#</a> JavaScript 高级教程</h1> <h2 id="函数中this指向"><a href="#函数中this指向" class="header-anchor">#</a> 函数中this指向</h2> <p>函数在调用时, Javascript会默认为this绑定一个值</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 定义一个函数</span>
|
||
<span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 1. 直接调用</span>
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Window</span>
|
||
|
||
<span class="token comment">// 2. 绑定对象调用</span>
|
||
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span> <span class="token literal-property property">aaa</span><span class="token operator">:</span> foo <span class="token punctuation">}</span>
|
||
obj<span class="token punctuation">.</span><span class="token function">aaa</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
|
||
<span class="token comment">// 3. 通过call/apply调用</span>
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span> <span class="token comment">// String {'Ziu'}</span>
|
||
</code></pre></div><p>this的绑定:</p> <ul><li>和定义的位置没有关系</li> <li>和调用方式/调用位置有关系</li> <li>是在运行时被绑定的</li></ul> <p><strong>this始终指向最后调用它的对象</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Window</span>
|
||
|
||
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">bar</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
obj<span class="token punctuation">.</span><span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
|
||
<span class="token keyword">const</span> baz <span class="token operator">=</span> obj<span class="token punctuation">.</span>bar
|
||
<span class="token function">baz</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Window</span>
|
||
</code></pre></div><h3 id="如何改变this的指向"><a href="#如何改变this的指向" class="header-anchor">#</a> 如何改变this的指向</h3> <h3 id="new-实例化一个函数"><a href="#new-实例化一个函数" class="header-anchor">#</a> new 实例化一个函数</h3> <blockquote><p>new一个对象时发生了什么:</p> <ol><li>创建一个空对象</li> <li>这个空对象会被执行prototype连接</li> <li>将this指向这个空对象</li> <li>执行函数体中的代码</li> <li>没有显式返回这个对象时 会默认返回这个对象</li></ol></blockquote> <p>函数可以作为一个构造函数, 作为一个类, 可以通过new关键字将其实例化</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 直接调用的话 this为Window</span>
|
||
|
||
<span class="token keyword">new</span> <span class="token class-name">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 通过new关键字调用 则this指向空对象</span>
|
||
</code></pre></div><h3 id="使用-call-apply-bind"><a href="#使用-call-apply-bind" class="header-anchor">#</a> 使用 call apply bind</h3> <p>在 JavaScript 中, 函数是对象。</p> <p>JavaScript 函数有它的属性和方法。call() 和 apply() 是预定义的函数方法。</p> <p>两个方法可用于调用函数,两个方法的第一个参数必须是对象本身</p> <hr> <p>要将<code>foo</code>函数中的<code>this</code>指向<code>obj</code>,可以通过赋值的方式:</p> <div class="language-js extra-class"><pre class="language-js"><code>obj<span class="token punctuation">.</span>foo <span class="token operator">=</span> foo <span class="token comment">// 绑定</span>
|
||
obj<span class="token punctuation">.</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 调用</span>
|
||
</code></pre></div><p>但是也可以通过对函数调用call / apply实现</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// 将foo执行时的this显式绑定到了obj上 并调用foo</span>
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span> <span class="token comment">// foo的this被绑定到了 Number { 123 } 上</span>
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">"ziu"</span><span class="token punctuation">)</span> <span class="token comment">// 绑定到了 String { "ziu" } 上</span>
|
||
</code></pre></div><h4 id="包装类对象"><a href="#包装类对象" class="header-anchor">#</a> 包装类对象</h4> <p>当我们直接使用类似:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token string">"ZiuChen"</span><span class="token punctuation">.</span>length <span class="token comment">// String.length</span>
|
||
</code></pre></div><p>的语句时,<code>JS</code>会为字符串 <code>ZiuChen</code> 包装一个对象,随后在这个对象上调用 <code>.length</code> 属性</p> <h4 id="call和apply的区别"><a href="#call和apply的区别" class="header-anchor">#</a> call和apply的区别</h4> <ul><li>相同点:第一个参数都是相同的,要求传入一个对象
|
||
<ul><li>在函数调用时,会将this绑定到这个传入的对象上</li></ul></li> <li>不同点:后面的参数
|
||
<ul><li>apply 传入的是一个数组</li> <li>call 传入的是参数列表</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token string">'targetThis'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'targetThis'</span><span class="token punctuation">,</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>当我们需要给一个带参数的函数通过call/apply的方式绑定this时,就需要使用到call/apply的第二个入参了。</p> <h4 id="参数列表"><a href="#参数列表" class="header-anchor">#</a> 参数列表</h4> <p>当传入函数的参数有多个时,可以通过<code>...args</code>将参数合并到一个数组中去</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">"Ziu"</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span> <span class="token comment">// ["Ziu", 18, 1.88]</span>
|
||
</code></pre></div><h4 id="bind绑定"><a href="#bind绑定" class="header-anchor">#</a> bind绑定</h4> <p>如果我们希望:在每次调用<code>foo</code>时,都能将<code>obj</code>绑定到<code>foo</code>的<code>this</code>上,那么就需要用到<code>bind</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 将obj绑定到foo上</span>
|
||
<span class="token keyword">const</span> fun <span class="token operator">=</span> <span class="token function">foo</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
|
||
<span class="token comment">// 在后续每次调用foo时, foo内的this都将指向obj</span>
|
||
<span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
<span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
</code></pre></div><p><code>bind()</code>方法将创建一个新的函数,当被调用时,将其<code>this</code>关键字</p> <h3 id="箭头函数"><a href="#箭头函数" class="header-anchor">#</a> 箭头函数</h3> <p>箭头函数是<code>ES6</code>新增的编写函数的方式,更简洁。</p> <ul><li><p>箭头函数不会绑定<code>this</code>、<code>arguments</code>属性</p> <ul><li><code>arguments</code></li></ul></li> <li><p>箭头函数不能作为构造函数来使用(不能与<code>new</code>同用,会报错)</p></li></ul> <h4 id="箭头函数中的this"><a href="#箭头函数中的this" class="header-anchor">#</a> 箭头函数中的this</h4> <p>在箭头函数中是没有<code>this</code>的:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">foo</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// window</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token comment">// window</span>
|
||
</code></pre></div><p>之所以找到了<code>Window</code>对象,是因为在调用<code>foo()</code>时,函数内部作用域并没有找到<code>this</code>,转而向上层作用域找<code>this</code></p> <p>因此找到了顶层的全局<code>this</code>,也即<code>Window</code>对象</p> <h4 id="箭头函数中this的查找规则"><a href="#箭头函数中this的查找规则" class="header-anchor">#</a> 箭头函数中this的查找规则</h4> <p>检查以下代码:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"obj"</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">bar</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> bar
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> fn <span class="token operator">=</span> obj<span class="token punctuation">.</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
</code></pre></div><p>代码执行完毕,控制台输出<code>this</code>值为<code>obj</code>对象,这是为什么?</p> <p>箭头函数中没有<code>this</code>,故会向上层作用域寻找<code>this</code>,<code>bar</code>的上层作用域为函数<code>foo</code>,而函数<code>foo</code>的<code>this</code>由其调用决定</p> <p>调用<code>foo</code>函数的为<code>obj</code>对象,故内部箭头函数中的<code>this</code>指向的是<code>obj</code></p> <p>检查以下代码:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"obj"</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">bar</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> bar
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> fn <span class="token operator">=</span> obj<span class="token punctuation">.</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Window</span>
|
||
</code></pre></div><p>和上面的代码不同之处在于:<code>foo</code>也是由箭头函数定义的,<code>bar</code>向上找不到<code>foo</code>的<code>this</code>,故而继续向上,找到了全局<code>this</code>,也即<code>Window</code>对象</p> <h3 id="严格模式"><a href="#严格模式" class="header-anchor">#</a> 严格模式</h3> <ul><li>在严格模式下,全局的<code>this</code>不是<code>Window</code>对象,而是<code>undefined</code>。</li> <li>在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。</li> <li>在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。</li></ul> <h3 id="this面试题"><a href="#this面试题" class="header-anchor">#</a> this面试题</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string">'window'</span>
|
||
|
||
<span class="token keyword">var</span> person <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'person'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">sayName</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> sss <span class="token operator">=</span> person<span class="token punctuation">.</span>sayName
|
||
|
||
<span class="token function">sss</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 默认绑定: window</span>
|
||
person<span class="token punctuation">.</span><span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 隐式绑定: person</span>
|
||
<span class="token punctuation">(</span>person<span class="token punctuation">.</span>sayName<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 隐式绑定: person, 本质与上一行代码相同</span>
|
||
<span class="token punctuation">;</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>sayName <span class="token operator">=</span> person<span class="token punctuation">.</span>sayName<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 间接调用: window</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">sayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string">'window'</span>
|
||
|
||
<span class="token keyword">var</span> person1 <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'person1'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo1</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo2</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo3</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">foo4</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">var</span> person2 <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'person2'</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
person1<span class="token punctuation">.</span><span class="token function">foo1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 隐式绑定: person1</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo1</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span> <span class="token comment">// 显式绑定: person2</span>
|
||
|
||
person1<span class="token punctuation">.</span><span class="token function">foo2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 上层作用域: window</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo2</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span> <span class="token comment">// 上层作用域: window</span>
|
||
|
||
person1<span class="token punctuation">.</span><span class="token function">foo3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 默认绑定: window</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo3</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 默认绑定: window</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span> <span class="token comment">// 显式绑定: person2</span>
|
||
|
||
person1<span class="token punctuation">.</span><span class="token function">foo4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 隐式绑定: person1</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo4</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 显式绑定: person2</span>
|
||
person1<span class="token punctuation">.</span><span class="token function">foo4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>person2<span class="token punctuation">)</span> <span class="token comment">// 隐式绑定: person1</span>
|
||
</code></pre></div><h2 id="原型与继承"><a href="#原型与继承" class="header-anchor">#</a> 原型与继承</h2> <p>JavaScript中,任何一个对象都有一个特殊的内置属性<code>[[prototype]]</code>,称之为原型</p> <ul><li>可以通过<code>.__proto__</code>或<code>Object.getPrototypeOf(obj)</code>获取到这个原型对象</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>__proto__<span class="token punctuation">)</span> <span class="token comment">// 由浏览器添加 非标准</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 标准的获取原型的方法</span>
|
||
</code></pre></div><h3 id="原型有什么作用"><a href="#原型有什么作用" class="header-anchor">#</a> 原型有什么作用?</h3> <p>当我们通过<code>[[getter]]</code>执行 <code>obj.name</code> 时:</p> <ul><li>首先在自身上找<code>name</code>属性,如果找到了则直接返回</li> <li>如果没找到,则沿着原型链向上查找,检查其原型是否存在该属性</li></ul> <p>手动为<code>obj</code>的原型添加<code>message</code>属性后,在<code>obj</code>上获取<code>name</code>属性,会沿着原型链找到原型上的<code>message</code>属性</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proto <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
|
||
proto<span class="token punctuation">.</span>message <span class="token operator">=</span> <span class="token string">'Hello, Prototype.'</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>message<span class="token punctuation">)</span> <span class="token comment">// Hello, Prototype.</span>
|
||
</code></pre></div><h3 id="函数的显式原型"><a href="#函数的显式原型" class="header-anchor">#</a> 函数的显式原型</h3> <p>之前我们说<strong>对象的原型都是隐式的</strong>,不能直接通过属性直接获取(<code>.__proto__</code>的方式是非标准)</p> <p>而<strong>函数是存在一个名为<code>prototype</code>的显式原型的</strong>,可以通过这个属性获取到函数的原型,向原型添加额外的属性</p> <p>每次在通过<code>new</code>操作符创建对象时,将对象的隐式原型指向这个显式原型</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 向构造函数的显式原型添加公共方法</span>
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">running</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> s1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> s2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'kobe'</span><span class="token punctuation">,</span> <span class="token number">19</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> s3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'brant'</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 任何一个由该构造函数创建的对象实例的原型都指向函数的显式原型</span>
|
||
<span class="token comment">// 可以调用原型上的公共方法</span>
|
||
s1<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// ziu is running</span>
|
||
s2<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// kobe is running</span>
|
||
|
||
<span class="token comment">// 对象实例的原型上包含构造函数与我们手动添加上去的公共方法</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>s1<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// {running: ƒ, constructor: ƒ}</span>
|
||
</code></pre></div><p>添加在对象原型上的方法,在被多个实例调用时只会开辟一块内存空间</p> <p>如果将公共方法放到构造函数中,那么每创建一个实例,都会为这个方法开辟一块新的内存空间</p> <p>构造函数的显式原型中的属性<code>constructor</code>,这个属性即指向构造函数,因此存在关系<code>Student --proto-> {constructor: Student}</code></p> <h3 id="object的原型"><a href="#object的原型" class="header-anchor">#</a> Object的原型</h3> <p>当我们定义了一个对象,它的原型即为<code>Object</code>,而<code>Object</code>的原型则为<code>Null</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> p1 <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// Object</span>
|
||
<span class="token keyword">const</span> p2 <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>p1<span class="token punctuation">)</span> <span class="token comment">// null</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p1<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p2<span class="token punctuation">)</span>
|
||
</code></pre></div><p>以上一节的例子举例:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// s1是构造函数Student的实例</span>
|
||
<span class="token keyword">const</span> p1 <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>s1<span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> p2 <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>p1<span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> p3 <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>p2<span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Student</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span> <span class="token comment">// {running: ƒ, constructor: ƒ}</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p1<span class="token punctuation">)</span> <span class="token comment">// {running: ƒ, constructor: ƒ}</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p2<span class="token punctuation">)</span> <span class="token comment">// Object</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p3<span class="token punctuation">)</span> <span class="token comment">// null</span>
|
||
</code></pre></div><h3 id="原型链实现继承"><a href="#原型链实现继承" class="header-anchor">#</a> 原型链实现继承</h3> <p>创建两个构造函数<code>Person</code>与<code>Student</code>,各自有自身的方法,我们希望实现<code>Student</code>继承<code>Person</code>的方法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">running</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> id<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">studying</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is studying.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> s1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">)</span>
|
||
s1<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// ERROR: s1.running is not a function</span>
|
||
</code></pre></div><p>显然现在<code>Student</code>和<code>Person</code>是没有任何关联的,要让二者联系起来有以下几种方法:</p> <h4 id="方法一-错误"><a href="#方法一-错误" class="header-anchor">#</a> 方法一(错误)</h4> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> <span class="token class-name">Person</span><span class="token punctuation">.</span>prototype
|
||
</code></pre></div><p>可以让<code>Student</code>构造函数的显式原型指向<code>Person</code>的显式原型,这时可以顺利在<code>s1</code>实例上调用<code>.running()</code>方法,但是存在问题:</p> <ul><li>在子类<code>Student</code>添加的<code>studying</code>方法会被添加到父类<code>Person</code>的显式原型上,这并不合理
|
||
<ul><li>父类和子类共享一个原型对象,子类的方法都被添加到了父类的原型对象上</li> <li>此后如果有从<code>Person</code>继承的子类,那这个子类也将可以调用<code>studying</code>方法,这是因为所有子类的方法都被放到了父类<code>Person</code>的显式原型上</li></ul></li></ul> <h4 id="方法二-有效但不合理"><a href="#方法二-有效但不合理" class="header-anchor">#</a> 方法二(有效但不合理)</h4> <p>创建一个父类的实例对象(<code>new Person()</code>)用这个实例对象作为子类的原型对象</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> p
|
||
</code></pre></div><p>创建一个<code>p</code>对象,其隐式原型<code>__proto__</code>指向<code>Person</code>的显式原型对象上</p> <p>通过这个方法,<code>Student</code>添加的<code>studying</code>方法将被放到<code>p</code>对象上,此后由<code>Student</code>派生的类,其隐式原型也将被指定到<code>p</code>对象上,而不会污染原始的原型</p> <p>但是当我们会发现,两个构造函数的内容是有重复的:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> id<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>针对<code>name</code>与<code>age</code>的定义完全可以被复用</p> <h4 id="方法三-最终"><a href="#方法三-最终" class="header-anchor">#</a> 方法三(最终)</h4> <p>借用构造函数方法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> id<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">Person</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">)</span> <span class="token comment">// 通过Person.call 绑定this到当前的s实例上</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> <span class="token class-name">Person</span><span class="token punctuation">.</span>prototype
|
||
|
||
<span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">)</span>
|
||
s<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
</code></pre></div><ul><li>借用继承的方法很简单:在子类构造函数内部调用父类型构造函数
|
||
<ul><li>因为函数可以在任意时刻被调用</li> <li>通过<code>apply()</code> <code>call()</code>方法也可以在创建新的对象上执行构造函数</li></ul></li></ul> <h3 id="创建原型对象的方法"><a href="#创建原型对象的方法" class="header-anchor">#</a> 创建原型对象的方法</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
</code></pre></div><p>要实现Student对Person的继承:</p> <p>之前我们通过<code>new</code>关键字,为<code>Student</code>创建一个新的原型对象,也介绍了这种方法存在的弊端</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> p<span class="token punctuation">.</span>prototype
|
||
</code></pre></div><p>可以使用另一种更优秀的方案:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token comment">// obj.__proto__ = Person.prototype // 非规范用法 兼容性不保证</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">setPrototypeOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span> <span class="token comment">// 挂载原型对象</span>
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> obj
|
||
</code></pre></div><p>社区中也有一种方案:</p> <p>不需要再<code>new Person()</code>,而是用另外一个构造函数,此后需要挂载原型时都通过<code>new F()</code>来实现</p> <ul><li>更具备通用性,此处做<code>Person</code>的继承,后续也可以做<code>Animal</code>的继承</li> <li>如果浏览器不支持<code>Object.setPrototypeOf()</code>则此方法更优</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token constant">F</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token class-name">F</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> <span class="token class-name">Person</span><span class="token punctuation">.</span>prototype
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">F</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>最终方案:</p> <p>从之前的代码可知,要达到的目的有两个:<code>1. 创建一个新对象 让原型对象不要被污染 2. 将新对象的原型挂载到目标原型上</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> obj <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
|
||
<span class="token class-name">Student</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> obj
|
||
</code></pre></div><p><code>Object.create()</code>传入的参数是原型对象,可以在创建新对象的同时将此对象的原型指向目标原型对象上</p> <h4 id="开发封装"><a href="#开发封装" class="header-anchor">#</a> 开发封装</h4> <p>根据上述最终方案的原理,在开发中可以对继承方案做如下封装:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">inherit</span><span class="token punctuation">(</span><span class="token parameter">subType<span class="token punctuation">,</span> superType</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 创建一个新对象并将新对象的原型指向父类构造函数的原型</span>
|
||
subType<span class="token punctuation">.</span>prototype <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>superType<span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 为子类的原型添加constructor属性</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>subType<span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token string">'constructor'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">enumerable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment">// 不可被枚举</span>
|
||
<span class="token literal-property property">configurable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 值可被修改</span>
|
||
<span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 值可被覆写</span>
|
||
<span class="token literal-property property">value</span><span class="token operator">:</span> subType <span class="token comment">// 初始值: 父类构造函数</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">inherit</span><span class="token punctuation">(</span>Student<span class="token punctuation">,</span> Person<span class="token punctuation">)</span>
|
||
</code></pre></div><p>另外,如果担心<code>Object.create()</code>的兼容性,也可以将创建对象的代码替换为:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">createObject</span><span class="token punctuation">(</span><span class="token parameter">o</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">function</span> <span class="token constant">F</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token class-name">F</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> o
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">F</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token operator">...</span>
|
||
subType<span class="token punctuation">.</span>prototype <span class="token operator">=</span> <span class="token function">createObject</span><span class="token punctuation">(</span>superType<span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
|
||
<span class="token operator">...</span>
|
||
</code></pre></div><p>也可以实现:创建对象并修改新对象的原型指向</p> <h3 id="对象方法补充"><a href="#对象方法补充" class="header-anchor">#</a> 对象方法补充</h3> <ul><li>hasOwnProperty
|
||
<ul><li>对象上是否有某一个属于自己的属性(不是在原型上的属性)</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> info <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token function">createObject</span><span class="token punctuation">(</span>info<span class="token punctuation">)</span> <span class="token comment">// 创建一个新对象并将新对象的原型指向info</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token comment">// Ziu: 对象自身上并没有该属性 会沿着原型链找到info对象</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false: 因为对象身上并没有该属性</span>
|
||
</code></pre></div><ul><li>in 或 for-in
|
||
<ul><li>判断某个属性是否存在于某个对象或对象的原型上</li></ul></li></ul> <p>以上文中例子举例,用<code>in</code>操作符可以沿着原型链获取属性:</p> <p><code>for-in</code>遍历的不只是自己身上的属性,也包括原型上的属性,因为对象都是继承自<code>Object</code>,而<code>Object</code>中的属性其属性描述符<code>enumerable</code>默认为false,故自己创建的对象在遍历时不会遍历到<code>Object</code>对象上的属性</p> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'name'</span> <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token comment">// true: 对象上没有 则沿着原型链找到原型上的属性</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token comment">// name age</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><ul><li>instanceof
|
||
<ul><li>用于判断构造函数(Person Student类)的prototype,是否出现在某个实例对象的原型链上</li> <li><strong>用于判断对象与构造函数之间的关系</strong></li> <li>该运算符右侧必须为一个对象:<code>s instanceof null</code>将报错</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
|
||
<span class="token function">inherit</span><span class="token punctuation">(</span>Student<span class="token punctuation">,</span> Person<span class="token punctuation">)</span> <span class="token comment">// 将Student的隐式原型指向Person的隐式原型(继承)</span>
|
||
|
||
<span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s <span class="token keyword">instanceof</span> <span class="token class-name">Student</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s <span class="token keyword">instanceof</span> <span class="token class-name">Person</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s <span class="token keyword">instanceof</span> <span class="token class-name">Object</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s <span class="token keyword">instanceof</span> <span class="token class-name">Array</span><span class="token punctuation">)</span> <span class="token comment">// false</span>
|
||
</code></pre></div><p><code>instanceof</code>会沿着原型链查找:s -> Student -> Person -> Object</p> <ul><li>isPrototypeOf
|
||
<ul><li><strong>用于检测某个对象是否出现在某个实例对象的原型链上</strong></li> <li>可以用于判断对象之间的继承关系</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Student</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">isPrototypeOf</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
</code></pre></div><h3 id="解读原型继承关系图"><a href="#解读原型继承关系图" class="header-anchor">#</a> 解读原型继承关系图</h3> <ul><li>f1是Foo的实例对象</li> <li>obj是Object的实例对象</li> <li>Function/Object/Foo都是Function的实例对象</li> <li>原型对象默认创建时,其隐式原型都是指向Object的显示原型(Object指向null)</li></ul> <p><img src="https://clarkdo.js.org/public/img/jsobj_full.jpg" alt="JavaScript Object Layout"></p> <p>在解读之前首先明确以下几点:</p> <ul><li>对象都有隐式原型,可以通过<code>Object.getPrototypeof()</code>或<code>__proto__</code>(非标准)获取到</li> <li>函数也是对象,有隐式原型,也有显式原型,显式原型可以通过<code>.prototype</code>获取到</li> <li><code>Object.getPrototypeOf()</code>本应传入的是一个对象,当我们为其传入一个构造函数时,是将此构造函数视为对象,此时通过<code>Object.getPrototypeOf(Foo)</code>获取到的是<strong>函数对象</strong>的原型,即<code>Function.prototype</code></li></ul> <p>由上至下解读,首先解读<code>function Foo()</code>这一层:</p> <p>通过构造函数<code>new Foo()</code>创建了两个实例对象<code>f1 f2</code>,<code>f1 f2</code>是由<code>function Foo</code>创建出来的,故其隐式原型指向<code>Foo.prototype</code></p> <p>Foo既是一个函数,也是一个对象(由<code>new Function()</code>创建出来的)。</p> <ul><li>作为函数,它拥有显式原型<code>prototype</code>,指向<code>Foo.prototype</code>这个原型对象</li> <li>作为对象,它拥有隐式原型<code>__proto__</code>,指向<code>Function.prototype</code>这个原型对象</li></ul> <p>而<code>Foo.prototype</code>作为一个原型对象,拥有他的构造函数<code>constructor</code>指向<code>Foo</code>,也拥有它的隐式原型<code>__proto__</code>指向<code>Object.prototype</code>(本质上<code>Foo.prototype</code>也是由<code>new Object()</code>创建出来的)</p> <p>随后,开始解读<code>function Object()</code>这第二层:</p> <p>通过构造函数<code>new Object()</code>创建出来两个实例对象<code>o1 o2</code>,它们是由<code>function Object</code>创建出来的,故其隐式原型指向<code>Object.prototype</code></p> <p>同样的,<code>function Object</code>作为构造函数对象,它既拥有作为函数的显式原型对象,也拥有作为对象的隐式原型对象</p> <ul><li>作为函数,它拥有显式原型,指向<code>Object.prototype</code></li> <li>作为对象,它是由<code>new Function()</code>创建的,其隐式原型指向<code>Function.prototype</code></li></ul> <p>需要注意的是,原型对象<code>Object.prototype</code>的隐式原型指向<code>null</code>,它的构造函数<code>constructor</code>指向<code>function Object</code></p> <p>继续解读<code>function Function()</code>第三层:</p> <p><code>JavaScript</code>中的函数对象都是通过<code>function Function()</code>这个构造函数创建出来的,所以所有函数的隐式原型<code>__proto__</code>都指向<code>Function.prototype</code></p> <ul><li><code>function Function()</code>作为函数,其显式原型指向<code>Function.prototype</code></li> <li>而当其作为对象,是由<code>new Function()</code>创建出来的,故其隐式原型也指向<code>Function.prototype</code></li></ul> <h3 id="构造函数的类方法"><a href="#构造函数的类方法" class="header-anchor">#</a> 构造函数的类方法</h3> <p>需要区分一下类方法与实例方法:</p> <ul><li>实例方法:在实例上调用,会沿着原型链向上查找</li> <li>类方法:在类上(构造函数上)直接调用</li></ul> <p>在下面的例子中,我们向<code>Person.prototype</code>上添加了方法<code>running</code>,当我们在实例对象<code>p</code>上调用<code>running</code>时,会沿着<code>p</code> <code>p.__proto__</code>(<code>Person.prototype</code>)查找,在<code>Person.prototype</code>上找到<code>running</code>方法后进行调用</p> <p>然而我们在<code>Person</code>类上直接调用<code>running()</code>则不行,这是因为<code>Person</code>只是<code>Person.prototype</code>的<code>constructor</code>属性,是它的构造函数,与原型链没有关系,<code>Person</code>上并没有<code>running()</code>方法,<code>Person.prototype</code>上才有</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">running</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
p<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Ziu is running</span>
|
||
Person<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// undefined</span>
|
||
</code></pre></div><p>要实现类方法,只需要直接在构造函数上添加新属性即可,因为构造函数本身也是一个对象:构造函数对象</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> names <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'abc'</span><span class="token punctuation">,</span> <span class="token string">'cba'</span><span class="token punctuation">,</span> <span class="token string">'nba'</span><span class="token punctuation">,</span> <span class="token string">'mba'</span><span class="token punctuation">]</span>
|
||
Person<span class="token punctuation">.</span><span class="token function-variable function">randomPerson</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> randName <span class="token operator">=</span> names<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> names<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span>randName<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> p2 <span class="token operator">=</span> Person<span class="token punctuation">.</span><span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p2<span class="token punctuation">)</span>
|
||
</code></pre></div><p>上例中,我们手动向<code>Person</code>构造函数对象中添加了类方法<code>randomPerson</code>,可以直接在<code>Person</code>上进行调用</p> <h2 id="es6继承"><a href="#es6继承" class="header-anchor">#</a> ES6继承</h2> <ul><li>class方式定义类</li> <li>extends实现继承</li> <li>Babel的ES6转ES5</li> <li>面向对象多态理解</li> <li>ES6对象的增强</li></ul> <p>ES6提供了<code>class</code>定义类的语法糖,其本质的特性是与ES6之前实现继承的方式是一样的</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 实例方法</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 静态方法(类方法)</span>
|
||
<span class="token keyword">static</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'static func: random person'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span> <span class="token comment">// 根据类创建实例</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Person</span><span class="token punctuation">.</span>prototype <span class="token operator">===</span> p<span class="token punctuation">.</span>__proto__<span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>constructor<span class="token punctuation">)</span> <span class="token comment">// class Person ...</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> Person<span class="token punctuation">)</span> <span class="token comment">// function</span>
|
||
</code></pre></div><p>当我们通过<code>new</code>关键字操作类时,会调用这个<code>constructor</code>函数,并执行以下操作:</p> <ol><li>在内存中创建一个新的对象(空对象)</li> <li>这个对象内部的<code>[[prototype]]</code>属性(隐式原型<code>__proto__</code>)会被赋值为该类的<code>prototype</code>属性</li> <li>构造函数内部的this,会指向创建出来的新对象</li> <li>执行构造函数内的代码</li> <li>如果构造函数没有返回非空对象,则返回创建出来的新对象</li></ol> <h3 id="与function的异同"><a href="#与function的异同" class="header-anchor">#</a> 与function的异同</h3> <p>区别在于:定义构造函数与定义实例方法的部分聚合到了一起(高内聚、低耦合)相同的功能如果要用<code>function</code>来实现:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">running</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Person</span><span class="token punctuation">.</span>prototype <span class="token operator">===</span> p<span class="token punctuation">.</span>__proto__<span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>constructor<span class="token punctuation">)</span> <span class="token comment">// function Person ...</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> Person<span class="token punctuation">)</span> <span class="token comment">// function</span>
|
||
</code></pre></div><p>运行代码可知,几个<code>console.log</code>输出都是相同的,这证明二者的本质是相同的,<code>Class</code>语法只是一种语法糖</p> <p>二者之间是存在区别的:</p> <ul><li>构造函数<code>function Person</code>可以通过<code>()</code>作为普通函数调用</li> <li><code>class Person</code>则不可以直接调用:<code>Class constructor Person cannot be invoked without 'new'</code></li></ul> <h3 id="定义访问器方法"><a href="#定义访问器方法" class="header-anchor">#</a> 定义访问器方法</h3> <p>为对象属性定义访问器(<code>Object.defineProperty()</code>):</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">let</span> value
|
||
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'name getted'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> value
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">val</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'name setted '</span> <span class="token operator">+</span> val<span class="token punctuation">)</span>
|
||
value <span class="token operator">=</span> val
|
||
<span class="token keyword">return</span> value
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
obj<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span> <span class="token comment">// name setted Ziu</span>
|
||
<span class="token keyword">const</span> tmp <span class="token operator">=</span> obj<span class="token punctuation">.</span>name <span class="token comment">// name getted</span>
|
||
</code></pre></div><p>直接在对象中定义访问器:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">_name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token keyword">get</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_name
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token keyword">set</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token parameter">val</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>_name <span class="token operator">=</span> val
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>在ES6的<code>class</code>关键字中定义访问器:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>_name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">get</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">set</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token parameter">val</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>_name <span class="token operator">=</span> val
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="访问器的应用场景"><a href="#访问器的应用场景" class="header-anchor">#</a> 访问器的应用场景</h4> <p>当我们需要频繁的对某些属性组合进行调用时,可以将这些属性组合,在外部可以通过访问器获得计算好的值</p> <p>例如下述代码中实现了一个简单的<code>Rectangle</code>类,可以通过访问器直接获取其<code>position</code>与<code>size</code>属性</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> width<span class="token punctuation">,</span> height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> x
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> width
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">get</span> <span class="token function">position</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token literal-property property">y</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">get</span> <span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> rect <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Rectangle</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>rect<span class="token punctuation">.</span>position<span class="token punctuation">,</span> rect<span class="token punctuation">.</span>size<span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="类的静态方法"><a href="#类的静态方法" class="header-anchor">#</a> 类的静态方法</h3> <p><strong>在ES6之前我们将这种方法称为<code>类方法</code>,在其之后我们将其称为静态方法</strong></p> <p>静态方法通常用于定义直接使用类来执行的方法,不需要有类的实例,使用<code>static</code>关键字来定义:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 实例方法</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 静态方法(类方法)</span>
|
||
<span class="token keyword">static</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'static func: random person'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>本质上:</p> <div class="language-js extra-class"><pre class="language-js"><code>Person<span class="token punctuation">.</span><span class="token function-variable function">randomPerson</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'static func: random person'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h3 id="extends实现继承"><a href="#extends实现继承" class="header-anchor">#</a> extends实现继承</h3> <p>在<code>Person</code>类的基础上实现<code>Student</code>类继承自<code>Person</code></p> <p>在子类的构造函数内需要通过<code>super()</code>并传入父类(超类)构造函数需要的参数,这样就可以调用父类的构造函数</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">sitting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is sitting.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">class</span> <span class="token class-name">Student</span> <span class="token keyword">extends</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">super</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token comment">// 在子类的constructor中通过super()调用父类的构造函数</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">studying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">sitting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 在子类中通过super.method()调用父类的方法</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is studying.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">)</span>
|
||
s<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 可以调用父类方法</span>
|
||
s<span class="token punctuation">.</span><span class="token function">studying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 也可以调用自己的方法</span>
|
||
</code></pre></div><ul><li>在子类中,执行<code>super.method(...)</code>可以调用一个父类方法</li> <li>在子类的<code>constructor</code>中,执行<code>super(...)</code>来调用父类<code>constructor</code></li></ul> <p><strong>在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token operator">...</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token keyword">super</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token comment">// 这是不对的,应该在使用this之前先调用super</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token operator">...</span>
|
||
</code></pre></div><h3 id="继承自默认类"><a href="#继承自默认类" class="header-anchor">#</a> 继承自默认类</h3> <p>可以通过继承,为内置类做修改或扩展,方便我们使用:</p> <p>在下例中,我们对内置类<code>Array</code>做了扩展,添加了访问器属性<code>lastItem</code>可以获取数组内最后一个元素</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">SelfArray</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">get</span> <span class="token function">lastItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SelfArray</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span>lastItem<span class="token punctuation">)</span>
|
||
</code></pre></div><p>传统方式也可以实现,通过操作原型:</p> <p>为<code>Array.prototype</code>定义属性<code>lastItem</code>,并为其添加<code>getter</code>函数,可以通过<code>lastItem</code>获取最后一个元素</p> <p>需要注意的是,这种方法会对所有<code>Array</code>对象产生影响,所有的数组都可以调用这个方法</p> <div class="language-js extra-class"><pre class="language-js"><code>Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span><span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token string">'lastItem'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span>lastItem<span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="类的混入mixin"><a href="#类的混入mixin" class="header-anchor">#</a> 类的混入mixin</h3> <p>JavaScript只支持单继承,不支持多继承。要让一个类继承自多个父类,调用来自不同父类的方法,可以使用<code>mixin</code></p> <p>下例中我们希望<code>Bird</code>能够同时继承自<code>Animal</code>和<code>Flyer</code>类,直接使用<code>extends</code>会报错</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">mixinAnimal</span><span class="token punctuation">(</span><span class="token parameter">BaseClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 1. 创建一个新的类 继承自baseClass</span>
|
||
<span class="token comment">// 2. 对这个新的类进行扩展 添加running方法</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">class</span> <span class="token class-name">extends</span> BaseClass <span class="token punctuation">{</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'running'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">mixinFlyer</span><span class="token punctuation">(</span><span class="token parameter">BaseClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">class</span> <span class="token class-name">extends</span> BaseClass <span class="token punctuation">{</span>
|
||
<span class="token function">flying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'flying'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">class</span> <span class="token class-name">Bird</span> <span class="token punctuation">{</span>
|
||
<span class="token function">eating</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'eating'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">class</span> <span class="token class-name">newBird</span> <span class="token keyword">extends</span> <span class="token class-name">mixinAnimal</span><span class="token punctuation">(</span><span class="token function">mixinFlyer</span><span class="token punctuation">(</span>Bird<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> b <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">newBird</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
b<span class="token punctuation">.</span><span class="token function">eating</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// eating</span>
|
||
b<span class="token punctuation">.</span><span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// running</span>
|
||
b<span class="token punctuation">.</span><span class="token function">flying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// flying</span>
|
||
</code></pre></div><p>通过调用<code>mixin</code>方法,创建一个新的类 继承自baseClass,对这个新的类进行扩展 添加我们希望新类能够继承的方法</p> <p>除了这种方式,也可以通过复制对象的方法实现继承<code>Object.assign(Bird.prototype, {})</code></p> <h4 id="react中的高阶组件"><a href="#react中的高阶组件" class="header-anchor">#</a> React中的高阶组件</h4> <p>在React的高阶组件实现中有<code>connect</code>方法,即是使用到了类似<code>mixin</code>的方法实现多继承</p> <h3 id="babel是如何转化es6的"><a href="#babel是如何转化es6的" class="header-anchor">#</a> Babel是如何转化ES6的</h3> <p>Babel可以对更高级的代码进行转义,转义后的代码支持在更低级的浏览器上运行。开发者可以使用高级语法进行开发而不需要担心在低级浏览器上的兼容问题。</p> <p>例如Babel会将ES6的类(Class)写法转义为ES5的<code>prototype</code>继承式写法</p> <h4 id="class是如何转化的"><a href="#class是如何转化的" class="header-anchor">#</a> class是如何转化的</h4> <p>假设有以下ES6代码,我们解读通过Babel转义后的ES5代码:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">static</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token string">'use strict'</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">_typeof</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token string">'@babel/helpers - typeof'</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">(</span>
|
||
<span class="token punctuation">(</span>_typeof <span class="token operator">=</span>
|
||
<span class="token string">'function'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol <span class="token operator">&&</span> <span class="token string">'symbol'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol<span class="token punctuation">.</span>iterator
|
||
<span class="token operator">?</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">typeof</span> obj
|
||
<span class="token punctuation">}</span>
|
||
<span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> obj <span class="token operator">&&</span>
|
||
<span class="token string">'function'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol <span class="token operator">&&</span>
|
||
obj<span class="token punctuation">.</span>constructor <span class="token operator">===</span> Symbol <span class="token operator">&&</span>
|
||
obj <span class="token operator">!==</span> <span class="token class-name">Symbol</span><span class="token punctuation">.</span>prototype
|
||
<span class="token operator">?</span> <span class="token string">'symbol'</span>
|
||
<span class="token operator">:</span> <span class="token keyword">typeof</span> obj
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
||
<span class="token function">_typeof</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
|
||
<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_classCallCheck</span><span class="token punctuation">(</span><span class="token parameter">instance<span class="token punctuation">,</span> Constructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>instance <span class="token keyword">instanceof</span> <span class="token class-name">Constructor</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Cannot call a class as a function'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> props<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> descriptor <span class="token operator">=</span> props<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
|
||
descriptor<span class="token punctuation">.</span>enumerable <span class="token operator">=</span> descriptor<span class="token punctuation">.</span>enumerable <span class="token operator">||</span> <span class="token boolean">false</span>
|
||
descriptor<span class="token punctuation">.</span>configurable <span class="token operator">=</span> <span class="token boolean">true</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">'value'</span> <span class="token keyword">in</span> descriptor<span class="token punctuation">)</span> descriptor<span class="token punctuation">.</span>writable <span class="token operator">=</span> <span class="token boolean">true</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> <span class="token function">_toPropertyKey</span><span class="token punctuation">(</span>descriptor<span class="token punctuation">.</span>key<span class="token punctuation">)</span><span class="token punctuation">,</span> descriptor<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_createClass</span><span class="token punctuation">(</span><span class="token parameter">Constructor<span class="token punctuation">,</span> protoProps<span class="token punctuation">,</span> staticProps</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>protoProps<span class="token punctuation">)</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span><span class="token class-name">Constructor</span><span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> protoProps<span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>staticProps<span class="token punctuation">)</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span>Constructor<span class="token punctuation">,</span> staticProps<span class="token punctuation">)</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>Constructor<span class="token punctuation">,</span> <span class="token string">'prototype'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Constructor
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_toPropertyKey</span><span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> key <span class="token operator">=</span> <span class="token function">_toPrimitive</span><span class="token punctuation">(</span>arg<span class="token punctuation">,</span> <span class="token string">'string'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token function">_typeof</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'symbol'</span> <span class="token operator">?</span> key <span class="token operator">:</span> <span class="token function">String</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_toPrimitive</span><span class="token punctuation">(</span><span class="token parameter">input<span class="token punctuation">,</span> hint</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">_typeof</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string">'object'</span> <span class="token operator">||</span> input <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> input
|
||
<span class="token keyword">var</span> prim <span class="token operator">=</span> input<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>toPrimitive<span class="token punctuation">]</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>prim <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> res <span class="token operator">=</span> <span class="token function">prim</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>input<span class="token punctuation">,</span> hint <span class="token operator">||</span> <span class="token string">'default'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">_typeof</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> res
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'@@toPrimitive must return a primitive value.'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">(</span>hint <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">?</span> String <span class="token operator">:</span> Number<span class="token punctuation">)</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">var</span> Person <span class="token operator">=</span> <span class="token comment">/*#__PURE__*/</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">_classCallCheck</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> Person<span class="token punctuation">)</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">_createClass</span><span class="token punctuation">(</span>
|
||
Person<span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'running'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">' is running.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'randomPerson'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span>
|
||
<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Person
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p><code>_createClass</code>传入一个构造函数,在<code>_createClass</code>内部:</p> <ul><li><p>检查是否传入了原型方法(实例方法)</p> <ul><li>如果传入了原型方法,通过调用<code>_defineProperties</code>将这些方法挂载到<code>Constructor.prototype</code>上</li> <li>在此例中,传入<code>_defineProperties</code>的第一个参数为原型对象,第二个参数为原型方法,通过for循环挂载方法,并分别配置每个方法的属性描述符:<code>enumerable: false</code>,配置其<code>configurable: true</code>,如果配置了<code>'value'</code>属性,则<code>writable: true</code></li></ul></li> <li><p>检查是否传入了静态方法(类方法)</p> <ul><li>如果传入了静态方法,通过调用<code>_defineProperties</code>将这些方法挂载到<code>Constructor</code>上</li> <li>在此例中,具体执行过程是相同的,只不过第一个入参变成了构造函数(类),将方法直接挂载到类上</li></ul></li> <li><p>为<code>Constructor</code>类添加显式原型<code>prototype</code>属性,其值不可被覆写</p></li> <li><p>返回该构造函数<code>Person</code></p></li> <li><p>直接通过<code>var p = new Person()</code>创建实例对象</p> <ul><li>在使用<code>new</code>关键字调用函数时,在函数内部调用了<code>_classCallCheck</code> <ul><li>检查调用方式,不允许通过调用函数的方法调用类,而只能通过<code>new</code>关键字</li> <li>使用<code>new</code>关键字时会默认创建一个<code>Person</code>实例,此时函数内部的<code>this</code>自然指向这个实例</li> <li>入参为<code>this</code>与该构造函数,如果<code>this</code>不是该构造函数的实例,则抛出错误</li></ul></li></ul></li> <li><p>代码中<code>_toPropertyKey _toPrimitive _typeof</code>都是方法类</p></li> <li><p>其中涉及到纯函数(pure function)的概念:纯函数是没有任何副作用的函数,可以直接被删除而不用考虑其影响,在Tree-Shaking时有较大作用(将代码从依赖树上删除)</p></li></ul> <h4 id="extends是如何转化的"><a href="#extends是如何转化的" class="header-anchor">#</a> extends是如何转化的</h4> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">static</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">class</span> <span class="token class-name">Student</span> <span class="token keyword">extends</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">super</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">studying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is studying.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">static</span> <span class="token function">randomStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'Kobe'</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token string">'use strict'</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">_inherits</span><span class="token punctuation">(</span><span class="token parameter">subClass<span class="token punctuation">,</span> superClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> superClass <span class="token operator">!==</span> <span class="token string">'function'</span> <span class="token operator">&&</span> superClass <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Super expression must either be null or a function'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
subClass<span class="token punctuation">.</span>prototype <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>superClass <span class="token operator">&&</span> superClass<span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">constructor</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">value</span><span class="token operator">:</span> subClass<span class="token punctuation">,</span> <span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">configurable</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>subClass<span class="token punctuation">,</span> <span class="token string">'prototype'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>superClass<span class="token punctuation">)</span> <span class="token function">_setPrototypeOf</span><span class="token punctuation">(</span>subClass<span class="token punctuation">,</span> superClass<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_setPrototypeOf</span><span class="token punctuation">(</span><span class="token parameter">o<span class="token punctuation">,</span> p</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
_setPrototypeOf <span class="token operator">=</span> Object<span class="token punctuation">.</span>setPrototypeOf
|
||
<span class="token operator">?</span> Object<span class="token punctuation">.</span><span class="token function">setPrototypeOf</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">_setPrototypeOf</span><span class="token punctuation">(</span><span class="token parameter">o<span class="token punctuation">,</span> p</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
o<span class="token punctuation">.</span>__proto__ <span class="token operator">=</span> p
|
||
<span class="token keyword">return</span> o
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token function">_setPrototypeOf</span><span class="token punctuation">(</span>o<span class="token punctuation">,</span> p<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_createSuper</span><span class="token punctuation">(</span><span class="token parameter">Derived</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> hasNativeReflectConstruct <span class="token operator">=</span> <span class="token function">_isNativeReflectConstruct</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">_createSuperInternal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> Super <span class="token operator">=</span> <span class="token function">_getPrototypeOf</span><span class="token punctuation">(</span>Derived<span class="token punctuation">)</span><span class="token punctuation">,</span>
|
||
result
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>hasNativeReflectConstruct<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> NewTarget <span class="token operator">=</span> <span class="token function">_getPrototypeOf</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">.</span>constructor
|
||
result <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token function">construct</span><span class="token punctuation">(</span>Super<span class="token punctuation">,</span> arguments<span class="token punctuation">,</span> NewTarget<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
||
result <span class="token operator">=</span> <span class="token function">Super</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token function">_possibleConstructorReturn</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_possibleConstructorReturn</span><span class="token punctuation">(</span><span class="token parameter">self<span class="token punctuation">,</span> call</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>call <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token function">_typeof</span><span class="token punctuation">(</span>call<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> call <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> call
|
||
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>call <span class="token operator">!==</span> <span class="token keyword">void</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Derived constructors may only return object or undefined'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token function">_assertThisInitialized</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_assertThisInitialized</span><span class="token punctuation">(</span><span class="token parameter">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>self <span class="token operator">===</span> <span class="token keyword">void</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ReferenceError</span><span class="token punctuation">(</span><span class="token string">"this hasn't been initialised - super() hasn't been called"</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> self
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_isNativeReflectConstruct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> Reflect <span class="token operator">===</span> <span class="token string">'undefined'</span> <span class="token operator">||</span> <span class="token operator">!</span>Reflect<span class="token punctuation">.</span>construct<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>Reflect<span class="token punctuation">.</span>construct<span class="token punctuation">.</span>sham<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> Proxy <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
||
<span class="token class-name">Boolean</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>Reflect<span class="token punctuation">.</span><span class="token function">construct</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token boolean">false</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_getPrototypeOf</span><span class="token punctuation">(</span><span class="token parameter">o</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
_getPrototypeOf <span class="token operator">=</span> Object<span class="token punctuation">.</span>setPrototypeOf
|
||
<span class="token operator">?</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">_getPrototypeOf</span><span class="token punctuation">(</span><span class="token parameter">o</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> o<span class="token punctuation">.</span>__proto__ <span class="token operator">||</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>o<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token function">_getPrototypeOf</span><span class="token punctuation">(</span>o<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_typeof</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token string">'@babel/helpers - typeof'</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">(</span>
|
||
<span class="token punctuation">(</span>_typeof <span class="token operator">=</span>
|
||
<span class="token string">'function'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol <span class="token operator">&&</span> <span class="token string">'symbol'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol<span class="token punctuation">.</span>iterator
|
||
<span class="token operator">?</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">typeof</span> obj
|
||
<span class="token punctuation">}</span>
|
||
<span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> obj <span class="token operator">&&</span>
|
||
<span class="token string">'function'</span> <span class="token operator">==</span> <span class="token keyword">typeof</span> Symbol <span class="token operator">&&</span>
|
||
obj<span class="token punctuation">.</span>constructor <span class="token operator">===</span> Symbol <span class="token operator">&&</span>
|
||
obj <span class="token operator">!==</span> <span class="token class-name">Symbol</span><span class="token punctuation">.</span>prototype
|
||
<span class="token operator">?</span> <span class="token string">'symbol'</span>
|
||
<span class="token operator">:</span> <span class="token keyword">typeof</span> obj
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
||
<span class="token function">_typeof</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
|
||
<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_classCallCheck</span><span class="token punctuation">(</span><span class="token parameter">instance<span class="token punctuation">,</span> Constructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>instance <span class="token keyword">instanceof</span> <span class="token class-name">Constructor</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'Cannot call a class as a function'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> props<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> descriptor <span class="token operator">=</span> props<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
|
||
descriptor<span class="token punctuation">.</span>enumerable <span class="token operator">=</span> descriptor<span class="token punctuation">.</span>enumerable <span class="token operator">||</span> <span class="token boolean">false</span>
|
||
descriptor<span class="token punctuation">.</span>configurable <span class="token operator">=</span> <span class="token boolean">true</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">'value'</span> <span class="token keyword">in</span> descriptor<span class="token punctuation">)</span> descriptor<span class="token punctuation">.</span>writable <span class="token operator">=</span> <span class="token boolean">true</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> <span class="token function">_toPropertyKey</span><span class="token punctuation">(</span>descriptor<span class="token punctuation">.</span>key<span class="token punctuation">)</span><span class="token punctuation">,</span> descriptor<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_createClass</span><span class="token punctuation">(</span><span class="token parameter">Constructor<span class="token punctuation">,</span> protoProps<span class="token punctuation">,</span> staticProps</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>protoProps<span class="token punctuation">)</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span><span class="token class-name">Constructor</span><span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> protoProps<span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>staticProps<span class="token punctuation">)</span> <span class="token function">_defineProperties</span><span class="token punctuation">(</span>Constructor<span class="token punctuation">,</span> staticProps<span class="token punctuation">)</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>Constructor<span class="token punctuation">,</span> <span class="token string">'prototype'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Constructor
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_toPropertyKey</span><span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> key <span class="token operator">=</span> <span class="token function">_toPrimitive</span><span class="token punctuation">(</span>arg<span class="token punctuation">,</span> <span class="token string">'string'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token function">_typeof</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'symbol'</span> <span class="token operator">?</span> key <span class="token operator">:</span> <span class="token function">String</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">function</span> <span class="token function">_toPrimitive</span><span class="token punctuation">(</span><span class="token parameter">input<span class="token punctuation">,</span> hint</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">_typeof</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string">'object'</span> <span class="token operator">||</span> input <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> input
|
||
<span class="token keyword">var</span> prim <span class="token operator">=</span> input<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>toPrimitive<span class="token punctuation">]</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>prim <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> res <span class="token operator">=</span> <span class="token function">prim</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>input<span class="token punctuation">,</span> hint <span class="token operator">||</span> <span class="token string">'default'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">_typeof</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> res
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'@@toPrimitive must return a primitive value.'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> <span class="token punctuation">(</span>hint <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">?</span> String <span class="token operator">:</span> Number<span class="token punctuation">)</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">var</span> Person <span class="token operator">=</span> <span class="token comment">/*#__PURE__*/</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">_classCallCheck</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> Person<span class="token punctuation">)</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">_createClass</span><span class="token punctuation">(</span>
|
||
Person<span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'running'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">running</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">' is running.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'randomPerson'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">randomPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span>
|
||
<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Person
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">var</span> Student <span class="token operator">=</span> <span class="token comment">/*#__PURE__*/</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">_Person</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">_inherits</span><span class="token punctuation">(</span>Student<span class="token punctuation">,</span> _Person<span class="token punctuation">)</span>
|
||
<span class="token keyword">var</span> _super <span class="token operator">=</span> <span class="token function">_createSuper</span><span class="token punctuation">(</span>Student<span class="token punctuation">)</span>
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> score</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">var</span> _this
|
||
<span class="token function">_classCallCheck</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> Student<span class="token punctuation">)</span>
|
||
_this <span class="token operator">=</span> <span class="token function">_super</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span>
|
||
_this<span class="token punctuation">.</span>score <span class="token operator">=</span> score
|
||
<span class="token keyword">return</span> _this
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">_createClass</span><span class="token punctuation">(</span>
|
||
Student<span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'studying'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">studying</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">' is studying.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span>
|
||
<span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token string">'randomStudent'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">value</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">randomStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span>
|
||
<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Student
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span>Person<span class="token punctuation">)</span>
|
||
<span class="token keyword">var</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'Kobe'</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>创建<code>Student</code>类的代码仍然是一个纯函数:</p> <ul><li>立即执行函数传入了一个实参<code>Person</code>,随后实参作为内部函数的形参读取到函数内部以供使用</li> <li>可以消除副作用,避免直接调用外部变量形成闭包,让立即执行函数在得到参数的同时成为纯函数</li></ul> <p>在<code>Student</code>内部通过调用<code>_inherits</code>,传入<code>Student</code>与<code>Person</code>,将二者之间做了关联:</p> <ul><li>创建一个<code>Person</code>实例对象,并将<code>Student</code>的原型对象指向此对象</li> <li>向此对象上添加<code>constructor</code>属性,指向构造函数<code>Student</code></li> <li>经过<code>_setPrototypeOf</code>,<code>Student</code>的<code>__proto__</code>指向了<code>Person</code>,这样带来的好处:让<code>Student</code>函数对象可以继承<code>Person</code>的类方法</li></ul> <p>实现继承后,通过<code>_createClass</code>创建类,相关内容不再重复叙述(挂载实例方法、类方法、<code>prototype</code>属性)</p> <p>至此完成了<code>Student</code>类的创建,随后我们通过<code>var s = new Student(...)</code>创建一个<code>Student</code>实例</p> <ul><li>通过<code>new</code>关键字调用<code>Student</code>时,将执行其内部的<code>function Student</code></li> <li>首先执行<code>_classCallCheck</code>检查调用方式是否合法</li> <li>在内部通过借用构造函数继承<code>_this = _super.call(this, name)</code> <ul><li>此处的<code>_super</code>本质上就是父类(可以理解为<code>_this = Person.call(this, name)</code>)下面来解释一下<code>_super</code>的创建过程</li> <li>通过<code>_createSuper</code>方法创建<code>_super</code> <ul><li>检查是否支持<code>Reflect</code>,返回的新的函数<code>_createSuperInternal</code>实际上就是<code>_super</code></li> <li>当外部通过<code>_this = _super.call(this, name)</code>调用时,实际上调用的就是这个函数</li> <li>首先获取子类的原型,通过<code>_getPrototypeof</code>,该函数内部进行了一些兼容性判断,检查是否支持各种获取原型的方法</li> <li>最终获取到<code>Student</code>的隐式原型<code>Person</code>并赋值给<code>_Super</code> <ul><li>如果支持<code>Reflect</code>,通过<code>Reflect.construct</code>实现借用构造函数继承,调用父类的构造方法</li> <li>如果不支持<code>Reflect</code>,通过<code>Super.apply()</code>实现···</li></ul></li></ul></li> <li>绕了一圈,本质上就是调用了<code>_Person.call(this, name)</code>,并且将创建的对象返回出来赋值给<code>result</code></li></ul></li></ul> <h4 id="自己实现的es5对比"><a href="#自己实现的es5对比" class="header-anchor">#</a> 自己实现的ES5对比</h4> <p>在之前的内容中我们自己实现了相关的类定义/继承功能</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name <span class="token comment">// 定义内部属性</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 定义实例方法</span>
|
||
<span class="token class-name">Person</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">running</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is running.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 定义类方法(静态方法)</span>
|
||
Person<span class="token punctuation">.</span><span class="token function-variable function">randomPerson</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>自己实现的继承:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">inherit</span><span class="token punctuation">(</span><span class="token parameter">SubClass<span class="token punctuation">,</span> SuperClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 创建一个新对象并将新对象的原型指向父类构造函数的原型</span>
|
||
subType<span class="token punctuation">.</span>prototype <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>superType<span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 为子类的原型添加constructor属性</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>subType<span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token string">'constructor'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">enumerable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment">// 不可被枚举</span>
|
||
<span class="token literal-property property">configurable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 值可被修改</span>
|
||
<span class="token literal-property property">writable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 值可被覆写</span>
|
||
<span class="token literal-property property">value</span><span class="token operator">:</span> subType <span class="token comment">// 初始值: 父类构造函数</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">inherit</span><span class="token punctuation">(</span>Student<span class="token punctuation">,</span> Person<span class="token punctuation">)</span>
|
||
</code></pre></div><p>相比之下不难发现,Babel转义用ES5实现相关功能的核心思想是一致的,只不过Babel转义后的代码添加了更多的边界条件的判定。</p> <h2 id="浏览器运行原理"><a href="#浏览器运行原理" class="header-anchor">#</a> 浏览器运行原理</h2> <h3 id="网页解析过程"><a href="#网页解析过程" class="header-anchor">#</a> 网页解析过程</h3> <p>输入域名 => DNS解析为IP => 目标服务器返回<code>index.html</code></p> <blockquote><p>DNS:Domain Name System</p></blockquote> <h4 id="html解析过程"><a href="#html解析过程" class="header-anchor">#</a> HTML解析过程</h4> <ul><li><p>浏览器开始解析<code>index.html</code>文件,当遇到<code><link></code>则向服务器请求下载<code>.css</code>文件</p></li> <li><p>遇到<code><script></code>标签则向服务器请求下载<code>.js</code>文件</p></li></ul> <img src="JavaScriptEnhanced.assets/image-20221118222207332-16687813334481.png" alt="浏览器解析HTML过程" style="zoom:80%;"> <img src="JavaScriptEnhanced.assets/image-20221118222311200-16687813941873.png" alt="浏览器是和如何工作的" style="zoom:80%;"> <p><a href="https://web.dev/howbrowserswork/" target="_blank" rel="noopener noreferrer">How browsers work<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h4 id="生成css规则"><a href="#生成css规则" class="header-anchor">#</a> 生成CSS规则</h4> <p>在解析的过程中,如果遇到<code><link></code>元素,那么会由浏览器负责下载对应的CSS文件</p> <ul><li>注意:下载CSS文件不会影响到DOM解析</li> <li>有单独一个线程对CSS文件进行下载与解析</li></ul> <p>浏览器下载完CSS文件后,就会对CSS文件进行解析,解析出对应的规则树:</p> <ul><li>我们可以称之为CSSOM(CSS Object Model,CSS对象模型)</li></ul> <h4 id="构建render-tree"><a href="#构建render-tree" class="header-anchor">#</a> 构建Render Tree</h4> <p>有了DOM Tree和CSSOM Tree之后,就可以将二者结合,构建Render Tree了</p> <p>此时,如果有某些元素的CSS属性<code>display: none;</code>那么这个元素就不会出现在Render Tree中</p> <ul><li>下载和解析CSS文件时,不会阻塞DOM Tree的构建过程</li> <li>但会阻塞Render Tree的构建过程:因为需要对应的CSSOM Tree</li></ul> <h4 id="布局和绘制-layout-paint"><a href="#布局和绘制-layout-paint" class="header-anchor">#</a> 布局和绘制(Layout & Paint)</h4> <p>第四步是在渲染树(Render Tree)上运行布局(Layout),以计算每个节点的几何体</p> <ul><li>渲染树会表示显示哪些节点以及其他的样式,但是不表示每个节点的尺寸、位置等信息</li> <li>布局是确定呈现树中所有节点的宽度、高度和位置信息</li></ul> <p>第五步是将每个节点绘制(Paint)到屏幕上</p> <ul><li>在绘制阶段,浏览器布局阶段计算的每个frame转为屏幕上实际的像素点</li> <li>包括将元素的可见部分进行绘制,比如文本、颜色、边框、阴影、替换元素</li></ul> <h4 id="回流和重绘-reflow"><a href="#回流和重绘-reflow" class="header-anchor">#</a> 回流和重绘(Reflow & )</h4> <p>回流也可称为重排</p> <p>理解回流(Reflow):</p> <ul><li>第一次确定节点的大小和位置,称之为布局(layout)</li> <li>之后对节点的大小、位置修改重新计算,称之为回流</li></ul> <p>什么情况下会引起回流?</p> <ul><li>DOM 结构发生改变(添加新的节点或者移除节点)</li> <li>改变了布局(修改了width height padding font-size等值)</li> <li>窗口resize(修改了窗口的尺寸等)</li> <li>调用getComputedStyle方法获取尺寸、位置信息</li></ul> <p>理解重绘(Repaint):</p> <ul><li>第一次渲染内容称之为绘制(paint)</li> <li>之后的重新渲染称之为重绘</li></ul> <p>什么情况下会引起重绘?</p> <ul><li>修改背景色、文字颜色、边框颜色、样式等</li></ul> <p><strong>回流一定会引起重绘,所以回流是一件很消耗性能的事情</strong></p> <ul><li>开发中要尽量避免发生回流</li> <li>修改样式尽量一次性修改完毕
|
||
<ul><li>例如通过cssText一次性设置样式,或通过修改class的方式修改样式</li></ul></li> <li>尽量避免频繁的操作DOM
|
||
<ul><li>可以在一个DocumentFragment或者父元素中,将要操作的DOM操作完成,再一次性插入到DOM树中</li></ul></li> <li>尽量避免通过getComputedStyle获取元素尺寸、位置等信息</li> <li>对某些元素使用position的absolute或fixed属性
|
||
<ul><li>并不是不会引起回流,而是开销相对较小,不会对其他元素产生影响</li></ul></li></ul> <h4 id="特殊解析-composite合成"><a href="#特殊解析-composite合成" class="header-anchor">#</a> 特殊解析: composite合成</h4> <p>在绘制的过程中,可以将布局后的元素绘制到多个合成图层中</p> <ul><li>这是浏览器的一种优化手段</li> <li>将不同流生成的不同Layer进行合并</li></ul> <div class="language- extra-class"><pre class="language-text"><code>标准流 => LayouTree => RenderLayer
|
||
`position:fixed;` => RenderLayer
|
||
</code></pre></div><p>默认情况,标准流中的内容都是被绘制在同一个图层(Layer)中的</p> <p>而一些特殊的属性,浏览器会创建一个新的合成层(CompositingLayer),并且新的图层可以利用GPU来加速绘制</p> <ul><li>每个合成层都是单独渲染的</li> <li>单独渲染可以避免所有的动画都在同一层中渲染导致性能问题</li> <li>在各自的层中渲染完成后,只需要将渲染结果更新回合成层即可</li></ul> <p>当元素具有哪些属性时,浏览器会为其创建新的合成层呢?</p> <ul><li>3D Transforms</li> <li>video canvas iframe</li> <li>opacity 动画转换时</li> <li>position: fixed</li> <li>will-change: 一个实验性的属性,提前告诉浏览器此元素可能发生哪些变化</li> <li>animation 或 transition设置了opacity、transform</li></ul> <h5 id="案例1-同一层渲染"><a href="#案例1-同一层渲染" class="header-anchor">#</a> 案例1:同一层渲染</h5> <div class="language-css extra-class"><pre class="language-css"><code><span class="token selector">.box1</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token selector">.box2</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>box1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>box2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
|
||
</code></pre></div><p>在开发者工具的图层工具中可以看到,两个元素<code>.box1</code> 和 <code>.box2</code>都是在一个层(Document)下渲染的:</p> <p><img src="JavaScriptEnhanced.assets/image-20221122103111654.png" alt="image-20221122103111654"></p> <h5 id="案例2-分层渲染"><a href="#案例2-分层渲染" class="header-anchor">#</a> 案例2:分层渲染</h5> <p>当我们为<code>.box2</code>添加上<code>position: fixed;</code>属性,这时<code>.box2</code>将在由浏览器创建出来的合成层,分层单独渲染</p> <div class="language-css extra-class"><pre class="language-css"><code><span class="token selector">.box2</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
|
||
<span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p><img src="JavaScriptEnhanced.assets/image-20221122103256116.png" alt="image-20221122103256116"></p> <h5 id="案例3-transform-3d"><a href="#案例3-transform-3d" class="header-anchor">#</a> 案例3:transform 3D</h5> <p>为元素添加上<code>transform</code>属性时,浏览器也会为对应元素创建一个合成层,需要注意的是:只有3D的变化浏览器才会创建</p> <p>如果是<code>translateX</code>或<code>translateY</code>则不会</p> <div class="language-css extra-class"><pre class="language-css"><code><span class="token selector">.box2</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
|
||
<span class="token comment">/* position: fixed; */</span>
|
||
<span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateZ</span><span class="token punctuation">(</span>10px<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p><img src="JavaScriptEnhanced.assets/image-20221122103715428.png" alt="image-20221122103715428"></p> <h5 id="案例4-transition-transform"><a href="#案例4-transition-transform" class="header-anchor">#</a> 案例4:transition+transform</h5> <p>当我们为元素添加上动画时,动画的中间执行过程的渲染会在新的图层上进行,但是中间动画渲染完成后,结果会回到原始图层上</p> <div class="language-css extra-class"><pre class="language-css"><code><span class="token selector">.box2</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
|
||
<span class="token property">transition</span><span class="token punctuation">:</span> transform 0.5s ease<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token selector">.box2:hover</span> <span class="token punctuation">{</span>
|
||
<span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>10px<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><ul><li>这也是使用<code>transform</code>执行动画性能更高的原因,因为浏览器会为动画的执行过程单独创建一个合成层</li> <li>如果是通过修改<code>top</code> <code>left</code>等定位属性实现的动画,是在原始的图层上渲染完成的。“牵一发则动全身”,动画过程中将导致整个渲染树回流与重绘,极大的影响性能</li></ul> <h5 id="案例5-transition-opacity"><a href="#案例5-transition-opacity" class="header-anchor">#</a> 案例5:transition+opacity</h5> <p>与<code>transform</code>类似,使用<code>transition</code>过渡的<code>opacity</code>动画,浏览器也会为其创建一个合成层</p> <div class="language-css extra-class"><pre class="language-css"><code><span class="token selector">.box2</span> <span class="token punctuation">{</span>
|
||
<span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
|
||
<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
|
||
<span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
|
||
<span class="token property">transition</span><span class="token punctuation">:</span> opacity 0.5s ease<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token selector">.box2:hover</span> <span class="token punctuation">{</span>
|
||
<span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h5 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h5> <p>分层确实可以提高性能,但是它是以内存管理为代价的,因此不应当作为Web性能优化策略的一部分过度使用</p> <h3 id="浏览器对script元素的处理"><a href="#浏览器对script元素的处理" class="header-anchor">#</a> 浏览器对script元素的处理</h3> <p>之前我们说到,在解析到<code>link</code>标签时,浏览器会异步下载其中的css文件,并在DOM树构建完成后,将其与CSS Tree合成为RenderTree</p> <p>但是当浏览器解析到<code>script</code>标签时,整个解析过程将被阻塞,当前<code>script</code>标签后面的DOM树将停止解析,直到当前<code>script</code>代码被下载、解析、执行完毕,才会继续解析HTML,构建DOM树</p> <p>为什么要这样做呢?</p> <ul><li>这是因为Javascript的作用之一就是操作DOM,并且可以修改DOM</li> <li>如果我们等到DOM树构建完成并且渲染出来了,再去执行Javascript,会造成回流和重绘,严重影响页面性能</li> <li>所以当浏览器构建DOM树遇到<code>script</code>标签时,会优先下载和执行Javascript代码,而后再继续构建DOM树</li></ul> <p>这也会带来新的问题,比如在现代的页面开发中:</p> <ul><li>脚本往往比HTML更“重”,浏览器也需要花更多的时间去处理脚本</li> <li>会造成页面的解析阻塞,在脚本下载、解析、执行完成之前,用户在界面上什么也看不到</li></ul> <p>为了解决这个问题,浏览器的<code>script</code>标签为我们提供了两个属性(attribute):<code>defer</code> 和 <code>async</code></p> <h4 id="defer属性"><a href="#defer属性" class="header-anchor">#</a> defer属性</h4> <p><code>defer</code> 即推迟,为<code>script</code>标签添加这个属性,相当于告诉浏览器:不要等待此脚本下载,而是继续解析HTML,构建DOM Tree</p> <ul><li>脚本将由浏览器进行下载,但是不会阻塞DOM Tree的构建过程</li> <li>如果脚本提前下载好了,那么它会等待DOM Tree构建完成,在<code>DOMContentLoaded</code><strong>事件触发之前</strong>先执行<code>defer</code>中的代码</li></ul> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script enter'</span><span class="token punctuation">)</span>
|
||
window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded enter'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>./defer.js<span class="token punctuation">"</span></span> <span class="token attr-name">defer</span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// defer.js</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'defer script enter'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>上述代码在控制台的输出为:</p> <div class="language- extra-class"><pre class="language-text"><code>script enter
|
||
defer script enter
|
||
DOMContentLoaded enter
|
||
</code></pre></div><ul><li>多个带<code>defer</code>的脚本也是按照自上至下的顺序执行的</li> <li>从某种角度来说,<code>defer</code>可以提高页面的性能,并且推荐放到<code>head</code>元素中</li> <li>注意:<code>defer</code>仅适用于外部脚本,对于<code>script</code>标签内编写的默认<code>JS</code>代码会被忽略掉</li></ul> <h4 id="async属性"><a href="#async属性" class="header-anchor">#</a> async属性</h4> <p><code>async</code>属性也可以做到:让脚本异步加载而不阻塞DOM树的构建,它与<code>defer</code>的区别:</p> <ul><li>用<code>async</code>标记的脚本是<strong>完全独立</strong>的</li> <li><code>async</code>脚本不能保证执行顺序,因为它是独立下载、独立运行,不会等待其他脚本</li> <li>使用<code>async</code>标记的脚本不会保证它将在<code>DOMContentLoaded</code>之前或之后被执行</li></ul> <p>要使用<code>async</code>属性标记的<code>script</code>操作DOM,必须在其中使用<code>DOMContentLoaded</code>监听器的回调函数,在该事件触发(DOM树构建完毕)后,执行相应的回调函数</p> <h2 id="javascript-运行原理"><a href="#javascript-运行原理" class="header-anchor">#</a> JavaScript 运行原理</h2> <h3 id="js代码的执行"><a href="#js代码的执行" class="header-anchor">#</a> JS代码的执行</h3> <p>JavaScript代码下载好后,是如何一步步被执行的?</p> <p>浏览器内核是由两部分组成的,以Webkit为例:</p> <ul><li>WebCore:负责HTML解析、布局、渲染等相关的工作</li> <li>JavaScriptCore:解析、执行JavaScript代码</li></ul> <h3 id="javascript-v8引擎"><a href="#javascript-v8引擎" class="header-anchor">#</a> JavaScript V8引擎</h3> <p><img src="JavaScriptEnhanced.assets/image-20221125090752249.png" alt="image-20221125090752249"></p> <p>JS源代码经过解析,生成抽象语法树(词法分析器、语法分析器),经过ignition转为字节码(二进制、跨平台),即可由CPU执行</p> <p>在ignition的过程中,会由TurboFan收集类型信息(检查哪些函数是被重复执行的),对优化生成的机器码,得到性能更高的机器指令</p> <p>如果生成的优化的机器码不符合函数实际执行,则会进行Deoptimization(反优化),降级回普通的字节码</p> <ul><li>Parse模块会将JavaScript代码转化为AST(抽象语法树),因为解释器并不直接认识JavaScript代码
|
||
<ul><li>如果函数没有被调用,那么是不会被转换成AST的</li> <li>官方文档:https://v8.dev/blog/scanner</li></ul></li> <li>Ignition是一个解释器,会将AST转换成ByteCode(字节码)
|
||
<ul><li>同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的计算)</li> <li>如果函数只调用一次,Ignition会直接解释执行ByteCode</li> <li>官方文档:https://v8.dev/blog/ignition-interpreter</li></ul></li> <li>TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码
|
||
<ul><li>如果一个函数被多次调用,那么就会被标记为热点函数,经过TurboFan转化成优化的机器码,提高代码的执行性能</li> <li>但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码</li> <li>官方文档:https://v8.dev/blog/turbofan-jit</li></ul></li></ul> <p><img src="JavaScriptEnhanced.assets/image-20221125094148365.png" alt="image-20221125094148365"></p> <p>Blink 获取到源码 => 转为Stream => Scanner扫描器</p> <ul><li>词法分析(lexical analysis,简称lexer)
|
||
<ul><li>将字符序列转换成token序列的过程,例如<code>var name = 'Ziu'</code>,词法分析器会将每个词转为token</li> <li>token是记号化(tokenization)的缩写</li> <li>词法分析器,也叫扫描器(scanner)</li></ul></li> <li>语法分析(syntactic analysis,也叫parsing)
|
||
<ul><li>语法分析器也可以称之为parser 解析器</li></ul></li></ul> <h3 id="javascript代码执行过程"><a href="#javascript代码执行过程" class="header-anchor">#</a> JavaScript代码执行过程</h3> <ul><li>初始化全局对象
|
||
<ul><li>js引擎会在执行代码之前,在堆内存中创建一个全局对象:Global Object (GO)</li> <li>该对象可以在所有的作用域(scope)中被访问</li> <li>里面会包含Date、Array、String、Number、setTimeout、setInterval等内置对象</li> <li>其中还包含一个window属性指向自己</li></ul></li> <li>执行上下文
|
||
<ul><li>JS引擎内部有一个执行上下文栈(Execution Context Stack 简称ECS),它是用于执行代码的调用栈</li> <li>那么现在它要执行谁呢?执行的是全局的代码块:
|
||
<ul><li>全局的代码块为了执行会构建一个Global Execution Context(GEC)</li> <li>GEC会被放入到ECS中执行</li></ul></li> <li>GEC被放入到ECS中里面包含两部分内容:
|
||
<ul><li>第一部分:在代码执行之前,在parser转化为AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值
|
||
<ul><li>这个过程也被称为变量的作用域提升(hoisting)</li></ul></li> <li>第二部分:在代码的执行过程中,对变量进行赋值,或者执行其他的函数
|
||
<ul><li>当代码被翻译为可执行代码,将进入到一个可执行的上下文中,活跃的函数执行上下文在逻辑上是一个栈,</li></ul></li></ul></li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">fun1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'fun1'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">fun2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'fun2 start'</span><span class="token punctuation">)</span>
|
||
<span class="token function">fun1</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'fun2 end'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">fun2</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>创建全局执行上下文 => 函数执行到<code>fun2()</code> => 创建<code>fun2</code>执行上下文 => 函数执行到<code>fun1()</code> => 创建<code>fun1</code>执行上下文 => <code>fun1</code>执行完毕出栈 => 继续执行<code>fun2</code>后续代码 => <code>fun2</code>执行完毕出栈 => 继续执行全局上下文后续代码 => 结束</p> <div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'fun2 start'</span>
|
||
<span class="token string">'fun1'</span>
|
||
<span class="token string">'fun2 end'</span>
|
||
<span class="token string">'script end'</span>
|
||
</code></pre></div><h2 id="proxy与reflect"><a href="#proxy与reflect" class="header-anchor">#</a> Proxy与Reflect</h2> <ul><li>监听对象的操作</li> <li>Proxy类基本使用</li> <li>Proxy常见捕获器</li> <li>Reflect介绍和作用</li> <li>Reflect基本使用</li> <li>Reflect的receiver</li></ul> <h3 id="监听对象方法"><a href="#监听对象方法" class="header-anchor">#</a> 监听对象方法</h3> <h4 id="proxy监听对象"><a href="#proxy监听对象" class="header-anchor">#</a> Proxy监听对象</h4> <p>可以使用Proxy对象将原对象包裹,此后的操作都对<code>proxy</code>进行,每次<code>get</code>与<code>set</code>被触发时都会自动执行相应代码</p> <ul><li>可以为<code>handler</code>传入不同的捕获器</li> <li>需要注意的是 <code>get</code> 与 <code>set</code> 都需要有返回值
|
||
<ul><li><code>get</code> 默认行为是返回属性值</li> <li><code>set</code> 返回<code>true</code>表示设置成功 也可以做其他<code>if-else</code>抛出错误表示执行失败</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 需要注意的是 get 与 set 都需要有返回值</span>
|
||
<span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'get'</span><span class="token punctuation">,</span> key<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token comment">// 默认行为是返回属性值</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'set'</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
|
||
target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> value
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span> <span class="token comment">// 代表执行成功</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> tmp <span class="token operator">=</span> proxy<span class="token punctuation">.</span>age <span class="token comment">// getter被触发</span>
|
||
proxy<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span> <span class="token comment">// setter被触发</span>
|
||
</code></pre></div><h4 id="defineproperty监听对象"><a href="#defineproperty监听对象" class="header-anchor">#</a> defineProperty监听对象</h4> <p>除此之外,可以通过<code>Object.defineProperty</code>为对象中某个属性设置<code>getter</code>与<code>setter</code>函数,可以达到类似的效果</p> <p>需要注意的是,此处要用<code>for-in</code>遍历对象的所有属性,并逐个为其设置<code>getter</code>与<code>setter</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">of</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> value <span class="token operator">=</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> key<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'get'</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> value
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function">set</span><span class="token punctuation">(</span>newVal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'set'</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal<span class="token punctuation">)</span>
|
||
value <span class="token operator">=</span> newVal
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="proxy与defineproperty的区别"><a href="#proxy与defineproperty的区别" class="header-anchor">#</a> Proxy与defineProperty的区别</h4> <p><a href="https://segmentfault.com/a/1190000041084082" target="_blank" rel="noopener noreferrer">defineProperty 和 Proxy区别<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <ol><li><p><strong>监听数据的角度</strong></p> <ol><li><code>defineproperty</code>只能监听某个属性而不能监听整个对象。</li> <li><code>proxy</code>不用设置具体属性,直接监听整个对象。</li> <li><code>defineproperty</code>监听需要知道是哪个对象的哪个属性,而<code>proxy</code>只需要知道哪个对象就可以了。也就是会省去<code>for in</code>循环提高了效率。</li></ol></li> <li><p><strong>监听对原对象的影响</strong></p> <ol><li>因为<code>defineproperty</code>是通过在原对象身上新增或修改属性增加描述符的方式实现的监听效果,一定会修改原数据。</li> <li>而<code>proxy</code>只是原对象的代理,<code>proxy</code>会返回一个代理对象不会在原对象上进行改动,对原数据无污染。</li></ol></li> <li><p><strong>实现对数组的监听</strong></p> <ol><li>因为数组 <code>length</code> 的特殊性 <code>(length 的描述符configurable 和 enumerable 为 false,并且妄图修改 configurable 为 True 的话 js 会直接报错:VM305:1 Uncaught TypeError: Cannot redefine property: length)</code></li> <li><code>defineproperty</code>无法监听数组长度变化, <code>Vue</code>只能通过重写数组方法的方式变现达成监听的效果,光重写数组方法还是不能解决修改数组下标时监听的问题,只能再使用自定义的<code>$set</code>的方式</li> <li>而<code>proxy</code>因为自身特性,是创建新的代理对象而不是在原数据身上监听属性,对代理对象进行操作时,所有的操作都会被捕捉,包括数组的方法和<code>length</code>操作,再不需要重写数组方法和自定义<code>set</code>函数了。(代码示例在下方)</li></ol> <p><strong>4. 监听的范围</strong></p> <ol><li><code>defineproperty</code>只能监听到<code>value</code>的 <code>get set</code> 变化。</li> <li><code>proxy</code>可以监听除 <code>[[getOwnPropertyNames]]</code> 以外所有<code>JS</code>的对象操作。监听的范围更大更全面。</li></ol></li></ol> <h3 id="proxy"><a href="#proxy" class="header-anchor">#</a> Proxy</h3> <div class="language-JS extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> handler<span class="token punctuation">)</span>
|
||
</code></pre></div><p>即使不传入handler,默认也会进行基本的代理操作,将对代理对象的操作透传给原始对象</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
proxy<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token number">1.88</span> <span class="token comment">// 添加新属性</span>
|
||
proxy<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span> <span class="token comment">// 修改原属性</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// { name: 'Ziu', age: 18, height: 1.88 }</span>
|
||
</code></pre></div><h4 id="捕获器-trap"><a href="#捕获器-trap" class="header-anchor">#</a> 捕获器 (trap)</h4> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy#handler_%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95" target="_blank" rel="noopener noreferrer">handler 对象的方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>常用的捕获器有<code>set</code>与<code>get</code>函数</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 设置 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> newVal
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 获取</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> target<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><ul><li>set函数有四个参数
|
||
<ul><li>target 目标对象(侦听的对象)</li> <li>property 即将被设置的属性key</li> <li>value 新属性值</li> <li>receiver 调用的代理对象</li></ul></li> <li>get函数有三个参数
|
||
<ul><li>target 目标对象(侦听的对象)</li> <li>property 被获取的属性key</li> <li>receiver 调用的代理对象</li></ul></li></ul> <p>另外介绍两个捕获器:<code>has</code>与<code>deleteProperty</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token operator">...</span>
|
||
<span class="token function-variable function">has</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 判断</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> key <span class="token keyword">in</span> target
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">deleteProperty</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 删除 </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token boolean">true</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">delete</span> proxy<span class="token punctuation">.</span>name <span class="token comment">// 监听: name 删除</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'age'</span> <span class="token keyword">in</span> proxy<span class="token punctuation">)</span> <span class="token comment">// 监听: age 判断</span>
|
||
</code></pre></div><h4 id="this指向问题"><a href="#this指向问题" class="header-anchor">#</a> this指向问题</h4> <p><code>Proxy</code>对象可以对我们的目标对象进行访问,但没有做任何拦截时,也不能保证与目标对象的行为一致,因为目标对象内部的<code>this</code>会自动改变为<code>Proxy</code>代理对象。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span> <span class="token operator">===</span> proxy
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>proxy<span class="token punctuation">.</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
</code></pre></div><h4 id="使用proxy监听嵌套对象"><a href="#使用proxy监听嵌套对象" class="header-anchor">#</a> 使用Proxy监听嵌套对象</h4> <p>TODO</p> <h3 id="reflect"><a href="#reflect" class="header-anchor">#</a> Reflect</h3> <p>Reflect是ES6新增的一个API,它本身是一个对象</p> <ul><li>提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法</li> <li>比如<code>Reflect.getPrototypeOf(target)</code>类似于<code>Object.getPrototypeOf()</code></li> <li>比如<code>Reflect.defineProperty(targetm propertyKey, attributes)</code>类似于<code>Object.defineProperty()</code></li></ul> <p>如果我们又Object对象可以完成这些操作,为什么还需要Reflect呢?</p> <ul><li>Object作为一个构造函数,这些操作放到它身上并不合适</li> <li>包含一些类似于 in delete的操作符</li> <li>在ES6新增了Reflect,让这些操作都集中到了Reflect对象上</li> <li>在使用Proxy时,可以做到不操作原对象</li></ul> <h4 id="与object操作的区别"><a href="#与object操作的区别" class="header-anchor">#</a> 与Object操作的区别</h4> <p>删除对象上的某个属性</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变</span>
|
||
<span class="token comment">// 同时该属性也能从对应的对象上被删除。 默认为 false。</span>
|
||
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">configurable</span><span class="token operator">:</span> <span class="token boolean">false</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 1. 旧方法 检查`delete obj.name`是否执行成功</span>
|
||
<span class="token comment">// 结果: 需要额外编写检查代码且存在问题(严格模式下删除configurable为false的属性将报错)</span>
|
||
<span class="token keyword">delete</span> obj<span class="token punctuation">.</span>name
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 2. Reflect</span>
|
||
<span class="token comment">// 结果: 根据是否删除成功返回结果</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>Reflect<span class="token punctuation">.</span><span class="token function">deleteProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="reflect常见方法"><a href="#reflect常见方法" class="header-anchor">#</a> Reflect常见方法</h4> <p>其中的方法与Proxy的方法是一一对应的,一共13个。其中的一些方法是Object对象中没有的:</p> <ul><li><code>has</code> 判断一个对象是否存在某个属性,和 <code>in</code> 运算符功能完全相同</li> <li><code>get</code> 获取对象身上某个属性的值,类似于<code>target[key]</code></li> <li><code>set</code> 将值分配给属性的函数,返回一个Boolean,如果更新成功则返回true</li> <li><code>deleteProperty</code> 作为函数的 <code>delete</code> 操作符,相当于执行 <code>delete target[key]</code></li> <li>···</li></ul> <p>代理对象的目的:不再直接操作原始对象,一切读写操作由代理完成。我们先前在编写Proxy的代理代码时,仍然有操作原对象的行为:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 设置 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> newVal <span class="token comment">// 直接操作原对象</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>这时我们可以让Reflect登场,代替我们对原对象进行操作,之前的代码可以修改:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 设置 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
Reflect<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 获取</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Reflect<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">has</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 判断</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Reflect<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>使用Reflect替代之前的对象操作有以下好处:</p> <ul><li>代理对象的目的:不再直接操作原对象</li> <li>Reflect.set方法有返回Boolean值,可以判断本次操作是否成功</li> <li>receiver就是外层的Proxy对象</li></ul> <p>针对好处三,做出如下解释。以下述代码为例,<code>set name(){}</code>函数中的<code>this</code>指向的是<code>obj</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">_name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token keyword">set</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token parameter">newVal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">set name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>_name <span class="token operator">=</span> newVal
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token keyword">get</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">get name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_name
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
|
||
obj<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token function-variable function">set</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal<span class="token punctuation">,</span> receiver</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 设置 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newVal<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
Reflect<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> newVal<span class="token punctuation">,</span> receiver<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">get</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> receiver</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">监听: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 获取</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> Reflect<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> receiver<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>我们使用Proxy代理,并且使用Reflect操作对象时,输出的<code>this</code>仍然为<code>obj</code>,需要注意的是,此处的<code>this</code>指向是默认指向原始对象<code>obj</code>,而如果业务需要改变<code>this</code>指向,此时可以为<code>Reflect.set()</code>的最后一个参数传入<code>receiver</code></p> <h4 id="reflect-construct方法"><a href="#reflect-construct方法" class="header-anchor">#</a> Reflect.construct方法</h4> <p>以下两段代码的实现结果是一样的:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">Person</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">)</span> <span class="token comment">// 借用</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> stu <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Student</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>stu<span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// Person.call(this, name, age) // 借用</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> stu <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Reflect<span class="token punctuation">.</span>construct</span><span class="token punctuation">(</span>Person<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">]</span><span class="token punctuation">,</span> Student<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>stu<span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="理解proxy与reflect中的receiver参数"><a href="#理解proxy与reflect中的receiver参数" class="header-anchor">#</a> 理解Proxy与Reflect中的receiver参数</h3> <p><a href="https://juejin.cn/post/7085742282476879902" target="_blank" rel="noopener noreferrer">Proxy和Reflect中的receiver到底是个什么东西<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p><a href="https://juejin.cn/post/7050489628062646286" target="_blank" rel="noopener noreferrer">ES6的Proxy中,为什么推荐使用Reflect.get而不是target[key]?<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="promise详解"><a href="#promise详解" class="header-anchor">#</a> Promise详解</h2> <ul><li>异步代码的困境</li> <li>认识Promise</li> <li>Promise状态变化</li> <li>Promise实例方法</li> <li>Promise的类方法</li></ul> <h3 id="异步代码"><a href="#异步代码" class="header-anchor">#</a> 异步代码</h3> <p>ES5之前,都是通过回调函数完成异步逻辑代码的,如果存在多次异步操作,会导致回调函数不断嵌套,回调地狱</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token parameter">callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span>
|
||
<span class="token function">callback</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span>
|
||
div<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> res
|
||
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="认识promise"><a href="#认识promise" class="header-anchor">#</a> 认识Promise</h3> <p>用Promise改造上述代码:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
data<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span>
|
||
div<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> res
|
||
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><ul><li>通过new创建Promise对象时,需要传入一个回调函数,称之为executor
|
||
<ul><li>这个回调函数<strong>会被立即执行</strong>,并且传入另外两个回调函数 <code>resolve reject</code></li> <li>当我们调用<code>resolve</code>时,会执行Promise对象的then方法传入的回调函数</li> <li>当我们调用<code>reject</code>时,会执行Promise对象的catch方法传入的回调函数</li></ul></li></ul> <blockquote><p><code>.catch()</code> 其实只是没有给处理已兑现状态的回调函数预留参数位置的 <code>.then()</code> 而已。</p></blockquote> <h4 id="promise状态变化"><a href="#promise状态变化" class="header-anchor">#</a> Promise状态变化</h4> <ul><li>Promise有三种状态 只修改一次 后续状态将被锁定
|
||
<ul><li><code>pending</code> 初始状态 既没有被兑现,也没有被拒绝
|
||
<ul><li>执行executor中代码时,处于该状态</li></ul></li> <li><code>fulfilled</code> 操作已完成
|
||
<ul><li>执行resolve时,Promise已经被兑现</li></ul></li> <li><code>rejected</code> 操作失败
|
||
<ul><li>执行reject时,Promise已经被拒绝</li></ul></li></ul></li></ul> <h4 id="resolve值"><a href="#resolve值" class="header-anchor">#</a> resolve值</h4> <p>为<code>resolve</code>函数传入普通值,Promise的状态会被设置为兑现,而为<code>resolve</code>传入一个Promise对象时,当前Promise对象的状态将由传入的Promise对象决定。如下述代码中,<code>'Outer Promise Result'</code>会被作为最终结果被兑现</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'Outer Promise Result'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">function</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p><code>resolve</code>还可以传入<code>thenable</code>对象:该对象中的<code>then</code>方法会被回调</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">then</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'thenable Object resolve'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>综上:</p> <ul><li>如果resolve传入一个普通的值或对象,那么这个值会作为then回调的参数</li> <li>如果resolve中传入的是另一个Promise,那么这个新Promise会决定原Promise的状态</li> <li>如果resolve中传入的是一个对象,并且这个对象中实现了then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise 的状态</li></ul> <h4 id="then方法"><a href="#then方法" class="header-anchor">#</a> .then方法</h4> <p>实际上,then方法可以传入两个回调函数,可以同时传入成功处理的回调函数和失败处理的回调函数。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
data
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
|
||
<span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span>
|
||
div<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> res
|
||
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">)</span>
|
||
</code></pre></div><p>在前文中我们描述<code>.catch</code>为:</p> <blockquote><p><code>.catch()</code> 其实只是没有给处理已兑现状态的回调函数预留参数位置的 <code>.then()</code> 而已。</p></blockquote> <p>那么<code>.catch</code>的实现本质上就是为成功回调传入null的<code>.then</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
data
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>Promise的<code>.then</code>方法可以被多次调用,下例中,控制台只会输出一次<code>'execute'</code>而会输出三次<code>'success'</code>,证明三次<code>.then</code>都被调用了。同理,<code>.catch</code>方法也可以被多次调用</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'execute'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'success'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'success'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'success'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="then的返回值"><a href="#then的返回值" class="header-anchor">#</a> .then的返回值</h4> <p>Promise本身支持链式调用,<code>.then</code>方法实际上是返回了一个新的Promise,链式调用中的<code>.then</code>是在等待这个新的Promise兑现之后执行</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'aaa'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token string">'bbb'</span> <span class="token comment">// return new Promise((res) => res('bbb'))</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="catch的返回值"><a href="#catch的返回值" class="header-anchor">#</a> .catch的返回值</h4> <p>可以通过<code>throw</code>抛出一个错误实现在链式调用中抛出异常,让<code>.catch</code>对异常进行处理</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'aaa'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
p<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token string">'bbb'</span> <span class="token comment">// return new Promise((res) => res('bbb'))</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Error Info'</span><span class="token punctuation">)</span> <span class="token comment">// return new Promise((_, rej) => rej('Error Info'))</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="promise类方法"><a href="#promise类方法" class="header-anchor">#</a> Promise类方法</h3> <h4 id="promise-resolve"><a href="#promise-resolve" class="header-anchor">#</a> <code>Promise.resolve()</code></h4> <p>类方法与实例方法,下例中两个方式是等效的,其中<code>Promise.resolve()</code>即为类方法。如果你现在已经有了一个数据内容,希望通过Promise包装来使用,这时就可以通过<code>Promise.resolve()</code>方法</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
<span class="token comment">// 等价于</span>
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="promise-reject"><a href="#promise-reject" class="header-anchor">#</a> <code>Promise.reject()</code></h4> <p>与<code>resolve</code>方法类似,下述两种写法的效果是相同的</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
<span class="token comment">// 等价于</span>
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">_<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">rej</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="promise-all"><a href="#promise-all" class="header-anchor">#</a> <code>Promise.all()</code></h4> <blockquote><p><code>**Promise.all(iterable)**</code> 方法返回一个 <a href="/note/006949885979dbd292ab622df526fdf7.html"><code>Promise</code></a> 实例,此实例在 <code>iterable</code> 参数内所有的 <code>promise</code> 都“完成(resolved)”或参数中不包含 <code>promise</code> 时回调完成(resolve);如果参数中 <code>promise</code> 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 <code>promise</code> 的结果。</p></blockquote> <ul><li>将多个Promise包裹在一起形成一个新的Promise</li> <li>新的Promise状态由包裹的所有Promise共同决定
|
||
<ul><li><strong>当所有的Promise状态都变成fulfilled状态时</strong>,新的Promise状态为<code>fulfilled</code>,并且会将所有的Promise返回值组成一个数组</li> <li><strong>当有一个Promise状态为reject时</strong>,新的Promise状态为<code>reject</code>,并且会将第一个<code>reject</code>的返回值作为参数</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> p1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'data1'</span><span class="token punctuation">,</span> <span class="token string">'data2'</span><span class="token punctuation">,</span> <span class="token string">'data3'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> p2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'Hello, Promise.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> p3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">_<span class="token punctuation">,</span> rej</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">rej</span><span class="token punctuation">(</span><span class="token string">'Failed'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">const</span> promises <span class="token operator">=</span> <span class="token punctuation">[</span>p1<span class="token punctuation">,</span> p2<span class="token punctuation">,</span> p3<span class="token punctuation">]</span>
|
||
|
||
Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>promises<span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="promise-allsettled-es11"><a href="#promise-allsettled-es11" class="header-anchor">#</a> <code>Promise.allSettled()</code> (ES11)</h4> <p><code>.all()</code>方法有一个缺陷:当某一个Promise被reject时,新的Promise会立刻变成reject状态,此时对于其他处于resolved和pending状态的Promise就获取不到结果了</p> <ul><li>会在所有的Promise都有结果(settled) 无论是fulfilled 还是 rejected时,才会有最终的状态</li> <li><strong>这个Promise的结果一定是fulfilled的</strong></li> <li>返回的结果是一个数组,每个元素包含Promise的状态与结果</li></ul> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">allSettled</span><span class="token punctuation">(</span>promises<span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="promise-race"><a href="#promise-race" class="header-anchor">#</a> <code>Promise.race()</code></h4> <blockquote><p><strong><code>Promise.race(iterable)</code></strong> 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。</p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">race</span><span class="token punctuation">(</span>promises<span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="promise-any-es12"><a href="#promise-any-es12" class="header-anchor">#</a> <code>Promise.any()</code> (ES12)</h4> <ul><li>any方法是ES12新增的方法,与race类似
|
||
<ul><li>any方法会等到一个fulfilled状态,才会决定新的Promise状态</li> <li>如果所有Promise都是reject的,那么也会等到所有Promise都变成rejected状态</li> <li>(race方法一旦fulfilled或rejected会直接修改新的Promise状态)</li></ul></li></ul> <h2 id="迭代器与生成器"><a href="#迭代器与生成器" class="header-anchor">#</a> 迭代器与生成器</h2> <h3 id="异步处理"><a href="#异步处理" class="header-anchor">#</a> 异步处理</h3> <h4 id="请求代码结构"><a href="#请求代码结构" class="header-anchor">#</a> 请求代码结构</h4> <p>假设有如下场景:请求3的数据依赖请求2,请求2的数据依赖请求1,这样会存在嵌套的问题</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 第一次请求</span>
|
||
<span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 第二次请求</span>
|
||
<span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 第三次请求</span>
|
||
<span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziuc'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>可以通过Promise链式调用,避免深层嵌套回调,但是代码并不足够优秀</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res <span class="token operator">+</span> <span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res <span class="token operator">+</span> <span class="token string">'Ziuc'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>生成器写法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span><span class="token operator">*</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res1 <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res2 <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res1 <span class="token operator">+</span> <span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res3 <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res2 <span class="token operator">+</span> <span class="token string">'Ziuc'</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res3<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> generator <span class="token operator">=</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
generator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
generator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
generator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
generator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>通过递归优化生成器代码</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">execGenFn</span><span class="token punctuation">(</span><span class="token parameter">genFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> generator <span class="token operator">=</span> <span class="token function">genFn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">function</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> result <span class="token operator">=</span> generator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>result<span class="token punctuation">.</span>done<span class="token punctuation">)</span> <span class="token keyword">return</span>
|
||
<span class="token keyword">else</span> result<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">exec</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">execGenFn</span><span class="token punctuation">(</span>getData<span class="token punctuation">)</span>
|
||
</code></pre></div><p>此时引入<code>async</code>和<code>await</code>可以提高代码的阅读性,<strong>本质上就是生成器函数和<code>yeild</code>的语法糖</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res1 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res2 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res1 <span class="token operator">+</span> <span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res3 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span>res2 <span class="token operator">+</span> <span class="token string">'Ziuc'</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res3<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h2 id="await-async-事件循环"><a href="#await-async-事件循环" class="header-anchor">#</a> await async 事件循环</h2> <ul><li>async await</li> <li>浏览器进程 线程</li> <li>宏任务、微任务队列</li> <li>Promise面试题解析</li> <li>throw try catch</li> <li>浏览器存储Storage</li></ul> <h3 id="异步函数-async"><a href="#异步函数-async" class="header-anchor">#</a> 异步函数 async</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 普通函数</span>
|
||
<span class="token keyword">function</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">fun</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token comment">// 箭头函数</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">fun</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token comment">// 生成器函数</span>
|
||
<span class="token keyword">function</span><span class="token operator">*</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 异步函数写法</span>
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">fun</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">fun</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 默认包裹Promise</span>
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token string">'123'</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token comment">// Promise {<fulfilled>: '123'}</span>
|
||
|
||
res<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">r</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span> <span class="token comment">// '123'</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>异步函数的返回值默认会被包裹一层Promise。</p> <p>如果代码中抛出了错误,不会像普通函数一样报错,而是会在内部调用<code>reject(err)</code>将错误抛给<code>.catch</code>方法(如果有的话),否则会直接抛出</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Error Info'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> <span class="token string">'123'</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">r</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="await关键字"><a href="#await关键字" class="header-anchor">#</a> await关键字</h3> <ul><li>await关键字只能在异步函数中使用</li> <li>通常await后面跟上一个表达式,该表达式会返回一个Promise</li> <li>await会<strong>等到Promise的状态变为fulfilled状态</strong>,之后继续执行异步函数</li></ul> <p>会阻塞代码执行,与yeild类似</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token parameter">param</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> param
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> data1 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> data2 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> data3 <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziuc'</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data1<span class="token punctuation">,</span> data2<span class="token punctuation">,</span> data3<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>如果代码在await过程中出现异常,也可以通过<code>.catch</code>捕获到异常</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token parameter">param</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Error Info'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> param
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'ziu'</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token comment">// 捕获到异步函数内抛出的异常</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="进程与线程"><a href="#进程与线程" class="header-anchor">#</a> 进程与线程</h3> <ul><li>进程:计算机已经运行的程序,是操作系统管理程序的一种方式
|
||
<ul><li>启动一个应用程序时就会默认启动<strong>一个或多个进程</strong></li></ul></li> <li>线程:操作系统能够运行运算调度的最小单元,通常情况下它被包含在进程中
|
||
<ul><li><strong>每一个进程</strong>中,都会启动<strong>至少一个线程</strong>用来执行程序中的代码,这个线程被称之为<strong>主线程</strong></li> <li>可以认为进程是线程的容器</li></ul></li></ul> <p>操作系统可以同时让多个进程同时工作</p> <ul><li>CPU的运算速度很快,可以快速地在多个进程之间迅速地切换</li> <li>当进程中的线程获取到时间片时,就可以快速执行我们编写的代码</li> <li>用户是感受不到这种快速的切换的</li></ul> <h3 id="javascript线程"><a href="#javascript线程" class="header-anchor">#</a> JavaScript线程</h3> <p>JavaScript是单线程(可以开启Worker)的,但是JavaScript线程应该有自己的容器进程:浏览器或Node</p> <ul><li>浏览器是一个应用程序,是多进程的,每打开一个Tab页面就会开启一个新的进程:防止一个页面卡死导致浏览器崩溃</li> <li>每个进程都有很多的线程,其中就<strong>包括执行JavaScript代码的线程</strong></li> <li>JavaScript的代码执行是在一个单独的线程执行的
|
||
<ul><li>这意味着JavaScript的代码在同一个时刻只能做一件事</li> <li>如果某些任务非常消耗时间,当前线程就会被阻塞</li> <li>timer函数、onClick、ajax callback</li></ul></li></ul> <h4 id="settimeout"><a href="#settimeout" class="header-anchor">#</a> setTimeout</h4> <p>当函数执行到<code>setTimeout</code>时,会由浏览器单独的另一个线程负责计时,将这个定时器任务放到Event Table,计时完成后Event Table会将定时器的回调函数放入Event Queue,当主线程的代码执行完毕后,会去Event Queue中取出队头的任务放入主线程中执行</p> <p>这样的过程会不断重复,这也就是常说的Event Loop 事件循环</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'timeout'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="setinterval"><a href="#setinterval" class="header-anchor">#</a> setInterval</h4> <p><code>setInterval</code>与<code>setTimeout</code>类似,只不过<code>setInterval</code>会每隔将注册的回调函数放入Event Queue,如果前面的事件处理得太久也会出现延迟执行的问题,如果队列前面的事件阻塞的时间太长,那么后续队列中就连续被放入了多个<code>setInterval</code>的回调函数任务,这样就失去了定期执行的初衷。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'interval'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="onclick"><a href="#onclick" class="header-anchor">#</a> onClick</h4> <p>DOM监听时注册的回调函数也会作为异步任务进入事件循环中,每次点击都会将回调函数任务加入到Event Queue中。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span>
|
||
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'btn Clicked'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="微任务与宏任务"><a href="#微任务与宏任务" class="header-anchor">#</a> 微任务与宏任务</h3> <ul><li><p>宏任务队列<code>macrotask queue</code></p> <ul><li><code>ajax、setTimeout、setInterval、DOM监听、UI Rendering等</code></li></ul></li> <li><p>微任务<code>microtask queue</code></p> <ul><li><code>Promise的.then回调、Mutation Observer API、queueMicrotask()等</code></li></ul></li> <li><p>微任务和宏任务皆为异步任务,它们都属于一个队列,主要区别在于他们的执行顺序,Event Loop的走向和取值。</p></li> <li><p>主线程的代码先执行</p></li> <li><p>在执行任何一个宏任务之前,都会先查看微任务队列中是否有任务需要执行</p> <ul><li>宏任务执行之前,保证微任务队列是空的</li> <li>如果不为空,那么优先执行微任务队列中的任务(回调)</li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'timeout1'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'timeout2'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'promise'</span>
|
||
<span class="token string">'script end'</span>
|
||
<span class="token string">'then'</span>
|
||
<span class="token string">'timeout1'</span>
|
||
<span class="token string">'timeout2'</span>
|
||
</code></pre></div><p>Promise内的代码会直接在主线程中执行,而<code>.then</code>内的回调则会作为微任务进入微任务队列</p> <h3 id="事件循环-面试题"><a href="#事件循环-面试题" class="header-anchor">#</a> 事件循环 面试题</h3> <h4 id="面试题1"><a href="#面试题1" class="header-anchor">#</a> 面试题1</h4> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout1'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then4'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then2'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise1'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then1'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout2'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'2'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">queueMicrotask</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'queueMicrotask1'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then3'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'promise1'</span>
|
||
<span class="token string">'2'</span>
|
||
<span class="token string">'script end'</span>
|
||
<span class="token string">'then1'</span>
|
||
<span class="token string">'queueMicrotask1'</span>
|
||
<span class="token string">'then3'</span>
|
||
<span class="token string">'setTimeout1'</span>
|
||
<span class="token string">'then2'</span>
|
||
<span class="token string">'then4'</span>
|
||
<span class="token string">'setTimeout2'</span>
|
||
</code></pre></div><ul><li>主线程 <code>script start</code> <code>promise1</code> <code>2</code> <code>script end</code></li> <li>宏任务 <code>setTimeout1</code> <code>setTimeout2</code></li> <li>微任务 <code>then1</code> <code>queueMicrotask1</code> <code>then3</code></li></ul> <p>先开始执行微任务队列,微任务队列执行完毕清空后,开始<code>setTimeout1</code>宏任务</p> <ul><li><code>setTimeout1</code> 宏任务开始,<code>then4</code>进入微任务队列,<code>then2</code>直接执行</li> <li><code>setTimeout1</code> 宏任务结束,微任务队列非空,执行<code>then4</code>,清空微任务队列</li> <li><code>setTimeout2</code> 宏任务开始,执行完毕</li></ul> <h4 id="await的使用"><a href="#await的使用" class="header-anchor">#</a> await的使用</h4> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token parameter">param</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span>param<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData end'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'getData start'</span>
|
||
<span class="token string">'getData end'</span>
|
||
<span class="token string">'script end'</span>
|
||
<span class="token string">'setTimeout'</span>
|
||
<span class="token string">'res Ziu'</span>
|
||
</code></pre></div><ul><li>主线程 <code>script start</code> <code>getData start</code> <code>getData end</code> <code>script end</code></li></ul> <p>主线程运行过程中,执行到<code>getData start</code>后的<code>Promise</code>时,其中代码在主线程中进行</p> <p>遇到<code>setTimeout</code>,放入Event Table由浏览器开始计时,计时2s结束后,将回调函数放入宏任务队列中执行<code>setTimeout</code></p> <p><code>setTimeout</code>执行完毕,<code>res(param)</code>执行后,返回的Promise成功<code>resolved</code>,将<code>.then</code>回调函数放入微任务队列并开始执行</p> <p>微任务<code>.then</code>执行完毕输出<code>res</code> 代码执行结束</p> <h4 id="改用await实现微任务"><a href="#改用await实现微任务" class="header-anchor">#</a> 改用await实现微任务</h4> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token parameter">param</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span>param<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData end'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>改写上述面试题2,将res部分代码改为使用<code>await</code>,这里的代码输出为:</p> <div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'getData start'</span>
|
||
<span class="token string">'script end'</span>
|
||
<span class="token string">'setTimeout'</span>
|
||
<span class="token string">'res Ziu'</span>
|
||
<span class="token string">'getData end'</span>
|
||
</code></pre></div><p><strong><code>await</code>后续的代码,实质上就是一个微任务,这些代码不在主线程中被执行,而是被放入微任务队列:</strong></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/* 使用await */</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData end'</span><span class="token punctuation">)</span>
|
||
<span class="token comment">/* 不使用await */</span>
|
||
<span class="token function">reqData</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'getData end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>这样就会出现:先<code>script end</code>,后<code>setTimeout, res Ziu, getData end</code>的情况</p> <h4 id="面试题2"><a href="#面试题2" class="header-anchor">#</a> 面试题2</h4> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 start'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">await</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 end'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async2'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise1'</span><span class="token punctuation">)</span>
|
||
<span class="token function">res</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise2'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
|
||
</code></pre></div><div class="language-sh extra-class"><pre class="language-sh"><code><span class="token string">'script start'</span>
|
||
<span class="token string">'async1 start'</span>
|
||
<span class="token string">'async2'</span>
|
||
<span class="token string">'promise1'</span>
|
||
<span class="token string">'script end'</span>
|
||
<span class="token string">'async1 end'</span>
|
||
<span class="token string">'promise2'</span>
|
||
<span class="token string">'setTimeout'</span>
|
||
</code></pre></div><p><code>await</code>前的代码是跟随之前代码的执行顺序执行的,而其后的代码会被放入微任务队列中延迟执行</p> <h3 id="node事件循环"><a href="#node事件循环" class="header-anchor">#</a> Node事件循环</h3> <p>TODO</p> <h2 id="防抖与节流"><a href="#防抖与节流" class="header-anchor">#</a> 防抖与节流</h2> <ul><li>认识防抖与节流</li> <li>underscore使用</li> <li>防抖函数实现优化</li> <li>节流函数实现优化</li> <li>深拷贝函数的实现</li> <li>事件总线工具实现</li></ul> <h3 id="防抖函数"><a href="#防抖函数" class="header-anchor">#</a> 防抖函数</h3> <p>降低高频操作的发生频次,如输入框防抖</p> <ul><li>当事件触发时,相应的函数不会立即触发,而是会等待一定的时间</li> <li>当事件密集触发时,函数的触发会被频繁的推迟</li> <li>只有等待了一段时间也没有事件触发,才会真正的执行响应函数</li></ul> <p>防抖的应用场景</p> <ul><li>输入框中频繁输入内容</li> <li>频繁的点击按钮</li> <li>监听浏览器的滚动事件</li> <li>用户缩放浏览器的resize事件</li></ul> <h4 id="基本实现"><a href="#基本实现" class="header-anchor">#</a> 基本实现</h4> <ul><li>入参:函数、防抖时间</li> <li>返回值:一个新的函数</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> timeout</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_debounce</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token comment">// 高频调用 清理上次调用的timer</span>
|
||
<span class="token comment">// 创建本次调用的timer</span>
|
||
timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// 执行回调 清理此次调用的timer</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _debounce
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span>
|
||
input<span class="token punctuation">.</span>oninput <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h4 id="优化-绑定this-传入参数"><a href="#优化-绑定this-传入参数" class="header-anchor">#</a> 优化 绑定this 传入参数</h4> <p>此时并没有绑定<code>this</code>,无法通过<code>this.value</code>获取到当前输入框内的值,现在要将返回的函数<code>_debounce</code>绑定给<code>input</code></p> <p>以DOM事件绑定的函数为例,事件触发回调的入参会有参数<code>event</code>可供使用</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> timeout</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_debounce</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token comment">// 高频调用 清理上次调用的timer</span>
|
||
<span class="token comment">// 创建本次调用的timer</span>
|
||
timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// 执行回调 清理此次调用的timer</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _debounce
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span>
|
||
input<span class="token punctuation">.</span>oninput <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">,</span> event<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
|
||
</code></pre></div><p>需要注意的是:在箭头函数中没有<code>this</code>,会直接去上层作用域找<code>this</code>,直到找到<code>function</code>定义的函数。</p> <h4 id="优化-取消功能"><a href="#优化-取消功能" class="header-anchor">#</a> 优化 取消功能</h4> <p>如果用户输入过程中执行了页面跳转,旧的防抖函数需要被取消</p> <p>给<code>_debounce</code>绑定一个取消的函数<code>cancel()</code>,执行后如果有timer,则清理此timer</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> timeout</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_debounce</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token comment">// 高频调用 清理上次调用的timer</span>
|
||
<span class="token comment">// 创建本次调用的timer</span>
|
||
timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// 执行回调 清理此次调用的timer</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
_debounce<span class="token punctuation">.</span><span class="token function-variable function">cancel</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _debounce
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> callback <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">,</span> event<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
||
input<span class="token punctuation">.</span>oninput <span class="token operator">=</span> callback
|
||
|
||
<span class="token keyword">const</span> <span class="token function-variable function">cancel</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'debounce canceled'</span><span class="token punctuation">)</span>
|
||
callback<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="优化-立即执行功能"><a href="#优化-立即执行功能" class="header-anchor">#</a> 优化 立即执行功能</h4> <p>第一次触发时立即执行,后续时才防抖(默认为<code>false</code>)</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> timeout<span class="token punctuation">,</span> immediate <span class="token operator">=</span> <span class="token boolean">false</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token keyword">let</span> isInvoke <span class="token operator">=</span> <span class="token boolean">false</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_debounce</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token comment">// 高频调用 清理上次调用的timer</span>
|
||
|
||
<span class="token comment">// 需要立即执行 并且是第一次执行 立即执行回调</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>immediate <span class="token operator">&&</span> <span class="token operator">!</span>isInvoke<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
isInvoke <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token comment">// 标记已经执行过</span>
|
||
<span class="token keyword">return</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 创建本次调用的timer</span>
|
||
timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// 执行回调 清理此次调用的timer</span>
|
||
isInvoke <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token comment">// 恢复初始状态</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
_debounce<span class="token punctuation">.</span><span class="token function-variable function">cancel</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
isInvoke <span class="token operator">=</span> <span class="token boolean">false</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _debounce
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="优化-获取返回值"><a href="#优化-获取返回值" class="header-anchor">#</a> 优化 获取返回值</h4> <p>在某些场景下,我们希望获取防抖函数中回调的返回值</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> myDebounce <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>height<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
<span class="token keyword">return</span> res
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 三次调用只会执行最后一次</span>
|
||
<span class="token keyword">const</span> res1 <span class="token operator">=</span> <span class="token function">myDebounce</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res2 <span class="token operator">=</span> <span class="token function">myDebounce</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> res3 <span class="token operator">=</span> <span class="token function">myDebounce</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res1<span class="token punctuation">,</span> res2<span class="token punctuation">,</span> res3<span class="token punctuation">)</span> <span class="token comment">// undefined undefined undefined</span>
|
||
</code></pre></div><p>可以将<code>callback</code>的返回值用Promise返回,后续有结果直接通过<code>.then</code>即可获取到返回值,同时通过<code>try-catch</code>包裹,抛出代码执行错误</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> timeout<span class="token punctuation">,</span> immediate <span class="token operator">=</span> <span class="token boolean">false</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
|
||
<span class="token keyword">let</span> isInvoke <span class="token operator">=</span> <span class="token boolean">false</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_debounce</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token comment">// 高频调用 清理上次调用的timer</span>
|
||
<span class="token comment">// 需要立即执行 并且是第一次执行 立即执行回调</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>immediate <span class="token operator">&&</span> <span class="token operator">!</span>isInvoke<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
isInvoke <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token comment">// 标记已经执行过</span>
|
||
<span class="token keyword">return</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 创建本次调用的timer</span>
|
||
timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
<span class="token function">resolve</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
|
||
timer <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// 执行回调 清理此次调用的timer</span>
|
||
isInvoke <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token comment">// 恢复初始状态</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _debounce
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> myDebounce <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>height<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
|
||
<span class="token keyword">return</span> res
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token function">myDebounce</span><span class="token punctuation">(</span><span class="token string">'Ziu'</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">1.88</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token comment">// Ziu 18 1.88</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="节流函数"><a href="#节流函数" class="header-anchor">#</a> 节流函数</h3> <h4 id="基本实现-2"><a href="#基本实现-2" class="header-anchor">#</a> 基本实现</h4> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> interval</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> startTime <span class="token operator">=</span> <span class="token number">0</span> <span class="token comment">// 开始时间</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_throttle</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> nowTime <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 当前时间</span>
|
||
<span class="token keyword">const</span> waitTime <span class="token operator">=</span> interval <span class="token operator">-</span> <span class="token punctuation">(</span>nowTime <span class="token operator">-</span> startTime<span class="token punctuation">)</span> <span class="token comment">// 需要等待的时间</span>
|
||
<span class="token comment">// 结束等待 调用函数</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>waitTime <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
startTime <span class="token operator">=</span> nowTime <span class="token comment">// 重置开始时间 准备下一次调用</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _throttle
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> callback <span class="token operator">=</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">,</span> event<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span>
|
||
input<span class="token punctuation">.</span>oninput <span class="token operator">=</span> callback
|
||
</code></pre></div><h4 id="立即执行"><a href="#立即执行" class="header-anchor">#</a> 立即执行</h4> <p>一般情况下需要立即执行,也是默认状态。当需要取消第一次输入时的立即执行时,可以令<code>startTime</code>与<code>nowTime</code>相等,这样<code>_throttle</code>第一次触发时,计算出来的<code>waitTime</code>值就为<code>interval</code>的值,也就是等待一个间隔的时间再执行。</p> <p>需要注意的是触发条件为<code>!immediate && startTime ===0</code>同时满足,默认立即执行,只有同时满足<code>startTime === 0</code>即第一次触发函数时才会设置<code>startTime = nowTime</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> interval<span class="token punctuation">,</span> immediate <span class="token operator">=</span> <span class="token boolean">true</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> startTime <span class="token operator">=</span> <span class="token number">0</span> <span class="token comment">// 开始时间</span>
|
||
<span class="token keyword">const</span> <span class="token function-variable function">_throttle</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> nowTime <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 当前时间</span>
|
||
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>immediate <span class="token operator">&&</span> startTime <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
startTime <span class="token operator">=</span> nowTime
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> waitTime <span class="token operator">=</span> interval <span class="token operator">-</span> <span class="token punctuation">(</span>nowTime <span class="token operator">-</span> startTime<span class="token punctuation">)</span> <span class="token comment">// 需要等待的时间</span>
|
||
<span class="token comment">// 结束等待 调用函数</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>waitTime <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span>
|
||
startTime <span class="token operator">=</span> nowTime <span class="token comment">// 重置开始时间 准备下一次调用</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> _throttle
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">const</span> callback <span class="token operator">=</span> <span class="token function">throttle</span><span class="token punctuation">(</span>
|
||
<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">,</span> event<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token number">2000</span><span class="token punctuation">,</span>
|
||
<span class="token boolean">false</span>
|
||
<span class="token punctuation">)</span>
|
||
input<span class="token punctuation">.</span>oninput <span class="token operator">=</span> callback
|
||
</code></pre></div><h2 id="深拷贝与浅拷贝"><a href="#深拷贝与浅拷贝" class="header-anchor">#</a> 深拷贝与浅拷贝</h2> <p>对象属于引用类型,如果单纯复制</p> <h3 id="浅拷贝"><a href="#浅拷贝" class="header-anchor">#</a> 浅拷贝</h3> <ul><li>直接引用赋值
|
||
<ul><li>两个对象仍然共用一块内存</li></ul></li> <li>浅拷贝
|
||
<ul><li>解构创建一个新对象</li> <li><code>Object.assign(target, source)</code></li></ul></li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj1 <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">friend</span><span class="token operator">:</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'kobe'</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 1. 引用赋值</span>
|
||
<span class="token comment">// 修改obj2会影响原数据</span>
|
||
<span class="token keyword">const</span> obj2 <span class="token operator">=</span> obj1
|
||
obj2<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziu'</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj1<span class="token punctuation">,</span> obj2<span class="token punctuation">)</span>
|
||
|
||
<span class="token comment">// 2. 浅拷贝</span>
|
||
<span class="token comment">// 修改基本数据类型不会影响原对象</span>
|
||
<span class="token comment">// 但是引用类型数据仍然是原对象的引用</span>
|
||
<span class="token keyword">const</span> obj3 <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">...</span>obj1 <span class="token punctuation">}</span> <span class="token comment">// Object.assign({}, obj1)</span>
|
||
obj3<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Ziuc'</span>
|
||
obj3<span class="token punctuation">.</span>friend<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'james'</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj1<span class="token punctuation">,</span> obj3<span class="token punctuation">)</span>
|
||
</code></pre></div><h3 id="深拷贝"><a href="#深拷贝" class="header-anchor">#</a> 深拷贝</h3> <ul><li><code>JSON.stringify()</code> <code>JSON.parse()</code> <ul><li>性能较差 对<code>function</code> <code>Symbol</code>无能为力(只能解析标准JSON格式 其他内容默认会被忽略)</li> <li>局限性较大</li></ul></li> <li>实现深拷贝函数(第三方库)</li></ul> <h4 id="基本实现-3"><a href="#基本实现-3" class="header-anchor">#</a> 基本实现</h4> <p>封装函数<code>isObject</code>判断传入变量是否为对象类型</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">isObject</span><span class="token punctuation">(</span><span class="token parameter">variable</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// null | object | array -> object</span>
|
||
<span class="token comment">// function -> function</span>
|
||
<span class="token keyword">const</span> type <span class="token operator">=</span> <span class="token keyword">typeof</span> variable
|
||
<span class="token keyword">return</span> variable <span class="token operator">!==</span> <span class="token keyword">null</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">||</span> type <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isObject</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isObject</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isObject</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isObject</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false</span>
|
||
</code></pre></div><p>通过递归实现基本的<code>deepCopy</code>函数,可以深拷贝嵌套对象</p> <p>传入的对象如果包含数组,通过 <code>Array.isArray()</code> <code>.toString()</code> 等方法对数据类型进行具体的判断</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span><span class="token parameter">originValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 递归的值非对象 直接返回其本身</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isObject</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> originValue
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">const</span> target <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// 判断原始值是数组还是对象</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">in</span> originValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 递归调用deepCopy 实时创建新对象</span>
|
||
target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>originValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> target
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="支持set"><a href="#支持set" class="header-anchor">#</a> 支持Set</h4> <p>此时的代码,如果原始对象包含<code>Set()</code>,他也会被当做<code>Object</code>处理,但是需要注意的是:</p> <ul><li><code>Set()</code>不支持 <code>for-in</code> 遍历</li> <li><code>Set()</code>只支持 <code>for-of</code> 遍历</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 处理Set</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>originValue <span class="token keyword">instanceof</span> <span class="token class-name">Set</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> item <span class="token keyword">of</span> originValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
|
||
set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token function">deepCopy</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> set
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="支持函数"><a href="#支持函数" class="header-anchor">#</a> 支持函数</h4> <p>一般情况下是不需要深拷贝函数的,对性能有较大的影响,当然,如果一定要支持深拷贝函数,只需要对函数做一次判断即可</p> <p>直接返回其本身,这样两个函数都是同一片内存空间的引用,不必重新开辟新的内存空间</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 处理Function</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> originValue <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> originValue
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="支持symbol作为值"><a href="#支持symbol作为值" class="header-anchor">#</a> 支持Symbol作为值</h4> <p><code>typeof Symbol()</code> 返回的是 <code>'symbol'</code>,同时需要考虑到如果<code>Symbol()</code>传入了<code>description</code>的情况</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 处理Symbol</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> originValue <span class="token operator">===</span> <span class="token string">'symbol'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token function">Symbol</span><span class="token punctuation">(</span>originValue<span class="token punctuation">.</span>description<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><h4 id="支持symbol作为键"><a href="#支持symbol作为键" class="header-anchor">#</a> 支持Symbol作为键</h4> <p>当<code>Symbol</code>作为键在执行<code>for-in</code>时不会被遍历得到,以下是MDN对<code>for-in</code>的说明:</p> <blockquote><p><strong><code>for...in</code></strong> <strong>语句</strong>以任意顺序迭代一个对象的除<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol" target="_blank" rel="noopener noreferrer">Symbol<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>以外的<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties" target="_blank" rel="noopener noreferrer">可枚举<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>属性,包括继承的可枚举属性。</p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 遍历对象中的Symbol键</span>
|
||
<span class="token keyword">const</span> symbolKeys <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertySymbols</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> symbol <span class="token keyword">of</span> symbolKeys<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
target<span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span>symbol<span class="token punctuation">.</span>description<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>originValue<span class="token punctuation">[</span>symbol<span class="token punctuation">]</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
</code></pre></div><p>使用<code>Object.getOwnPropertySymbols()</code>方法获取所有键名类型为<code>Symbol</code>的<code>Symbo</code>对象并遍历,逐个向新的深拷贝对象中添加对应<code>description</code>的新的<code>Symbol</code>键值对</p> <h4 id="支持循环引用"><a href="#支持循环引用" class="header-anchor">#</a> 支持循环引用</h4> <p>循环引用:在使用<code>JSON.stringify</code>对包含循环引用的对象进行转化时会报错</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Object'</span>
|
||
<span class="token punctuation">}</span>
|
||
obj<span class="token punctuation">.</span>self <span class="token operator">=</span> obj
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj <span class="token operator">===</span> obj<span class="token punctuation">.</span>self<span class="token punctuation">)</span> <span class="token comment">// true</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>self<span class="token punctuation">.</span>self<span class="token punctuation">.</span>self<span class="token punctuation">.</span>self<span class="token punctuation">.</span>self<span class="token punctuation">.</span>self<span class="token punctuation">)</span> <span class="token comment">// obj</span>
|
||
</code></pre></div><p>如果使用我们之前编写的<code>deepCopy</code>拷贝一个包含循环引用的对象,会出现函数执行栈溢出的问题,这是因为<code>target[key] = deepCopy(originValue[key])</code>不会跳出而是会一直递归,最终导致栈溢出</p> <p>可以为增加一个默认入参,每次调用<code>deepCopy</code>时为其传入一个<code>Map</code>,其中保存着拷贝出来的新对象的引用,在调用<code>deepCopy</code>时对此<code>Map</code>进行判断,如果其中已经包含了拷贝出来的新对象则直接取值并赋给当前的key,不再重新拷贝</p> <p>每次执行完深拷贝需要对这个<code>Map</code>中保存的对象进行删除操作,如果通过<code>map = null</code>销毁此<code>map</code>,由于<code>Map</code>是强引用,里面保存的对象在内存中并不会被真正销毁。可以使用<code>WeakMap</code>替换,<code>WeakMap</code>中的引用是弱引用,如果引用的原始对象被销毁,能保证其引用的对象也被销毁</p> <h3 id="完整代码"><a href="#完整代码" class="header-anchor">#</a> 完整代码</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">isObject</span><span class="token punctuation">(</span><span class="token parameter">variable</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// null | object | array -> object</span>
|
||
<span class="token comment">// function -> function</span>
|
||
<span class="token keyword">const</span> type <span class="token operator">=</span> <span class="token keyword">typeof</span> variable
|
||
<span class="token keyword">return</span> variable <span class="token operator">!==</span> <span class="token keyword">null</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">||</span> type <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">function</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>originValue<span class="token punctuation">,</span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeakMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 处理Symbol</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> originValue <span class="token operator">===</span> <span class="token string">'symbol'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> <span class="token function">Symbol</span><span class="token punctuation">(</span>originValue<span class="token punctuation">.</span>description<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 递归的值非对象 直接返回其本身</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isObject</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> originValue
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 处理Set</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>originValue <span class="token keyword">instanceof</span> <span class="token class-name">Set</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> item <span class="token keyword">of</span> originValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
|
||
set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token function">deepCopy</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token keyword">return</span> set
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 处理Function</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> originValue <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> originValue
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 如果存在引用循环 且上次已经设置过引用 则跳出递归</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">return</span> map<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 如果是对象/数组类型 需要创建新的对象/数组</span>
|
||
<span class="token keyword">const</span> target <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// 判断原始值是数组还是对象</span>
|
||
map<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>originValue<span class="token punctuation">,</span> target<span class="token punctuation">)</span> <span class="token comment">// 将新对象自身保存到WeakMap中</span>
|
||
|
||
<span class="token comment">// 遍历当前对象中所有普通的key</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">in</span> originValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 递归调用deepCopy 实时创建新对象</span>
|
||
target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>originValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">,</span> map<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 遍历对象中的Symbol键</span>
|
||
<span class="token keyword">const</span> symbolKeys <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertySymbols</span><span class="token punctuation">(</span>originValue<span class="token punctuation">)</span>
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> symbol <span class="token keyword">of</span> symbolKeys<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
target<span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span>symbol<span class="token punctuation">.</span>description<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>originValue<span class="token punctuation">[</span>symbol<span class="token punctuation">]</span><span class="token punctuation">,</span> map<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">return</span> target
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">friend</span><span class="token operator">:</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'kobe'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">address</span><span class="token operator">:</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'洛杉矶'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">detail</span><span class="token operator">:</span> <span class="token string">'斯坦普斯中心'</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">array</span><span class="token operator">:</span> <span class="token punctuation">[</span>
|
||
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'JavaScript权威指南'</span><span class="token punctuation">,</span> <span class="token literal-property property">price</span><span class="token operator">:</span> <span class="token number">99</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'JavaScript高级程序设计'</span><span class="token punctuation">,</span> <span class="token literal-property property">price</span><span class="token operator">:</span> <span class="token number">66</span> <span class="token punctuation">}</span>
|
||
<span class="token punctuation">]</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">set</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'abc'</span><span class="token punctuation">,</span> <span class="token string">'cba'</span><span class="token punctuation">,</span> <span class="token string">'nba'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
||
<span class="token function-variable function">func</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello, deepCopy'</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'abc'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'Hello, Symbol Key.'</span><span class="token punctuation">,</span>
|
||
<span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'cba'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'Hello, Symbol Key.'</span>
|
||
<span class="token punctuation">}</span>
|
||
obj<span class="token punctuation">.</span>self <span class="token operator">=</span> obj
|
||
|
||
<span class="token keyword">const</span> newObj <span class="token operator">=</span> <span class="token function">deepCopy</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newObj<span class="token punctuation">)</span>
|
||
</code></pre></div><h2 id="事件总线"><a href="#事件总线" class="header-anchor">#</a> 事件总线</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">ZiuEventBus</span> <span class="token punctuation">{</span>
|
||
<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>eventMap <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">on</span><span class="token punctuation">(</span><span class="token parameter">eventName<span class="token punctuation">,</span> eventFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 获取保存事件回调的数组</span>
|
||
<span class="token keyword">let</span> eventFns <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>eventMap<span class="token punctuation">[</span>eventName<span class="token punctuation">]</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>eventFns<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
eventFns <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
|
||
<span class="token keyword">this</span><span class="token punctuation">.</span>eventMap<span class="token punctuation">[</span>eventName<span class="token punctuation">]</span> <span class="token operator">=</span> eventFns <span class="token comment">// 一个事件名可以同时注册多个回调函数</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token comment">// 将当前回调存入数组</span>
|
||
eventFns<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>eventFn<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">off</span><span class="token punctuation">(</span><span class="token parameter">eventName<span class="token punctuation">,</span> eventFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> eventFns <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>eventMap<span class="token punctuation">[</span>eventName<span class="token punctuation">]</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>eventFns<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token comment">// 如果没有注册过事件回调 直接返回</span>
|
||
|
||
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> eventFns<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">const</span> fn <span class="token operator">=</span> eventFns<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
|
||
|
||
<span class="token comment">// 是同一个函数引用</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span>fn <span class="token operator">===</span> eventFn<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
eventFns<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>
|
||
<span class="token keyword">break</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token function">emit</span><span class="token punctuation">(</span><span class="token parameter">eventName<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
||
<span class="token keyword">let</span> eventFns <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>eventMap<span class="token punctuation">[</span>eventName<span class="token punctuation">]</span>
|
||
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>eventFns<span class="token punctuation">)</span> <span class="token keyword">return</span>
|
||
eventFns<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token keyword">const</span> eventBus <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZiuEventBus</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">const</span> <span class="token function-variable function">callBack</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">payload</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'navClick'</span><span class="token punctuation">,</span> payload<span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 支持为同一事件注册多个回调</span>
|
||
eventBus<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'navClick'</span><span class="token punctuation">,</span> callBack<span class="token punctuation">)</span>
|
||
eventBus<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'navClick'</span><span class="token punctuation">,</span> callBack<span class="token punctuation">)</span>
|
||
|
||
<span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span>
|
||
btn<span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
<span class="token comment">// 手动触发事件回调</span>
|
||
eventBus<span class="token punctuation">.</span><span class="token function">emit</span><span class="token punctuation">(</span><span class="token string">'navClick'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
|
||
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ziu'</span><span class="token punctuation">,</span>
|
||
<span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
||
<span class="token punctuation">}</span>
|
||
|
||
<span class="token comment">// 支持移除回调</span>
|
||
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
||
eventBus<span class="token punctuation">.</span><span class="token function">off</span><span class="token punctuation">(</span><span class="token string">'navClick'</span><span class="token punctuation">,</span> callBack<span class="token punctuation">)</span> <span class="token comment">// 移除某个事件的某次回调</span>
|
||
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">5000</span><span class="token punctuation">)</span>
|
||
</code></pre></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated:</span> <span class="time">1/1/2023, 8:51:13 AM</span></div></footer> <!----> </main></div><div class="global-ui"><!----></div></div>
|
||
<script src="/assets/js/app.292c8404.js" defer></script><script src="/assets/js/2.1a074358.js" defer></script><script src="/assets/js/15.12230d80.js" defer></script>
|
||
</body>
|
||
</html>
|