{"componentChunkName":"component---src-templates-blog-post-js","path":"/object-assign/","result":{"data":{"site":{"siteMetadata":{"title":"😏","author":"thoamsy"}},"markdownRemark":{"id":"937f45aa-f670-598f-b33e-ac3a7bf56086","html":"<p>在 <em>immutable struct</em> 或者说 <em>functional programming</em> 的影响下, <code class=\"language-text\">Object.assign</code> 和 <a href=\"https://github.com/tc39/proposal-object-rest-spread\">Object Spread</a> 是我们离不开的操作. 不过它的功能真的是 <em>shadow copy</em> 吗? 这里我列出一个例子来记录这个问题, 以防以后碰到坑.</p>\n<p>下面是一个对象, 包括了几种典型的属性:</p>\n<ol>\n<li>普通属性</li>\n<li>get 属性</li>\n<li>set 属性</li>\n<li>Symbol</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> obj <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  a<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">get</span> <span class=\"token function\">hh</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__GETTER__'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a <span class=\"token operator\">+=</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">set</span> <span class=\"token function\">hh</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">val</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__SETTER__'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a <span class=\"token operator\">+=</span> val <span class=\"token operator\">*</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">[</span><span class=\"token function\">Symbol</span><span class=\"token punctuation\">(</span><span class=\"token string\">'cool'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token string\">'good'</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>先提出问题, 哪种类型的属性会被成功 copy? <code class=\"language-text\">get 和 set</code> 时候会被运行呢?</p>\n<p>首先可以确定的是, 连续两次打印 <code class=\"language-text\">obj.hh</code> 的话, 一定会得到 <code class=\"language-text\">2, 3</code>. 因为每次 <code class=\"language-text\">hh</code> 都会被运行对吧.</p>\n<p>OK, 现在开始对它 <code class=\"language-text\">assign</code>, 有下面代码</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> shadow <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>obj <span class=\"token punctuation\">}</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>shadow<span class=\"token punctuation\">.</span>hh<span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>shadow<span class=\"token punctuation\">.</span>hh<span class=\"token punctuation\">)</span></code></pre></div>\n<p>这个时候得到的值是多少呢(假设这串代码紧接上面的代码)\n最后的结果是 <code class=\"language-text\">4, 4</code>\n这说明 GET 只被运行了一次后, 就再也没有运行了.\n那我们打印一下 shadow 的内部看看,</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">Object<span class=\"token punctuation\">.</span><span class=\"token function\">getOwnPropertyDescriptors</span><span class=\"token punctuation\">(</span>shadow<span class=\"token punctuation\">)</span></code></pre></div>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/b0dd709a206bcde06de0b0ffc0157ef2/9685e/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27.500000000000004%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'110\\'%3e%3cpath%20d=\\'M0%205v5h5l5%201-5%201c-4%200-5%200-5%202s0%202%201%201c2-1%203%204%202%205H2l-1-1-1%204c0%203%200%204%201%203%201-2%202-1%202%202l-1%202c-2%200-2%201-2%204s0%204%201%203c1-3%201-2%202%202%200%204%200%204-2%203-1-2-1%202-1%2033v35h401V0H0v5\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          data-srcset=\"/static/b0dd709a206bcde06de0b0ffc0157ef2/ba381/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.webp 200w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/7f61c/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.webp 400w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/d00b9/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.webp 800w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/92f8c/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.webp 1200w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/7fa3c/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.webp 1336w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/b0dd709a206bcde06de0b0ffc0157ef2/772e8/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png 200w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/e17e5/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png 400w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/5a190/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png 800w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/c1b63/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png 1200w,\n/static/b0dd709a206bcde06de0b0ffc0157ef2/9685e/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png 1336w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image lazyload\"\n          data-src=\"/static/b0dd709a206bcde06de0b0ffc0157ef2/5a190/06FE5C2C-8A1B-45EE-B45D-D3DB0774F9FA.png\"\n          alt=\"06FE5C2C 8A1B 45EE B45D D3DB0774F9FA\"\n          title=\"06FE5C2C 8A1B 45EE B45D D3DB0774F9FA\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span></p>\n<p>注意到, 这个时候 hh 只是一个普通的属性, 而不再属于 get set. 作为对比, 我们看下 obj 会输出什么.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/73ccd330d70754382a3ed1d85ee766e1/9f9a4/336C40D7-A962-48C0-B485-B81EDD28B4EA.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'107\\'%3e%3cpath%20d=\\'M0%2053v54h401V0H0v53m0%201v54l1-50A570%20570%200%20012%201H0v53\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          data-srcset=\"/static/73ccd330d70754382a3ed1d85ee766e1/ba381/336C40D7-A962-48C0-B485-B81EDD28B4EA.webp 200w,\n/static/73ccd330d70754382a3ed1d85ee766e1/7f61c/336C40D7-A962-48C0-B485-B81EDD28B4EA.webp 400w,\n/static/73ccd330d70754382a3ed1d85ee766e1/d00b9/336C40D7-A962-48C0-B485-B81EDD28B4EA.webp 800w,\n/static/73ccd330d70754382a3ed1d85ee766e1/92f8c/336C40D7-A962-48C0-B485-B81EDD28B4EA.webp 1200w,\n/static/73ccd330d70754382a3ed1d85ee766e1/9fbc2/336C40D7-A962-48C0-B485-B81EDD28B4EA.webp 1560w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/73ccd330d70754382a3ed1d85ee766e1/772e8/336C40D7-A962-48C0-B485-B81EDD28B4EA.png 200w,\n/static/73ccd330d70754382a3ed1d85ee766e1/e17e5/336C40D7-A962-48C0-B485-B81EDD28B4EA.png 400w,\n/static/73ccd330d70754382a3ed1d85ee766e1/5a190/336C40D7-A962-48C0-B485-B81EDD28B4EA.png 800w,\n/static/73ccd330d70754382a3ed1d85ee766e1/c1b63/336C40D7-A962-48C0-B485-B81EDD28B4EA.png 1200w,\n/static/73ccd330d70754382a3ed1d85ee766e1/9f9a4/336C40D7-A962-48C0-B485-B81EDD28B4EA.png 1560w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image lazyload\"\n          data-src=\"/static/73ccd330d70754382a3ed1d85ee766e1/5a190/336C40D7-A962-48C0-B485-B81EDD28B4EA.png\"\n          alt=\"336C40D7 A962 48C0 B485 B81EDD28B4EA\"\n          title=\"336C40D7 A962 48C0 B485 B81EDD28B4EA\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span></p>\n<p>所以结论就是, 普通属性和 Symbol 会被 Copy. 至于 Symbol 时候还是原来那个, 自己测试一下可以发现肯定是的.</p>\n<p>那么, 另外一个问题. 这些 GET 和 SET 是在什么情况下被执行的呢? 我们可以看到, 上面只打印出了 <strong><em>GETTER</em></strong> 而没有 <strong><em>SETTER</em></strong>, 先引用 MDN 的文档</p>\n<blockquote>\n<p>The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters.</p>\n</blockquote>\n<p>也就是说, 第二个参数的 GET 会被调用, 第一个参数的 SET 会被调用. 而因为 <code class=\"language-text\">{ …obj }</code> 就相当于 <code class=\"language-text\">Object.assign({}, obj)</code>, 所以只有 GET 会被调用。</p>\n<p>如何证明 SET 会被调用呢? 这个简单, 使用 <code class=\"language-text\">Object.assign(obj, obj)</code> 就行.\n如果现在的代码是这样的</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> symbol <span class=\"token operator\">=</span> <span class=\"token function\">Symbol</span><span class=\"token punctuation\">(</span><span class=\"token string\">'cool'</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> obj <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  a<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">get</span> <span class=\"token function\">hh</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__GETTER__'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a <span class=\"token operator\">+=</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">set</span> <span class=\"token function\">hh</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">val</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__SETTER__'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>a <span class=\"token operator\">+=</span> val <span class=\"token operator\">*</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">[</span>symbol<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token string\">'good'</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">.</span>hh<span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">.</span>hh<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> aha <span class=\"token operator\">=</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">assign</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">,</span> obj<span class=\"token punctuation\">)</span>\nconsole<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\">getOwnPropertyDescriptors</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>Reflect<span class=\"token punctuation\">.</span><span class=\"token function\">ownKeys</span><span class=\"token punctuation\">(</span>aha<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>会出现下面的结果.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 538px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/306e2f20608f2abb12380067efc28b5f/9516f/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 116.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'464\\'%3e%3cpath%20d=\\'M0%2015v15h13l13%201-13%201H0v25h14l13%201-14%201H0v405h401V0H206A8900%208900%200%20003%201L0%200v15m95%205l1%208%201-3c0-6%205-5%207%201l2%202c1%200%201-1-1-4l-1-4c3-4%200-8-5-8h-4v8m0%2027l1%208%201-3c0-3%200-4%202-4%201%200%203%201%204%204l3%203c1%200%201-1-1-4s-2-4-1-6c2-3-1-7-7-7-2%200-2%201-2%209m41%2079v9h4c4%200%205-1%205-3%202-5%200-9-4-9-3%200-3%200-3-2l-1-3-1%208m26%2027v9h4c5%200%206-1%206-6s-2-7-5-6c-2%200-3%200-2-2l-1-3c-2%200-2%201-2%208m27%2027v9h4c5-1%206-2%206-7%200-4-2-6-6-6-2%201-2%201-2-1l-1-3-1%208m-105-3c-2%201-3%209-1%2011%203%203%209%200%209-6%200-5-4-7-8-5m53%201c-4%204-1%2012%204%2011h2c0%202-3%203-5%203h-2%208l1-9v-7h-3c-3%200-4%201-5%202m-68%2054c-3%205%200%2011%204%2010%203-1%203%200%203%201l-4%202c-3%200-3%202%200%202%205%200%206-2%206-10v-7h-4c-3%200-4%200-5%202m161-1l-1%205c0%204%201%206%205%206s5-2%205-6-1-6-5-6l-4%201m53%201c-3%205%200%2011%204%2010%203-1%203%200%203%201l-4%202c-3%200-3%202%200%202%205%200%206-2%206-10v-7h-4c-3%200-4%200-5%202m-52%2026c-2%201-3%208-1%2010s7%201%208-1c2-4%200-11-4-11l-3%202m-69%2029l1%208%203%201c4%200%206-1%206-7%200-4-2-7-6-6-1%201-2%201-1-1l-1-3c-2%200-2%201-2%208m28%2019l-1%209c0%207%201%207%203%208%204%200%207-2%207-6%200-5-2-7-5-7-3%201-3%201-3-2s-1-3-1-2m-107%205c-2%203-1%2010%201%2011%206%203%2011-6%206-10-1-2-5-2-7-1m54%201c-4%203%200%2012%204%2010%202-1%202-1%202%201l-4%202c-4%200-4%202%200%202%205%200%206-2%206-10v-7h-3l-5%202m-55%2028v9h4c4%200%206-1%206-5%200-5-2-7-5-7-3%201-3%200-3-2l-1-3-1%208m14-1c-3%206%203%2014%208%209v-10c-2-2-7-1-8%201m54%200c-2%202-2%207%201%209%204%204%2010-2%207-8-1-3-6-4-8-1m13%200c-3%205-1%2010%204%2010%204%200%205-2%205-6l-1-5c-2-2-7-1-8%201m60%2023c0%202%200%202-2%202-4-2-8%207-4%2010l5%202h3v-9l-1-8-1%203m-46%203c-4%204-1%2012%204%2011%202-1%202%200%202%201l-4%202c-3%200-3%201%200%202%204%200%206-2%206-10l-1-7h-3c-1-1-3%200-4%201m14%200c-1%201-2%202-2%205%200%204%201%206%205%206%205%200%207-7%203-11-2-2-3-2-6%200m13%200c-4%204-2%2011%203%2011%204%200%205-2%205-6%200-6-4-9-8-5m-68%2029v9h3c4%200%207-3%207-7%200-3-4-6-6-5-2%200-2%200-2-2l-1-3-1%208m26%2019v9c0%207%201%207%203%208%205%200%207-1%207-6s-2-8-5-7c-2%201-3%201-2-1%200-3-2-5-3-3m27%2034v9h3c4%201%207-1%207-6%200-4-2-6-5-6-3%201-3%200-3-2l-1-3-1%208m-106-2c-2%202-1%209%201%2010%205%204%209-2%207-8-1-3-6-4-8-2m53%201c-3%205%200%2011%204%2010%203-1%203%200%203%201l-4%202c-3%200-3%202%200%202%205%200%206-2%206-10v-7h-4c-3%200-4%200-5%202\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          data-srcset=\"/static/306e2f20608f2abb12380067efc28b5f/ba381/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.webp 200w,\n/static/306e2f20608f2abb12380067efc28b5f/7f61c/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.webp 400w,\n/static/306e2f20608f2abb12380067efc28b5f/b52d2/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.webp 538w\"\n          sizes=\"(max-width: 538px) 100vw, 538px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/306e2f20608f2abb12380067efc28b5f/772e8/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.png 200w,\n/static/306e2f20608f2abb12380067efc28b5f/e17e5/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.png 400w,\n/static/306e2f20608f2abb12380067efc28b5f/9516f/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.png 538w\"\n          sizes=\"(max-width: 538px) 100vw, 538px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image lazyload\"\n          data-src=\"/static/306e2f20608f2abb12380067efc28b5f/9516f/7F67AD27-E0D9-42B7-AB4C-D67D9A4C7241.png\"\n          alt=\"7F67AD27 E0D9 42B7 AB4C D67D9A4C7241\"\n          title=\"7F67AD27 E0D9 42B7 AB4C D67D9A4C7241\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span></p>\n<p>在这里, GET 和 SET 都被调用了一次, 分别是 source 和 target 调用的. 而这个时候 a 变成 12 也不难解释.\n因为 <code class=\"language-text\">obj.a</code> 原来是 3. 当 assign 被调用的时候, 内部会有一个 <code class=\"language-text\">obj.a = obj.a</code> 的过程. 先 GET, 就让 <code class=\"language-text\">obj.a</code> 变成了 4, 然后是 SET, 也就是 <code class=\"language-text\">obj.a += obj.a * 4</code> 就成了 12.</p>\n<p>不过, 值得注意的是, 这里 hh 还是 GET 和 SET, 并没有像上面的 assign 所做的一样，被替换成普通的属性.\n不知道这是不是有意为之.</p>\n<p>那么我们该如何复制含有 get 和 set 的对象呢? 如果用到 ES8 的特性的话, 会很简单</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> realShadow <span class=\"token operator\">=</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span>\n  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>\n  Object<span class=\"token punctuation\">.</span><span class=\"token function\">getOwnPropertyDescriptors</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/af279db6c89a2d5d7aa85a971678507a/0c1c2/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'107\\'%3e%3cpath%20d=\\'M0%2054v53h401V0H0v54m0%200v54l1-50a583%20583%200%2001-1-4\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          data-srcset=\"/static/af279db6c89a2d5d7aa85a971678507a/ba381/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.webp 200w,\n/static/af279db6c89a2d5d7aa85a971678507a/7f61c/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.webp 400w,\n/static/af279db6c89a2d5d7aa85a971678507a/d00b9/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.webp 800w,\n/static/af279db6c89a2d5d7aa85a971678507a/92f8c/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.webp 1200w,\n/static/af279db6c89a2d5d7aa85a971678507a/64634/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.webp 1542w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/af279db6c89a2d5d7aa85a971678507a/772e8/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png 200w,\n/static/af279db6c89a2d5d7aa85a971678507a/e17e5/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png 400w,\n/static/af279db6c89a2d5d7aa85a971678507a/5a190/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png 800w,\n/static/af279db6c89a2d5d7aa85a971678507a/c1b63/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png 1200w,\n/static/af279db6c89a2d5d7aa85a971678507a/0c1c2/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png 1542w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image lazyload\"\n          data-src=\"/static/af279db6c89a2d5d7aa85a971678507a/5a190/1A25BA7A-053A-42D7-91AB-2184F28CFAA5.png\"\n          alt=\"1A25BA7A 053A 42D7 91AB 2184F28CFAA5\"\n          title=\"1A25BA7A 053A 42D7 91AB 2184F28CFAA5\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span></p>\n<p>这里 a 的值还是 3, 说明这个 get 根本没有被执行, 完成没有副作用. 这才是真正的浅拷贝嘛!</p>\n<p>OK, 那么这里可以得出一个结论: 对于普通的纯对象, 比如 redux 里保存的那些, 使用 <code class=\"language-text\">assign</code> 没有任何问题. 但如果是自己定义的复杂对象, 带了很多 get 的话, 最好的方式还是采用下面这种最安全的方式吧.</p>\n<p>值得一提的是, 这也是 MDN 推荐的方式:</p>\n<blockquote>\n<p>Whereas the Object.assign() method will only copy enumerable and own properties from a source object to a target object, you are able to use this method and Object.create() for a shallow copy between two unknown objects</p>\n</blockquote>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">Object<span class=\"token punctuation\">.</span><span class=\"token function\">create</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> Object<span class=\"token punctuation\">.</span><span class=\"token function\">getOwnPropertyDescriptors</span><span class=\"token punctuation\">(</span>obj<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>","frontmatter":{"title":"Object.assign 的一些问题","spoiler":null,"image":null,"date":"2018/01/31"}}},"pageContext":{"slug":"/object-assign/","previous":{"fields":{"slug":"/deep-learning/"},"frontmatter":{"title":"Deep Learning Quick Guide（翻译）","image":null,"spoiler":null}},"next":{"fields":{"slug":"/lodash-fp/"},"frontmatter":{"title":"使用 lodash/fp","image":null,"spoiler":"感受 fp 的强大"}}}}}