wwW623mm显示“页面浏览器打印页面设置不到里面623mmcom的内容”怎么解决?

404 Not Found
404 Not Found
The requested URL was not found on this server.
您要找的内容已被删除&figure&&img src=&https://pic4.zhimg.com/v2-591c1b35d2b970ba60fd8dbc5e965451_b.jpg& data-rawwidth=&689& data-rawheight=&391& class=&origin_image zh-lightbox-thumb& width=&689& data-original=&https://pic4.zhimg.com/v2-591c1b35d2b970ba60fd8dbc5e965451_r.jpg&&&/figure&&p&产品经理er除了不喜欢写文档,还不喜欢画流程图,这是真的吗?实际上,不是的,画流程图就像是将自己创造的迷宫走了一遍,只要保证不迷路,同时也不要困在迷宫当中,就算是走通了。&/p&&p&“迷宫游戏”只是其中的一种流程,而产品经理er需要绘制的产品流程图包括&b&业务流程图(Transaction Flow Diagram)、任务/活动流程图(Mission Flow Diagrams)、功能流程图(Function Flow Diagram)、页面流程图(Page Flow Diagram)、数据流程图(Data Flow Diagram)以及时序图(UML)&/b&,这里基本涵盖了一款完整的产品包含的全部流程了。&/p&&p&&br&&/p&&h2&&b&业务流程图(Transaction Flow Diagram)&/b&&/h2&&p&业务流程图是指产品线上的业务,在不同阶段下,不同对象之间通过执行对应的功能/模块,以达到完成该业务的过程。&/p&&p&比如说,电商平台购买的流程;比如说,上门拍摄全家福的流程等等,都算业务的流程。&/p&&p&例如拍摄全家福这样的业务流程,很简单地做法,就是将整个业务参与的角色所需要准备、操作的功能按照模块罗列清楚,然后将整个业务贯穿的任务连接起来。那么分解出主要的阶段就是,用户在手机上下单,系统处理后将订单进行智能化分配,摄影师接到单后出发上门服务,最后由平台对样片进行处理,线下打印发货配送样片。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-318f9ca2dfd6beab6f71ac_b.jpg& data-rawwidth=&623& data-rawheight=&66& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&623& data-original=&https://pic1.zhimg.com/v2-318f9ca2dfd6beab6f71ac_r.jpg&&&figcaption&业务流程图&/figcaption&&/figure&&p&&br&&/p&&p&那么,正常的业务流程不单单是这么简单的,需要将整个系统参与并执行的操作全部罗列清楚,一般用&b&泳道图&/b&来呈现:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-2a174cbd9b0bbec142657_b.jpg& data-rawwidth=&1098& data-rawheight=&1334& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&1098& data-original=&https://pic4.zhimg.com/v2-2a174cbd9b0bbec142657_r.jpg&&&figcaption&业务流程图-泳道图&/figcaption&&/figure&&p&&br&&/p&&h2&&b&任务/活动流程图(Mission Flow Diagrams)&/b&&/h2&&p&跟业务流程图不一样的是,任务/活动流程图属于业务流程图细分下的一种流程,比如单独的拿“下单”这个流程来说,下单需要经过用户挑选拍摄套餐,选择完毕后下单最后支付。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-a9adbe1cb42c21a9a8c22e583a4bb447_b.jpg& data-rawwidth=&623& data-rawheight=&65& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&623& data-original=&https://pic4.zhimg.com/v2-a9adbe1cb42c21a9a8c22e583a4bb447_r.jpg&&&figcaption&任务图&/figcaption&&/figure&&p&&br&&/p&&p&那么这里会有跟业务流程图不一样的点,&/p&&p&1、任务流程图只展示某一个对象执行的操作,完成单一的目标&/p&&p&2、只展示正常的活动流程&/p&&p&&br&&/p&&h2&&b&功能流程图(Function Flow Diagram)&/b&&/h2&&p&功能流程图其实是任务流程图继续细分下来的图形。比如购买拍摄全家福套餐的任务流程图:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-3c5c2fd3addbf_b.jpg& data-rawwidth=&236& data-rawheight=&673& data-size=&normal& class=&content_image& width=&236&&&figcaption&功能流程图&/figcaption&&/figure&&p&因为是小程序的版本,所以并没有注册登录的功能,只需要微信授权。&/p&&p&&br&&/p&&h2&&b&页面流程图(Page Flow Diagram)&/b&&/h2&&p&页面流程比较好理解,即表示页面流程之间的跳转,比如在线购买全家福套餐的页面流程,&/p&&figure&&img src=&https://pic3.zhimg.com/v2-8ee984df8ba268fb3cd2e2_b.jpg& data-rawwidth=&95& data-rawheight=&673& data-size=&normal& class=&content_image& width=&95&&&figcaption&页面流程图&/figcaption&&/figure&&p&&br&&/p&&p&这里跟功能流程的区别主要有,&/p&&p&1、页面流程模仿的是用户在客户端执行操作的每一个页面的跳转,不涉及判断流程;&/p&&p&2、中间也有可能会中断流程,如果没定义好流程的话,比如选择收货地址后页面不跳转,那么流程即中断。&/p&&p&&br&&/p&&h2&&b&数据流程图(Data Flow Diagram)&/b&&/h2&&p&数据流程图是我们很少涉及的流程,一般是技术人员绘制得比较多。数据流程描述的是页面流程每一步的操作所对应的与后台之间的联系,&/p&&figure&&img src=&https://pic3.zhimg.com/v2-e00d153e162fee9ff419de_b.jpg& data-rawwidth=&360& data-rawheight=&685& data-size=&normal& class=&content_image& width=&360&&&figcaption&数据流程图&/figcaption&&/figure&&p&&br&&/p&&h2&&b&时序图(UML)&/b&&/h2&&p&时序图是表示前后台之间的系统交互,经常用于绘制注册登录、支付下单、订单查询等等关于有状态变化的流程,比如注册的时序图:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-929d039abef03a9a007540eee1aaacc3_b.jpg& data-rawwidth=&821& data-rawheight=&717& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&821& data-original=&https://pic4.zhimg.com/v2-929d039abef03a9a007540eee1aaacc3_r.jpg&&&figcaption&时序图&/figcaption&&/figure&&p&每一个步骤都可以查看到用户与系统的操作反馈和状态的变化。&/p&&h2&画图工具推荐&/h2&&p&这里我只推荐一款比较实用的画图工具--VISIO,如果你还没入门,那它就是一款入门比较简单,同时进阶后绘制更高级更复杂的流程时,也是可以满足你的需求。&/p&&p&不同系统都有很多画图工具,具体还是看个人喜欢。&/p&&p&&br&&/p&&p&总的来说,当需要画流程图的时候,必须要仔细画好,特别是前期产品做规划和后台定流程的情况下,稍有不慎,后面进行产品需求变更的时候,可能需要消耗极大的人力、物力、财力。&/p&&p&&/p&&p&&/p&&p&&/p&&p&&/p&&p&&/p&&p&&/p&&p&&/p&&p&&/p&
产品经理er除了不喜欢写文档,还不喜欢画流程图,这是真的吗?实际上,不是的,画流程图就像是将自己创造的迷宫走了一遍,只要保证不迷路,同时也不要困在迷宫当中,就算是走通了。“迷宫游戏”只是其中的一种流程,而产品经理er需要绘制的产品流程图包括业…
&figure&&img src=&https://pic4.zhimg.com/v2-58b5ff5e5d319cb09e45_b.jpg& data-rawwidth=&1652& data-rawheight=&1020& class=&origin_image zh-lightbox-thumb& width=&1652& data-original=&https://pic4.zhimg.com/v2-58b5ff5e5d319cb09e45_r.jpg&&&/figure&&p&大家都知道 近期android联盟发布了快应用产品,可以在android手机上使用类RN,Weex的开发方式进行原生系统应用的开发。&/p&&blockquote&1. 快应用是基于手机硬件平台的新型应用形态,标准是由主流手机厂商组成的快应用联盟联合制定。&br&2. 快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台,以平台化的生态模式对个人开发者和企业开发者全品类开放。&br&3. 快应用具备传统APP完整的应用体验,无需安装、即点即用。&/blockquote&&p&快应用官网:&a href=&https://link.zhihu.com/?target=https%3A//www.quickapp.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&快应用官方网站&/a&&/p&&p&新浪移动作为快应用第一批内测用户,在小米手机上已经很早的发布了新浪新闻客户端的快应用程序,大家可以在小米手机上搜索 新浪新闻客户端 体验:&/p&&a class=&video-box& href=&https://link.zhihu.com/?target=https%3A//www.zhihu.com/video/538112& target=&_blank& data-video-id=&& data-video-playable=&true& data-name=&& data-poster=&https://pic1.zhimg.com/80/v2-b3ec02a5ca49a4dcfc44a165fa8f133c_b.jpg& data-lens-id=&538112&&
&img class=&thumbnail& src=&https://pic1.zhimg.com/80/v2-b3ec02a5ca49a4dcfc44a165fa8f133c_b.jpg&&&span class=&content&&
&span class=&title&&&span class=&z-ico-extern-gray&&&/span&&span class=&z-ico-extern-blue&&&/span&&/span&
&span class=&url&&&span class=&z-ico-video&&&/span&https://www.zhihu.com/video/538112&/span&
&p&在上个月,美团点评发布了&a href=&https://link.zhihu.com/?target=https%3A//github.com/Meituan-Dianping/mpvue& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&mpvue框架&/a&,功能是用vue来编写微信小程序,同时可以运行在web上,其实很早以前我们这边也同样在进行技术调研和攻关,不过后来看到mpvue的火爆,更加坚定和肯定了我们这个想法是可以实现的,现在我们内部如果开发微信小程序也是建议使用mpvue。&/p&&p&但是快应用产品发布后,在android手机上如何能够达到和mpvue一样的效果,我们经过调研和开发,目前已经基本完成了第一版的核心代码。&/p&&p&废话不多说,直接看视频效果,下面2段视频分别是在vue-hap-tools下开发的快应用,一个是同样的代码build出来的web版本快应用。&/p&&p&web版本:&/p&&a class=&video-box& href=&https://link.zhihu.com/?target=https%3A//www.zhihu.com/video/852480& target=&_blank& data-video-id=&& data-video-playable=&true& data-name=&& data-poster=&https://pic2.zhimg.com/80/v2-6e8cd0cb2b98c25ef65adebf6cea0565_b.jpg& data-lens-id=&852480&&
&img class=&thumbnail& src=&https://pic2.zhimg.com/80/v2-6e8cd0cb2b98c25ef65adebf6cea0565_b.jpg&&&span class=&content&&
&span class=&title&&&span class=&z-ico-extern-gray&&&/span&&span class=&z-ico-extern-blue&&&/span&&/span&
&span class=&url&&&span class=&z-ico-video&&&/span&https://www.zhihu.com/video/852480&/span&
&p&快应用版本:&/p&&a class=&video-box& href=&https://link.zhihu.com/?target=https%3A//www.zhihu.com/video/881024& target=&_blank& data-video-id=&& data-video-playable=&true& data-name=&& data-poster=&https://pic1.zhimg.com/80/v2-eab237770_b.jpg& data-lens-id=&881024&&
&img class=&thumbnail& src=&https://pic1.zhimg.com/80/v2-eab237770_b.jpg&&&span class=&content&&
&span class=&title&&&span class=&z-ico-extern-gray&&&/span&&span class=&z-ico-extern-blue&&&/span&&/span&
&span class=&url&&&span class=&z-ico-video&&&/span&https://www.zhihu.com/video/881024&/span&
&p&项目地址:&a href=&https://link.zhihu.com/?target=https%3A//github.com/Youjingyu/vue-hap-tools& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Youjingyu/vue-hap-tools&/a&&/p&&p&目前来看,我们在开发过程中,只要是注意使用快应用的css子集以及使用我们构建工具中的分端构建注释代码,&a href=&https://link.zhihu.com/?target=https%3A//github.com/Youjingyu/vue-hap-tools/blob/master/docs/knownIssues.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&遵守一定的开发规则和注意问题&/a&,那么我们就可以比较顺利的开发出一套可以复用在快应用以及web上的前端程序。&/p&&p&安装以及开发使用技巧可以参考我们的官方文档,在脚手架中我们已经集成了一个简单的todolist的demo,开发者快速的构建上手体验一下。&/p&&p&至于我们是如何hack的hap-tools官方工具,由于篇幅比较长,后期有时间考虑再单独写篇文章进行介绍,这个项目的主要作者是:&a href=&https://link.zhihu.com/?target=https%3A//github.com/Youjingyu& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Youjingyu (whale)&/a& , &a class=&member_mention& href=&https://www.zhihu.com/people/fb53bd2dfdf39a21c1ec0& data-hash=&fb53bd2dfdf39a21c1ec0& data-hovercard=&p$b$fb53bd2dfdf39a21c1ec0&&@whale&/a&,我只是参与了template部分的转换以及对官方脚手架结构的一些源码阅读(快应用官方并没有开源构建工具)。&/p&&p&最后如果大家在使用过程中对vue-hap-tools工具有什么问题可以及时提到&a href=&https://link.zhihu.com/?target=https%3A//github.com/Youjingyu/vue-hap-tools/issues& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Youjingyu/vue-hap-tools&/a& issues中,更多的使用和安装方法可以参考我们的github官网文档。&/p&&p&最后感叹一句:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-effcd1c91e377_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1368& data-rawheight=&762& class=&origin_image zh-lightbox-thumb& width=&1368& data-original=&https://pic2.zhimg.com/v2-effcd1c91e377_r.jpg&&&/figure&&p&&/p&
大家都知道 近期android联盟发布了快应用产品,可以在android手机上使用类RN,Weex的开发方式进行原生系统应用的开发。1. 快应用是基于手机硬件平台的新型应用形态,标准是由主流手机厂商组成的快应用联盟联合制定。 2. 快应用标准的诞生将在研发接口、能力…
&p&那就不撒谎,老老实实做技术,输出技术文章,像我一样,脚踏实地,没有银弹,我特么还是土木毕业的呢,不一样找到工作(还移民了...&/p&&p&&br&&/p&&p&最近还有个小伙伴拿到头条实习呢....(虽然对于知乎大众来说好像没什么了不起&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-af487a3c7d71aaf54903edb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&592& data-rawheight=&101& class=&origin_image zh-lightbox-thumb& width=&592& data-original=&https://pic4.zhimg.com/50/v2-af487a3c7d71aaf54903edb_r.jpg&&&/figure&&p& 但是,你看,人家现在也才刚刚找到实习呢,不靠骗不靠猜,脚踏实地,研究源码,找到offer!&/p&&p&&br&&/p&&h2&&b&网络篇&/b&&/h2&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-269d736aa516c5e7a8d7d1b7a038ff36_180x120.jpg& data-image-width=&600& data-image-height=&350& class=&internal&&方正:事件驱动与协程:基本概念介绍&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-7e8e4c20f6cc1683faca9634efe8d118_180x120.jpg& data-image-width=&723& data-image-height=&375& class=&internal&&方正:事件循环和协程:从生成器到协程&/a&&h2&&b&框架教程篇&/b&&/h2&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-a5ab56c6ab0b396e13d9e_180x120.jpg& data-image-width=&466& data-image-height=&264& class=&internal&&方正:koa:一个几分钟就能学会的web框架&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-dbfaec0af8658eae99ac2b_180x120.jpg& data-image-width=&576& data-image-height=&212& class=&internal&&方正:koa2:Node.js开发一个同步服务器&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-dbfaec0af8658eae99ac2b_180x120.jpg& data-image-width=&576& data-image-height=&212& class=&internal&&方正:koa2:路由、模版渲染以及异步编程&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-29db694cb6bdacd6ee64dbef7af0a493_180x120.jpg& data-image-width=&1121& data-image-height=&632& class=&internal&&方正:Nodejs:摆脱黑工坊发展出一款基础企业级框架&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-8c00a2e61a4b02b900b491b5cba4d111_180x120.jpg& data-image-width=&750& data-image-height=&422& class=&internal&&方正:使用Typescript封装一款装饰器风格的Web框架&/a&&p&&b&源码(造轮子)篇&/b&&/p&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-cefb46d2c00ac8eadc480c_180x120.jpg& data-image-width=&600& data-image-height=&350& class=&internal&&方正:Luy 1.0 :一个React-like轮子的诞生&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-6a90ae0c978a18b1cce572f61c29b6eb_180x120.jpg& data-image-width=&1364& data-image-height=&712& class=&internal&&方正:80+代码实现一个React版本的酷炫动效简历&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-70dd0becd259d177b028cd9dc4d6f9ef_180x120.jpg& data-image-width=&758& data-image-height=&351& class=&internal&&方正:「造轮子」坑爹面试之现场撸旋转木马(Carousel)组件&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-4f7f2e9eedd9ae7cbf99f1b0ddc0.jpg& data-image-width=&1254& data-image-height=&625& class=&internal&&方正:造轮子:拖拽排序组件Dragact,年三十都在搞的代码&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-61dd6a0b0.jpg& data-image-width=&835& data-image-height=&423& class=&internal&&方正:React:Suspense的实现与探讨&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-0ebde8a0a0a0e0x120.jpg& data-image-width=&1226& data-image-height=&672& class=&internal&&方正:源码笔记:Nodejs 如何高效的获取时间戳而不影响性能的?&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-a7ede82b.jpg& data-image-width=&1187& data-image-height=&564& class=&internal&&方正:Node.js源码阅读:多进程架构的演进之路与eggjs多进程架构实践&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-bcbbebee6f3b0x120.jpg& data-image-width=&1497& data-image-height=&853& class=&internal&&方正:Node.js源码阅读:庖丁解牛,30行教你实现模块化&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-425bddfa0a7da3e5ef61c_180x120.jpg& data-image-width=&1327& data-image-height=&598& class=&internal&&方正:Node.js源码阅读:js层核心模块&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-425bddfa0a7da3e5ef61c_180x120.jpg& data-image-width=&1327& data-image-height=&598& class=&internal&&方正:Node.js源码解析:深入Libuv理解事件循环&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-60db66eb8ec5c6da9291680cadx120.jpg& data-image-width=&1132& data-image-height=&564& class=&internal&&方正:附录:从源码看,1分钟了解nextTick的优化&/a&&a href=&https://zhuanlan.zhihu.com/p/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-60db66eb8ec5c6da9291680cadx120.jpg& data-image-width=&1132& data-image-height=&564& class=&internal&&方正:Node源码解析:模块加载和Node.js启动&/a&&p&&br&&/p&&p&仓库:&a href=&//link.zhihu.com/?target=https%3A//github.com//Fz-node& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/Fz-node&/a&&/p&&p&&br&&/p&&p&还有很多很多,我写了真的不少了.....几十万字的了。&/p&&p&&/p&
那就不撒谎,老老实实做技术,输出技术文章,像我一样,脚踏实地,没有银弹,我特么还是土木毕业的呢,不一样找到工作(还移民了... 最近还有个小伙伴拿到头条实习呢....(虽然对于知乎大众来说好像没什么了不起 但是,你看,人家现在也才刚刚找到实习呢,…
&figure&&img src=&https://pic1.zhimg.com/v2-b6d2b81e1f3c8ed40d69e_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic1.zhimg.com/v2-b6d2b81e1f3c8ed40d69e_r.jpg&&&/figure&&p&&a href=&https://link.zhihu.com/?target=https%3A//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Proxy&/a& 是 JavaScript 2015 的一个新特性,下面让我们看看他实现哪些有趣的东西。&/p&&h2&更安全的枚举类型&/h2&&p&在 JavaScript 里,我们通常用一个对象来表示枚举值。&/p&&p&但这往往是不安全,我们希望枚举值:&/p&&ul&&li&如果不存在的话,报错。&/li&&li&不允许动态设置,否则报错。&/li&&li&不允许删除,否则报错。&/li&&/ul&&p&我们下面会写一个 &code&enum&/code& 的函数,不过先让我们来看看他在 redux 的 action types 的应用。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&// enum.test.js&/span&
&span class=&nx&&test&/span&&span class=&p&&(&/span&&span class=&s1&&'enum'&/span&&span class=&p&&,&/span& &span class=&p&&()&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&c1&&// 我们定义了俩个 action type&/span&
&span class=&kr&&const&/span& &span class=&nx&&actionTypes&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&ADD_TODO&/span&&span class=&o&&:&/span& &span class=&s1&&'add_todo'&/span&&span class=&p&&,&/span&
&span class=&nx&&UPDATE_TODO&/span&&span class=&o&&:&/span& &span class=&s1&&'update_todo'&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&safeActionTypes&/span& &span class=&o&&=&/span& &span class=&kr&&enum&/span&&span class=&p&&(&/span&&span class=&nx&&actionTypes&/span&&span class=&p&&)&/span&
&span class=&c1&&// 当读取一个不存在的枚举值时会报错&/span&
&span class=&c1&&// 因为 'DELETE_TODO' 并没有定义,所以此时会报错&/span&
&span class=&nx&&expect&/span&&span class=&p&&(()&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&nx&&safeActionTypes&/span&&span class=&p&&[&/span&&span class=&s1&&'DELETE_TODO'&/span&&span class=&p&&]&/span&
&span class=&p&&}).&/span&&span class=&nx&&toThrowErrorMatchingSnapshot&/span&&span class=&p&&()&/span&
&span class=&c1&&// 当删除一个枚举值时会报错&/span&
&span class=&nx&&expect&/span&&span class=&p&&(()&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&k&&delete&/span& &span class=&nx&&safeActionTypes&/span&&span class=&p&&[&/span&&span class=&s1&&'ADD_TODO'&/span&&span class=&p&&]&/span&
&span class=&p&&}).&/span&&span class=&nx&&toThrowErrorMatchingSnapshot&/span&&span class=&p&&()&/span&
&span class=&p&&})&/span&
&/code&&/pre&&/div&&p&那么,&code&enum&/code& 函数怎么写呢?&br&很简单,只要用 Proxy 的 &code&get&/code& , &code&set&/code& 和 &code&deleteProperty&/code& 钩子就好了。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&// erum.js&/span&
&span class=&kr&&export&/span& &span class=&k&&default&/span& &span class=&kd&&function&/span& &span class=&kr&&enum&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nb&&Proxy&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&,&/span& &span class=&p&&{&/span&
&span class=&nx&&get&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&])&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&Reflect&/span&&span class=&p&&.&/span&&span class=&nx&&get&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&nx&&ReferenceError&/span&&span class=&p&&(&/span&&span class=&sb&&`Unknown enum '&/span&&span class=&si&&${&/span&&span class=&nx&&prop&/span&&span class=&si&&}&/span&&span class=&sb&&'`&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&p&&},&/span&
&span class=&nx&&set&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&nx&&TypeError&/span&&span class=&p&&(&/span&&span class=&s1&&'Enum is readonly'&/span&&span class=&p&&)&/span&
&span class=&p&&},&/span&
&span class=&nx&&deleteProperty&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&nx&&TypeError&/span&&span class=&p&&(&/span&&span class=&s1&&'Enum is readonly'&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&p&&})&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&拓展一下的话,我们是不是可以写个&a href=&https://link.zhihu.com/?target=https%3A//medium.com/%40SylvainPV/type-safety-in-javascript-using-es6-proxies-eee8fbbbd600& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&类型校验库&/a&,在这里我们就不展开了。&/p&&h2&测试,Mock&/h2&&p&利用 &code&apply&/code& 钩子,Proxy 可以检测一个函数的调用情况。&/p&&p&下面是一个简单的,用于单元测试的 &a href=&https://link.zhihu.com/?target=http%3A//sinonjs.org/releases/v4.4.8/spies/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spy 库&/a&。他可以获取函数的调用次数,以及调用时的参数等。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&// spy.js&/span&
&span class=&kr&&export&/span& &span class=&kd&&function&/span& &span class=&nx&&spy&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&spyFn&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{}&/span&
&span class=&nx&&spyFn&/span&&span class=&p&&.&/span&&span class=&nx&&toBeCalledTimes&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&nx&&spyFn&/span&&span class=&p&&.&/span&&span class=&nx&&lastCalledWith&/span& &span class=&o&&=&/span& &span class=&kc&&undefined&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nb&&Proxy&/span&&span class=&p&&(&/span&&span class=&nx&&spyFn&/span&&span class=&p&&,&/span& &span class=&p&&{&/span&
&span class=&nx&&apply&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&thisArg&/span&&span class=&p&&,&/span& &span class=&nx&&argumentsList&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&toBeCalledTimes&/span& &span class=&o&&+=&/span& &span class=&mi&&1&/span&
&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&lastCalledWith&/span& &span class=&o&&=&/span& &span class=&nx&&argumentsList&/span&&span class=&p&&.&/span&&span class=&nx&&join&/span&&span class=&p&&(&/span&&span class=&s1&&', '&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&p&&})&/span&
&span class=&p&&}&/span&
&span class=&c1&&// spy.test.js&/span&
&span class=&kr&&const&/span& &span class=&nx&&colors&/span& &span class=&o&&=&/span& &span class=&p&&[&/span&&span class=&s1&&'red'&/span&&span class=&p&&,&/span& &span class=&s1&&'blue'&/span&&span class=&p&&]&/span&
&span class=&kr&&const&/span& &span class=&nx&&callback&/span& &span class=&o&&=&/span& &span class=&nx&&spy&/span&&span class=&p&&()&/span&
&span class=&nx&&colors&/span&&span class=&p&&.&/span&&span class=&nx&&forEach&/span&&span class=&p&&(&/span&&span class=&nx&&color&/span& &span class=&o&&=&&/span& &span class=&nx&&callback&/span&&span class=&p&&(&/span&&span class=&nx&&color&/span&&span class=&p&&))&/span&
&span class=&nx&&expect&/span&&span class=&p&&(&/span&&span class=&nx&&callback&/span&&span class=&p&&.&/span&&span class=&nx&&toBeCalledTimes&/span&&span class=&p&&).&/span&&span class=&nx&&toBe&/span&&span class=&p&&(&/span&&span class=&nx&&colors&/span&&span class=&p&&.&/span&&span class=&nx&&length&/span&&span class=&p&&)&/span&
&span class=&nx&&expect&/span&&span class=&p&&(&/span&&span class=&nx&&callback&/span&&span class=&p&&.&/span&&span class=&nx&&lastCalledWith&/span&&span class=&p&&).&/span&&span class=&nx&&toBe&/span&&span class=&p&&(&/span&&span class=&nx&&colors&/span&&span class=&p&&[&/span&&span class=&mi&&1&/span&&span class=&p&&])&/span&
&/code&&/pre&&/div&&p&另外,用 &a href=&https://link.zhihu.com/?target=https%3A//medium.com/fiverr-engineering/writing-a-js-proxy-based-assertion-function-5ab& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Proxy 写一个断言库&/a&也是挺方便的,这里就不展开了。&/p&&h2&Immutable&/h2&&p&我们也可以利用 Proxy 在数据结构上做些操作,比如实现一个像 &a href=&https://link.zhihu.com/?target=https%3A//github.com/mweststrate/immer& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&immer&/a& 的 Immutable 库。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kr&&import&/span& &span class=&p&&{&/span& &span class=&nx&&shallowCopy&/span& &span class=&p&&}&/span& &span class=&nx&&from&/span& &span class=&s1&&'./utils/index'&/span&
&span class=&kr&&export&/span& &span class=&kd&&function&/span& &span class=&nx&&produce&/span&&span class=&p&&(&/span&&span class=&nx&&base&/span&&span class=&p&&,&/span& &span class=&nx&&producer&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&state&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&base&/span&&span class=&p&&,&/span& &span class=&c1&&// 原来的数据&/span&
&span class=&nx&&copy&/span&&span class=&o&&:&/span& &span class=&kc&&null&/span&&span class=&p&&,&/span& &span class=&c1&&// 新的,复制的数据&/span&
&span class=&nx&&modified&/span&&span class=&o&&:&/span& &span class=&kc&&false&/span&&span class=&p&&,&/span& &span class=&c1&&// 是否修改过&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&proxy&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nb&&Proxy&/span&&span class=&p&&(&/span&&span class=&nx&&state&/span&&span class=&p&&,&/span& &span class=&p&&{&/span&
&span class=&nx&&get&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&// 如果修改过,则返回副本数据,或者返回原来的数据&/span&
&span class=&k&&return&/span& &span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&modified&/span& &span class=&o&&?&/span& &span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&copy&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&]&/span& &span class=&o&&:&/span& &span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&base&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&]&/span&
&span class=&p&&},&/span&
&span class=&nx&&set&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&,&/span& &span class=&nx&&value&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&// set 钩子的时候,设置 modifyied 为 true&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&modifyied&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&modified&/span& &span class=&o&&=&/span& &span class=&kc&&true&/span&
&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&copy&/span& &span class=&o&&=&/span& &span class=&nx&&shallowCopy&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&base&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&nx&&target&/span&&span class=&p&&.&/span&&span class=&nx&&copy&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&nx&&value&/span&
&span class=&k&&return&/span& &span class=&kc&&true&/span&
&span class=&p&&}&/span&
&span class=&p&&})&/span&
&span class=&nx&&producer&/span&&span class=&p&&.&/span&&span class=&nx&&call&/span&&span class=&p&&(&/span&&span class=&nx&&proxy&/span&&span class=&p&&,&/span& &span class=&nx&&proxy&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&nx&&proxy&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&实际效果就像下面这个样子:&/p&&p&我们得到了新的不同的 &code&nextState&/code& ,但是原来的 &code&baseState&/code& 并没有发生变化。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nx&&test&/span&&span class=&p&&(&/span&&span class=&s1&&'produce'&/span&&span class=&p&&,&/span& &span class=&p&&()&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&baseState&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'foo'&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&nextState&/span& &span class=&o&&=&/span& &span class=&nx&&produce&/span&&span class=&p&&(&/span&&span class=&nx&&baseState&/span&&span class=&p&&,&/span& &span class=&nx&&draft&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&nx&&draft&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&s1&&'bar'&/span&
&span class=&p&&})&/span&
&span class=&nx&&expect&/span&&span class=&p&&(&/span&&span class=&nx&&nextState&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span&&span class=&p&&).&/span&&span class=&nx&&toBe&/span&&span class=&p&&(&/span&&span class=&s1&&'bar'&/span&&span class=&p&&)&/span& &span class=&c1&&// nestState 发生了变化&/span&
&span class=&nx&&expect&/span&&span class=&p&&(&/span&&span class=&nx&&baseState&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span&&span class=&p&&).&/span&&span class=&nx&&toBe&/span&&span class=&p&&(&/span&&span class=&s1&&'foo'&/span&&span class=&p&&)&/span& &span class=&c1&&// 而 baseState 保持不变&/span&
&span class=&p&&})&/span&
&/code&&/pre&&/div&&h2&Observe,响应式系统&/h2&&p&用 Proxy 来实现一个 pub/sub 模式也是挺简单的。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&// observe.js&/span&
&span class=&kr&&export&/span& &span class=&kd&&function&/span& &span class=&nx&&observe&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&onChange&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&createProxy&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&onChange&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&kd&&function&/span& &span class=&nx&&createProxy&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&onChange&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&trap&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&get&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&value&/span& &span class=&o&&=&/span& &span class=&nx&&object&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&]&/span&
&span class=&c1&&// 这里可以优化一下,不应该每次都创建新的 proxy&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&k&&typeof&/span& &span class=&nx&&value&/span& &span class=&o&&===&/span& &span class=&s1&&'object'&/span& &span class=&o&&&&&/span& &span class=&nx&&value&/span& &span class=&o&&!==&/span& &span class=&kc&&null&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&createProxy&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&[&/span&&span class=&nx&&prop&/span&&span class=&p&&],&/span& &span class=&nx&&onChange&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&nx&&value&/span&
&span class=&p&&},&/span&
&span class=&nx&&set&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&,&/span& &span class=&nx&&value&/span&&span class=&p&&,&/span& &span class=&p&&...&/span&&span class=&nx&&args&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&onChange&/span&&span class=&p&&()&/span&
&span class=&k&&return&/span& &span class=&nx&&Reflect&/span&&span class=&p&&.&/span&&span class=&nx&&set&/span&&span class=&p&&(&/span&&span class=&nx&&object&/span&&span class=&p&&,&/span& &span class=&nx&&prop&/span&&span class=&p&&,&/span& &span class=&nx&&value&/span&&span class=&p&&,&/span& &span class=&p&&...&/span&&span class=&nx&&args&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nb&&Proxy&/span&&span class=&p&&(&/span&&span class=&nx&&target&/span&&span class=&p&&,&/span& &span class=&nx&&trap&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&c1&&// observe.test.js&/span&
&span class=&nx&&test&/span&&span class=&p&&(&/span&&span class=&s1&&'observe'&/span&&span class=&p&&,&/span& &span class=&p&&()&/span& &span class=&o&&=&&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&stub&/span& &span class=&o&&=&/span& &span class=&nx&&jest&/span&&span class=&p&&.&/span&&span class=&nx&&fn&/span&&span class=&p&&()&/span&
&span class=&kr&&const&/span& &span class=&nx&&data&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&user&/span&&span class=&o&&:&/span& &span class=&p&&{&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'foo'&/span&&span class=&p&&,&/span&
&span class=&p&&},&/span&
&span class=&nx&&colors&/span&&span class=&o&&:&/span& &span class=&p&&[&/span&&span class=&s1&&'red'&/span&&span class=&p&&],&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&reactiveData&/span& &span class=&o&&=&/span& &span class=&nx&&observe&/span&&span class=&p&&(&/span&&span class=&nx&&data&/span&&span class=&p&&,&/span& &span class=&nx&&stub&/span&&span class=&p&&)&/span&
&span class=&c1&&// push 会触发两次 set 钩子&/span&
&span class=&c1&&// 第一次把 colors 的 2 属性设置为 'blue'&/span&
&span class=&c1&&// 第二次把 colors 的 length 属性设置为 2&/span&
&span class=&nx&&reactiveData&/span&&span class=&p&&.&/span&&span class=&nx&&colors&/span&&span class=&p&&.&/span&&span class=&nx&&push&/span&&span class=&p&&(&/span&&span class=&s1&&'blue'&/span&&span class=&p&&)&/span&
&span class=&nx&&reactiveData&/span&&span class=&p&&.&/span&&span class=&nx&&user&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&s1&&'baz'&/span&
&span class=&c1&&// 动态增加一个新的属性&/span&
&span class=&nx&&reactiveData&/span&&span class=&p&&.&/span&&span class=&nx&&type&/span& &span class=&o&&=&/span& &span class=&s1&&'zzz'&/span&
&span class=&nx&&expect&/span&&span class=&p&&(&/span&&span class=&nx&&stub&/span&&span class=&p&&).&/span&&span class=&nx&&toHaveBeenCalledTimes&/span&&span class=&p&&(&/span&&span class=&mi&&4&/span&&span class=&p&&)&/span&
&span class=&p&&})&/span&
&/code&&/pre&&/div&&p&从上面可以发现,Proxy 不仅可以代理对象,也可以代理数组;还可以代理动态增加的属性如 &code&type&/code& 。这也是 &code&Object.defineProperty&/code& 做不到的。&/p&&p&加个依赖追踪的话,我们就可以实现一个类似 Vue 或者 Mobx 的&a href=&https://link.zhihu.com/?target=https%3A//vuejs.org/v2/guide/reactivity.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&响应式系统&/a&了。&/p&&h2&更多有趣的例子&/h2&&p&我们还可以用 Proxy 实现很多东西,比如埋点可以不,性能监控可以不?&/p&&ul&&li&&a href=&https://link.zhihu.com/?target=https%3A//medium.com/dailyjs/how-to-use-javascript-proxies-for-fun-and-profit-a9f8& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&How to use JavaScript Proxies for Fun and Profit&/a&&/li&&li&&a href=&https://link.zhihu.com/?target=http%3A//dealwithjs.io/es6-features-10-use-cases-for-proxy/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ES6 Features - 10 Use Cases for Proxy&/a&&/li&&li&&a href=&https://link.zhihu.com/?target=https%3A//github.com/mikaelbr/proxy-fun& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&proxy-fun&/a&&/li&&/ul&&p&Proxy 的更多玩法,大家好好挖掘挖掘
是 JavaScript 2015 的一个新特性,下面让我们看看他实现哪些有趣的东西。更安全的枚举类型在 JavaScript 里,我们通常用一个对象来表示枚举值。但这往往是不安全,我们希望枚举值:如果不存在的话,报错。不允许动态设置,否则报错。不允许删除,否…
&figure&&img src=&https://pic2.zhimg.com/v2-8e52e4decaf3e8d28572a3d_b.jpg& data-rawwidth=&1207& data-rawheight=&615& class=&origin_image zh-lightbox-thumb& width=&1207& data-original=&https://pic2.zhimg.com/v2-8e52e4decaf3e8d28572a3d_r.jpg&&&/figure&&p&&/p&&h2&&b&一. 重新认识面向对象&/b&&/h2&&h2&&b&1. JavaScript是一门面向对象的语言&/b&&/h2&&p&在说明JavaScript是一个面向对象的语言之前, 我们来探讨一下面向对象的三大基本特征:&b&封装&/b&, &b&继承&/b&, &b&多态&/b&。&/p&&p&&b&封装&/b&&/p&&blockquote&把抽象出来的属性和对方法组合在一起, 且属性值被保护在内部, 只有通过特定的方法进行改变和读取称为封装&/blockquote&&p&我们以代码举例, 首先我们构造一个&code&Person&/code&构造函数, 它有&code&name&/code&和&code&id&/code&两个属性, 并有一个&code&sayHi&/code&方法用于打招呼:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&//定义Person构造函数&/span&
&span class=&kd&&function&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&c1&&//在Person.prototype中加入方法&/span&
&span class=&nx&&Person&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&sayHi&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&s1&&'你好, 我是'&/span& &span class=&o&&+&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&现在我们生成一个实例对象&code&p1&/code&, 并调用&code&sayHi()&/code&方法&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&c1&&//实例化对象&/span&
&span class=&kd&&let&/span& &span class=&nx&&p1&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&1234&/span&&span class=&p&&);&/span&
&span class=&c1&&//调用sayHi方法&/span&
&span class=&nx&&p1&/span&&span class=&p&&.&/span&&span class=&nx&&sayHi&/span&&span class=&p&&();&/span&
&/code&&/pre&&/div&&p&在上述的代码中, &code&p1&/code&这个对象并不知道&code&sayHi()&/code&这个方法是如何实现的, 但是仍然可以使用这个方法. 这其实就是&b&封装&/b&. 你也可以实现对象属性的私有和公有, 我们在构造函数中声明一个&code&salary&/code&作为私有属性, 有且只有通过&code&getSalary()&/code&方法查询到薪资.&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&kd&&let&/span& &span class=&nx&&salary&/span& &span class=&o&&=&/span& &span class=&mi&&20000&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&getSalary&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&pwd&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&pwd&/span& &span class=&o&&===&/span& &span class=&mi&&123456&/span& &span class=&o&&?&/span& &span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&nx&&salary&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&s1&&'对不起, 你没有权限查看密码'&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&&b&继承&/b&&/p&&blockquote&可以让某个类型的对象获得另一个类型的对象的属性和方法称为继承&/blockquote&&p&以刚才的&code&Person&/code&作为父类构造器, 我们来新建一个子类构造器&code&Student&/code&, 这里我们使用&code&call()&/code&方法实现继承&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&id&/span&&span class=&p&&,&/span& &span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&//使用call实现父类继承&/span&
&span class=&nx&&Person&/span&&span class=&p&&.&/span&&span class=&nx&&call&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&,&/span& &span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&id&/span&&span class=&p&&);&/span&
&span class=&c1&&//添加子类的属性&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&kd&&let&/span& &span class=&nx&&s1&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&1234&/span&&span class=&p&&,&/span& &span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&&b&多态&/b&&/p&&blockquote&同一操作作用于不同的对象产生不同的执行结果, 这称为多态&/blockquote&&p&JavaScript中函数没有重载, 所以JavaScript中的多态是靠函数覆盖实现的。&/p&&p&同样以刚才的&code&Person&/code&构造函数为例, 我们为&code&Person&/code&构造函数添加一个&code&study&/code&方法&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&nx&&name&/span& &span class=&o&&+&/span& &span class=&s1&&'在学习'&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&同样, 我们新建一个&code&Student&/code&和&code&Teacher&/code&构造函数, 该构造函数继承&code&Person&/code&, 并也添加&code&study&/code&方法&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&+&/span& &span class=&s1&&'在学习'&/span& &span class=&o&&+&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&nx&&Student&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&1234&/span&&span class=&p&&);&/span&
&span class=&nx&&Student&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&constructor&/span& &span class=&o&&=&/span& &span class=&nx&&Student&/span&&span class=&p&&;&/span&
&span class=&kd&&function&/span& &span class=&nx&&Teacher&/span&&span class=&p&&(&/span&&span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&+&/span& &span class=&s1&&'为了教学而学习'&/span& &span class=&o&&+&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&nx&&Teacher&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Person&/span&&span class=&p&&(&/span&&span class=&s2&&&老夫子&&/span&&span class=&p&&,&/span& &span class=&mi&&4567&/span&&span class=&p&&);&/span&
&span class=&nx&&Teacher&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&constructor&/span& &span class=&o&&=&/span& &span class=&nx&&Teacher&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&测试我们新建一个函数&code&doStudy&/code&&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&doStudy&/span&&span class=&p&&(&/span&&span class=&nx&&role&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&nx&&role&/span& &span class=&k&&instanceof&/span& &span class=&nx&&Person&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&role&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span&&span class=&p&&();&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&此时我们分别实例化&code&Student&/code&和&code&Teacher&/code&, 并调用&code&doStudy&/code&方法&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&let&/span& &span class=&nx&&student&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span&
&span class=&kd&&let&/span& &span class=&nx&&teacher&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Teacher&/span&&span class=&p&&(&/span&&span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span&
&span class=&nx&&doStudy&/span&&span class=&p&&(&/span&&span class=&nx&&student&/span&&span class=&p&&);&/span& &span class=&c1&&//阿辉在学习前端开发&/span&
&span class=&nx&&doStudy&/span&&span class=&p&&(&/span&&span class=&nx&&teacher&/span&&span class=&p&&);&/span& &span class=&c1&&//老夫子为了教学在学习前端开发&/span&
&/code&&/pre&&/div&&p&对于同一函数&code&doStudy&/code&, 由于参数的不同, 导致不同的调用结果,这就实现了多态.&/p&&p&&b&JavaScript的面向对象&/b&&br&从上面的分析可以论证出, JavaScript是一门面向对象的语言, 因为它实现了面向对象的所有特性. 其实, 面向对象仅仅是一个概念或者一个编程思想而已, 它不应该依赖于某个语言存在, 比如Java采用面向对象思想构造其语言, 它实现了类, 继承, 派生, 多态, 接口等机制. 但是这些机制,只是实现面向对象的一种手段, 而非必须。换言之, 一门语言可以根据自身特性选择合适的方式来实现面向对象。 由于大多数程序员首先学习的是Java, C++等高级编程语言, 因而先入为主的接受了“类”这个面向对象实际方式,所以习惯性的用类式面向对象语言中的概念来判断该语言是否是面向对象的语言。这也是很多有其他编程语言经验的人在学习JavaScript对象时,感觉到很困难的地方。&/p&&p&实际上, JavaScript是通过一种叫&b&原型(prototype)&/b&的方式来实现面向对象编程的。下面我们就来讨论一下&b&基于类(class-basesd)的面向对象&/b&和&b&基于原型(protoype-based)的面向对象&/b&这两者的差别。&/p&&h2&&b&2. 基于类的面向对象和基于原型的面向对象的比较&/b&&/h2&&p&&b&基于类的面向对象&/b&&/p&&p&在基于&b&类&/b&的面向对象语言中(比如Java和C++), 是构建在&b&类(class)&/b&和&b&实例(instance)&/b&上的。其中&b&类&/b&定义了所有用于具有某一特征对象的属性。&b&类&/b&是抽象的事物, 而不是其所描述的全部对象中的任何特定的个体。另一方面, 一个&b&实例&/b&是一个&b&类&/b&的实例化,是其中的一个成员。&/p&&p&&b&基于原型的面向对象&/b&&br&在基于&b&原型&/b&的语言中(如JavaScript)并不存在这种区别:&b&它只有对象!&/b&不论是构造函数(constructor),实例(instance),原型(prototype)本身都是对象。基于原型的语言具有所谓的原型对象的概念,新对象可以从中获得原始的属性。&/p&&p&所以,在JavaScript中有一个很有意思的&code&__proto__&/code&属性(ES6以下是非标准属性)用于访问其原型对象, 你会发现,上面提到的构造函数,实例,原型本身都有&code&__proto__&/code&指向原型对象。其最后顺着原型链都会指向&code&Object&/code&这个构造函数,然而&code&Object&/code&的原型对象的原型是&code&null&/code&,不信, 你可以尝试一下&code&Object.prototype.__proto__ === null&/code&为&code&true&/code&。然而&code&typeof null === 'object'&/code&为&code&true&/code&。到这里, 我相信你应该就能明白为什么JavaScript这类基于原型的语言中没有类和实例的区别, 而是&b&万物皆对象!&/b&&/p&&p&&b&差异总结&/b&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fa722a576a110d15c59a09e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&846& data-rawheight=&408& class=&origin_image zh-lightbox-thumb& width=&846& data-original=&https://pic1.zhimg.com/v2-fa722a576a110d15c59a09e_r.jpg&&&/figure&&h2&&b&二. ES5中的面向对象&/b&&/h2&&blockquote&*这里的ES5并不特指ECMAScript 5, 而是代表ECMAScript 6 之前的ECMAScript!&/blockquote&&h2&&b&(一) ES5中对象的创建&/b&&/h2&&p&在ES5中创建对象有两种方式, 第一种是使用对象字面量的方式, 第二种是使用构造函数的方式。该两种方法在特定的使用场景分别有其优点和缺点, 下面我们来分别介绍这两种创建对象的方式。&/p&&h2&&b&1. 使用对象字面量的方式&/b&&/h2&&p&我们通过对象字面量的方式创建两个&code&student&/code&对象,分别是&code&student1&/code&和&code&student2&/code&。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&var&/span& &span class=&nx&&student1&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span&
&span class=&nx&&age&/span&&span class=&o&&:&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span&
&span class=&nx&&subject&/span&&span class=&o&&:&/span& &span class=&s1&&'前端开发'&/span&
&span class=&p&&};&/span&
&span class=&kd&&var&/span& &span class=&nx&&student2&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'阿傻'&/span&&span class=&p&&,&/span&
&span class=&nx&&age&/span&&span class=&o&&:&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span&
&span class=&nx&&subject&/span&&span class=&o&&:&/span& &span class=&s1&&'大数据开发'&/span&
&span class=&p&&};&/span&
&/code&&/pre&&/div&&p&上面的代码就是使用对象字面量的方式创建实例对象, 使用对象字面量的方式在创建单一简单对象的时候是非常方便的。但是,它也有其缺点:&/p&&ul&&li&在生成多个实例对象时, 我们需要每次重复写&code&name&/code&,&code&age&/code&,&code&subject&/code&属性,写起来特别的麻烦&/li&&li&虽然都是学生的对象, 但是看不出&code&student1&/code&和&code&student2&/code&之间有什么联系。&/li&&/ul&&p&为了解决以上两个问题, JavaScript提供了构造函数创建对象的方式。&/p&&h2&&b&2. 使用构造函数的方式&/b&&/h2&&p&构造函数就其实就是一个普通的函数,当对构造函数使用&code&new&/code&进行实例化时,会将其内部&code&this&/code&的指向绑定实例对象上,下面我们来创建一个&code&Student&/code&构造函数(构造函数约定使用大写开头,和普通函数做区分)。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Student&/span& &span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&age&/span&&span class=&p&&,&/span& &span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&age&/span& &span class=&o&&=&/span& &span class=&nx&&age&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&我特意在构造函数中打印出&code&this&/code&的指向。上面我们提到,构造函数其实就是一个普通的函数, 那么我们使用普通函数的调用方式尝试调用&code&Student&/code&。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span& &span class=&c1&&//window{}&/span&
&/code&&/pre&&/div&&p&采用普通方式调用&code&Student&/code&时, &code&this&/code&的指向是&code&window&/code&。下面使用&code&new&/code&来实例化该构造函数, 生成一个实例对象&code&student1&/code&。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&let&/span& &span class=&nx&&student1&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span& &span class=&c1&&//Student {name: &阿辉&, age: 22, subject: &前端开发&}&/span&
&/code&&/pre&&/div&&p&当我们采用&code&new&/code&生成实例化对象&code&student1&/code&时, &code&this&/code&不再指向&code&window&/code&, 而是指向的实例对象本身。这些, 都是&code&new&/code&帮我们做的。上面的就是采用构造函数的方式生成实例对象的方式, 并且当我们生成其他实例对象时,由于都是采用&code&Student&/code&这个构造函数实例化而来的, 我们能够清楚的知道各实例对象之间的联系。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&let&/span& &span class=&nx&&student1&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span&
&span class=&kd&&let&/span& &span class=&nx&&student2&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿傻'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'大数据开发'&/span&&span class=&p&&);&/span&
&span class=&kd&&let&/span& &span class=&nx&&student3&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿呆'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'Python'&/span&&span class=&p&&);&/span&
&span class=&kd&&let&/span& &span class=&nx&&student4&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿笨'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'Java'&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&h2&&b&(二) ES5中对象的继承&/b&&/h2&&h2&&b&1.&/b& &b&&code&prototype&/code&的原型继承&/b&&/h2&&p&&code&prototype&/code&是JavaScript这类基于原型继承的核心, 只要弄明白了原型和原型链, 就基本上完全理解了JavaScript中对象的继承。下面我将着重的讲解为什么要使用&code&prototype&/code&和使用&code&prototype&/code&实现继承的方式。&/p&&p&&b&为什么要使用&code&prototype&/code&?&/b&&/p&&p&我们给之前的&code&Student&/code&构造函数新增一个&code&study&/code&方法&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Student&/span& &span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&age&/span&&span class=&p&&,&/span& &span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&age&/span& &span class=&o&&=&/span& &span class=&nx&&age&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&s1&&'我在学习'&/span& &span class=&o&&+&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&现在我们来实例化&code&Student&/code&构造函数, 生成&code&student1&/code&和``student2&code&, 并分别调用其&/code&study`方法。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&let&/span& &span class=&nx&&student1&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿辉'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'前端开发'&/span&&span class=&p&&);&/span&
&span class=&kd&&let&/span& &span class=&nx&&student2&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Student&/span&&span class=&p&&(&/span&&span class=&s1&&'阿傻'&/span&&span class=&p&&,&/span& &span class=&mi&&22&/span&&span class=&p&&,&/span& &span class=&s1&&'大数据开发'&/span&&span class=&p&&);&/span&
&span class=&nx&&student1&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span&&span class=&p&&();&/span& &span class=&c1&&//我在学习前端开发&/span&
&span class=&nx&&student2&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span&&span class=&p&&();&/span& &span class=&c1&&//我在学习大数据开发&/span&
&/code&&/pre&&/div&&p&这样生成的实例对象表面上看没有任何问题, 但是其实是有很大的&b&性能问题&/b&!我们来看下面一段代码:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nx&&console&/span&&span class=&p&&.&/span&&span class=&nx&&log&/span&&span class=&p&&(&/span&&span class=&nx&&student1&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &span class=&o&&===&/span& &span class=&nx&&student2&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span&&span class=&p&&);&/span& &span class=&c1&&//false&/span&
&/code&&/pre&&/div&&p&其实对于每一个实例对象&code&studentx&/code&,其&code&study&/code&方法的函数体是一模一样的,方法的执行结果只根据其实例对象决定,然而生成的每个实例都需要生成一个&code&study&/code&方法去占用一份内存。这样是非常不经济的做法。新手可能会认为, 上面的代码中也就多生成了一个&code&study&/code&方法, 对于内存的占用可以忽略不计。&/p&&p&那么我们在MDN中看一下在JavaScript中我们使用的&code&String&/code&实例对象有多少方法?&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-ecdd8c4f04eaad7fa08a90_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&875& data-rawheight=&905& class=&origin_image zh-lightbox-thumb& width=&875& data-original=&https://pic4.zhimg.com/v2-ecdd8c4f04eaad7fa08a90_r.jpg&&&/figure&&p&String中的方法&/p&&p&上面的方法只是&code&String&/code&实例对象中的一部分方法(我一个屏幕截取不完!), 这也就是为什么我们的字符串能够使用如此多便利的原生方法的原因。设想一下, 如果这些方法不是挂载在&code&String.prototype&/code&上, 而是像上面&code&Student&/code&一样写在&code&String&/code&构造函数上呢?那么我们项目中的每一个字符串,都会去生成这几十种方法去占用内存,这还没考虑&code&Math&/code&,&code&Array&/code&,&code&Number&/code&,&code&Object&/code&等对象!&/p&&p&现在我们应该知道应该将&code&study&/code&方法挂载到&code&Student.prototype&/code&原型对象上才是正确的写法,所有的&code&studentx&/code&实例都能继承该方法。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&function&/span& &span class=&nx&&Student&/span& &span class=&p&&(&/span&&span class=&nx&&name&/span&&span class=&p&&,&/span& &span class=&nx&&age&/span&&span class=&p&&,&/span& &span class=&nx&&subject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&=&/span& &span class=&nx&&name&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&age&/span& &span class=&o&&=&/span& &span class=&nx&&age&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&subject&/span& &span class=&o&&=&/span& &span class=&nx&&subject&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&nx&&Student&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&study&/span& &sp

我要回帖

更多关于 谷歌浏览器页面翻译 的文章

 

随机推荐