javascript王国之函数教主

前言: 本文是上一篇《一个没有类的世界是怎么玩转面向对象的》续集,由BlindingDark撰写, 老刘修改,原文参见 http://www.jianshu.com/p/74120c8ec56a

1

 拜函数教

Java 小王子在 JavaScript 王国待了也有一段时间,这里虽然不像 Java 帝国那样规范严苛,但也因此千奇百怪,五光十色。

要说小王子最喜欢待的地方,那还是人来人往的 JSON 酒馆,不仅有上好的酒菜,还有机会认识到各式各样的人。这不,一来二去他已经和上回认识的眼镜官员成了朋友,甚至私底下还称兄道弟的。

这一天小王子又和眼镜大哥一起约来吃酒。才寒暄了几句,筷子还没动,酒馆门口就发生了一点骚动。只见来了一位看起来像是教书先生的精瘦男子,旁边还有些随从。

“...... 大哥,这人什么来头,气度不凡啊。”小王子悄声向旁边的眼镜官员问到。

“哈哈,他是拜函数教的邱大教主,最近他们教派的信众激增啊,真是风水轮流转。”

“函数式?以前随父亲经商途中是听说过他们的事情,好像非常古老而且高深莫测啊,据说只有学者和虔诚的教徒才会加入他们,怎么最近也接收新人了?”

“小弟果然是见多识广,不错,在很久以前的确是这样,不过为何有大批新教徒这种事情也不在我的管辖范围内啊,所以也不太清楚。但是毕竟我是本国语言规范审查官,还是与他打过一些交道。不妨我们邀请他来一起喝酒,你亲自问他。”

小王子本来听到眼镜大哥也不了解情况正有些失望,突然得知可以直接面对面打探对方的底细,顿时兴奋了起来。

“那太好了!”

“这不是眼镜老弟么,别来无恙啊。”

“主教兄,甚好甚好,要不这顿我请?小二!”

饭菜上桌,互相客套了几句之后,话题就开始了。

“主教兄,这是我最近认识的朋友,年纪轻轻就周游四方,他有些事情要问你。”

“哦?”函数式主教把目光放了过来,“有何见教?”

“久闻贵教派向来神秘,为何最近有如此多的新教徒加入呢?”

“哈,这个嘛 ... 现在的年轻人都不喜欢条条框框,本教向来以简洁强大著称,自然就受欢迎了。”

小王子心想,这个教主倒也是有话直说、自卖自夸,不过难道没了面向对象这种强大的武器,他还能变出怎么样的花儿来?

“那还敢请教教主大人,依你看要怎么实现 Animal, Cat, Dog 这些对象呢?”想了一会儿,小王子认为不如直接发问。

“这个嘛,本教派并无对象这种说法,不过如果你愿意,也可以构造一个对象出来,只需要......”

“我们拜函数教不用对象~”,还没等着主教说完,旁边的妹子突然发话了。

“哦,小兰,你来说吧。”这位被叫做小兰的少女像是主教的助手,看起来深得主教信任。

“嘻嘻,教主大人说的太复杂了,其实实现你说的那些根本不用什么对象。”

“哦?那该怎么做?”小王子顿时来了兴趣。

2

 函数是一等公民

“你想啊,搞出来这些猫啊狗啊的,不就是想让他们都可以吃东西么?干嘛要封装到一个对象中,太压抑了”

0?wx_fmt=png

哦!Java 小王子恍然大悟,在自己的Java帝国,法律非常严格, 类和对象才是一等公民, 函数是不可能独立存在的, 你即使是想输出一个简单的hello world , 也必须写一个类,在类中写一个方法 , 在这个方法中才能输出hello world 。

在这里函数已经翻身做主人,成为了一等公民,再也不用困在对象的牢笼中,声明后就可以直接使用。

“也就是说,猫、狗都可以直接拿来调用咯?”

“是的呢~ 不止是猫、狗,连人都能作为参数调用呢, 只要一个对象有name这个属性就行啊”小兰的脸上还是一样的笑容。

0?wx_fmt=png

长期在一个强类型的语言中生活,小王子对这种有点“变态”的灵活性还真不习惯, 他说:“在Java帝国,方法的参数都有确定的类型,如果你的方法写错了,IDE就能自动帮你检测, 减少了很多错误,现在可就没这种福利了。”

“有得必有失嘛”小兰笑道 “你可以多写一点单元测试来保证正确性啊”

“既然函数是一等公民, 我相信它不止这点能耐吧?“

“那是自然, 我们这里的函数还可以作为参数传递给另外一个函数呢!”

0?wx_fmt=png

小王子突然想到父王给自己讲过,要在Java8中引入函数式编程, 可以把一个所谓的lambada 表达式传递给另外一个函数, 省去了创建类或匿名类的开销。

但是宫廷老师偷偷地告诉过自己:“那只是半吊子的函数式编程,每个lambda表达式其实还得和一个函数接口相匹配, JDK在背后做了类型的推断”

(微信公众号码农翻身注: 参见文章《Java帝国之函数式编程(上)》和《Java帝国之函数式编程(下)》)

“函数既然能作为参数,我猜肯定也能作为返回值吧?” 小王子觉得拜函数教的邱大教主在场, 这个天真活泼的小兰好像不敢给自己透露太多, 只好主动发问。

“你这个外乡人很聪明嘛, 估计有不少编程基础吧?” 小兰又展示了一段代码:

0?wx_fmt=png

果然和自己的猜想一致! 作为皇族,小王子确实非常聪明,他很快就想到了另外一个问题: 如果内部的eat函数访问了外部函数的变量会发生什么状况?

0?wx_fmt=png

按照我们Java 帝国的理论, 函数在被调用的时候是以栈帧的方式被压入栈中的, 函数的局部变量也在栈帧当中, 当这个函数返回,对应的栈帧就会被清除,局部变量自然也不可用了。

现在这个eat函数还能再使用createEatFunction()函数的desc这个变量吗? 或者在调用它的时候会使用外边的全局desc 变量?  从而输出 "dog 正在吃东西”?

函数作为返回值看起来很美, 但细节着实让人费解啊?

3

  闭包

看到小王子像上次一样又“卡”住发呆了, 眼镜官员笑着对主教和小兰说: 这小子肯定又在深思了。

小兰说:“这个外乡人确实不一般,思考很深入,让他的CPU再运转一会儿吧”

小王子没有找到答案,从思考中回来,看到大家都盯着自己看,有点不好意思, 把疑惑给大家说了。  

“外乡人,Java 把你毒害得不浅, 我看你资质不错,不如忘掉Java 那丑陋的模型, 加入到我们拜函数教来吧。 将来你继承我的位置也未可知啊!” 邱大教主看了小兰一眼,意味深长地说。

小兰接口说:“还是先解释下你的疑惑吧, 你那段代码的输出应该是‘dog is eating’ , 而不是 ‘dog 正在吃东西’”

小王子说: “这我猜到了, 我就是不理解一个函数(createEatFunction)都执行完了, 为什么它的变量(desc)还能被 后面执行的函数(eat)来使用。”

“要不说你的java毒中的很深啊, 你换个角度想想,局部变量在函数执行完以后还可以被访问, 那它肯定不能存在于你说的那个什么java栈帧中。” 小兰说。

“那它放在那里?”

“在JavaScript 当中,有个作用域链(scope chain)的东西,它定义了一个函数激活执行的时候去哪儿找变量的值,  比如eat函数的作用域链是这样的:”

0?wx_fmt=png

(微信公众号码农翻身注: 此图只是示意图,并不严谨,例如没有表达出Activation object, Variable Object等概念)

小王子看着这个图,马上就明白了,这个eat函数没有定义desc 这个变量, 所以就沿着链去查找, 在createEatFunction作用域去查找,如果还找不到,就到global 作用域中查找......

这个例子中,在createEatFunction的作用域中有定义,于是就直接使用了。

“可是 ”小王子不服气地说  “createEatFunction 已经执行完了, 难道它的desc 变量不删除吗?”

“那肯定不能删除喽”  小兰说  “这里和你熟悉的java 有个重要的不同, 当你执行creatEatFunction的时候, eat函数才会被创建出来,此时eat函数就会把外部函数的作用域链记录下来(其中包含desc=' is eating'),以便执行时使用”

“奥,这个作用域是在函数创建时刻发生关联的,而不是运行时刻”

“没错, 这叫做静态作用域(static scope),或者叫词法作用域(lexical scope)。当eat函数被激活执行,就可以在createEatFuncction中找到desc的值,而不是在全局中找到desc的值。 ”  小兰接着说,“我再给你看个例子, 你就理解这个静态作用域了”

0?wx_fmt=png

小王子说: “这段代码的输出应该是2 啊, 还有什么可说的,哦,不对不对,应该输出1, 静态作用域!   函数foo在创建的那一刻, 已经确定了它会和包含x=1的全局作用域关联 , 所以在运行的时候也只会从全局作用域查找,而不是从bar 函数的作用域中找x ”

“看来你已经Get到了, 这个静态作用域是实现闭包的一个必需条件, 你听说过闭包吧?”

小王子说: “我听父王说过,但是不知道怎么回事....”

小王子说漏了嘴,赶紧打住。

小兰像没有听到一样,继续讲闭包:“闭包在JavaScript当中就是一个函数和以静态方式存储的父作用域的一个集合体,通过这个集合体,一个函数就可以访问外部函数的变量了。 ”

“所以eat函数就可以访问外部函数的变量了!  闭包这个名称有点古怪,不过背后的概念还是比较清晰的” 小王子赶紧说。

4

 尾声

“咳咳,小莱你够了。客人都被你吓到了。”这时,在旁边默默看着的邱大教主说话了。

经过这一番交谈,小王子震惊于函数式的独特之处,尤其是和Java帝国的不同。

不过毕竟是皇族,阅历丰富,他还是悟出了一点门道,“我大概明白了一点,由于 JavaScript 是动态类型,其实无论是函数还是对象,在这里都可以做为一个值来传递。函数式里面偏向对值直接进行处理,通过对这些值的传递和组合,就可以组装实现更高级的功能。”

“不错不错,我看你这位朋友的来头可不一般啊,新加入的信徒大多都经过漫长的适应期才能理解,他却立即悟出这些道理来。”邱大教主对小王子赞赏有加,或许以他的智慧已经识破了小王子的身份。

“不不不,还是因为小兰妹妹讲的好啊。”小王子脸红的说道。

“这还不是多亏了我们的原型才能自由灵活的实现各种编程范式么。”眼镜大哥也参合了起来。

“哈哈哈,你又在自夸了。”

“来,说了这么多 eat,不说了,吃菜吃菜~”

看来编程世界上还有这么多种形态,小王子下次要去哪里,又会见识到怎样的东西呢?或许也能给他的 Java 帝国带回一些新鲜的血液?

登场人物名:

小兰 == lambda

邱大教主 == 阿隆佐.丘齐(Alonzo Church)  Lambda演算发明人

你看到的只是冰山一角, 更多精彩文章,请移步《码农翻身2016文章精华》或者《码农翻身2017上半年文章精华

有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 3340792577


码农翻身

用故事讲述技术

0.jpeg

内容概要:本文围绕列车-轨道-桥梁交互仿真研究,基于Matlab平台构建数值模型,系统分析列车运行过程中轨道与桥梁结构间的动态相互作用机制。研究涵盖多体动力学建模、耦合系统运动方程求解、边界条件设定及仿真结果可视化等关键环节,重点揭示高速行车条件下基础设施的振动传递规律与力学响应特征。该仿真方法可有效评估结构安全性、舒适性指标及疲劳寿命,为轨道交通工程的设计优化与运维管理提供理论支撑和技术路径。文中配套提供了完整的Matlab代码实现方案及操作说明,便于用户复现、验证和拓展相关研究。; 适合人群:具备Matlab编程基础和结构动力学、车辆动力学等相关专业知识的研究生、科研人员及从事铁路工程、桥梁工程与交通系统安全评估的工程技术人才,尤其适合开展轨道交通耦合振动课题的研究者。; 使用场景及目标:①用于高校与科研机构进行列车-轨道-桥梁耦合系统动力学特性的教学演示与科学研究;②支撑高速铁路桥梁的设计优化、运营安全性评估与减振降噪方案验证;③为复杂交通基础设施的多物理场耦合仿真提供建模思路与代码参考。; 阅读建议:建议读者结合所提供的Matlab代码逐模块深入研读,重点关注系统建模假设、质量-刚度-阻尼矩阵构建方法及数值积分算法的实现细节,同时可通过调整参数进行敏感性分析,进一步掌握仿真模型的适用范围与优化方向。
内容概要:本文系统研究了非线性薛定谔方程的物理信息神经网络(PINN)求解方法,提出一种将物理规律嵌入深度学习模型的科学计算新范式。通过构建全连接神经网络架构,将非线性薛定谔方程及其初始/边界条件作为损失函数的核心组成部分,实现了在无须大量标注数据的前提下对复值偏微分方程的高精度数值求解。该方法充分利用自动微分技术精确计算方程残差,有效融合了数据驱动与模型驱动的优势,在光学孤子传播、量子系统演化等典型场景中展现出优异的逼近能力与泛化性能。文中配套提供了完整的Python实现代码,涵盖网络搭建、损失定义、训练优化与结果可视化全流程。; 适合人群:具备Python编程能力与深度学习基础知识,熟悉偏微分方程理论及科学计算的理工科研究生、科研人员,以及从事光学、量子物理、流体力学等领域建模与仿真的工程技术人员。; 使用场景及目标:① 掌握PINN方法的基本原理与实现技巧;② 学习如何将复杂物理方程转化为可训练的神经网络损失项;③ 应用于非线性光学、玻色-爱因斯坦凝聚、水波动力学等问题的仿真与预测;④ 为相关科研课题提供可复现的算法原型与代码参考。; 阅读建议:建议读者结合所提供的Python代码进行动手实践,重点理解神经网络对微分算子的近似机制、损失函数的多任务加权策略以及训练过程中的超参数调优方法,进而可迁移至其他非线性偏微分方程的求解任务,拓展其在交叉学科中的应用边界。
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 微软推出的【AZ-900微软认证】是一项针对初学者的基础级云服务资格认证,其目的在于帮助学习者掌握云概念、微软Azure服务的运作机制以及云解决方案的核心知识。获得这一认证后,考生将能够清晰地理解云计算领域的基础术语、服务模式(包括IaaS、PaaS、SaaS等)以及这些服务在Azure平台上的实际应用方式。 在【必过考题】部分,我们可以观察到两个重点议题,它们分别聚焦于PaaS(平台即服务)的概念阐释和云成本的计算方式。 在第一个议题中,考生被要求辨别关于PaaS的正确性描述。PaaS平台提供了一个开发环境,但并不允许用户直接访问操作系统(Box 1: No)。比如,Azure Web Apps服务可以用来部署web应用,但用户无法直接管理虚拟机或IIS系统。另一方面,PaaS确实具备自动扩展的功能(Box 2: Yes),这表示可以根据实际需求自动增加负载均衡的虚拟机以支持web应用的运行。PaaS框架还为开发人员提供了构建和调整云端应用的工具,预置的应用组件能够有效缩短新应用的编程周期(Box 3: Yes)。 第二个议题同样关注云计算理念的理解,尤其强调IT支出从资本性支出(CapEx)向运营性支出(OpEx)的转型思想。传统的IT投资通常被视为CapEx,而云计算的按需付费机制使企业能够将这部分开支转化为OpEx,从而在财务规划上获得更大的自由度。 在为AZ-900考试做准备时,考生需要特别关注以下几个核心知识点: 1. **云服务模式**:深入理解IaaS(基础设施即服务)、PaaS和SaaS(软件即服务)之间的差异及其各自的应用情境。 2. **Azure服务*...
源码下载地址: https://pan.quark.cn/s/239a0d536a1e 依据所提供的文件资料,可以归纳出以下核心内容:由清华大学计算机系邓俊辉教授精心编纂的算法训练营题目合集,对于CSP(中国软件专业人才设计与创业大赛)及PAT(程序设计能力测试)这类编程竞赛具有极高的参考价值,堪称一份极具价值的参考资料。此类竞赛普遍对参赛者的算法功底和编程技巧提出严苛要求。该合集中的题目与算法领域紧密相连,其中包含了“最大红矩形”这一典型题目。所谓最大红矩形题目,其核心任务是针对一个由红色与绿色方格构成的棋盘,寻觅出最大的纯红矩形区域。要攻克这一问题,必须运用数据结构与算法的相关知识,特别是栈这一数据结构的应用。 “最大红矩形”问题能够被抽象转化为“直方图最大面积”问题。具体转化方法是将棋盘的每一列视为一个独立的直方图单元,其中红色方格的贡献体现为当前位置与前一个绿色方格所在行数的差值,从而保证每个直方图的基宽恒定为1。随后,借助扫描直方图的技术手段来探寻最大矩形面积。这一过程需要对每个直方图进行系统性遍历,并利用栈来记录各直方图的下标信息。一旦检测到当前直方图的高度小于栈顶元素所记录的高度,则意味着遭遇了一个“高点”,此时需计算以该“高点”为右边界条件的最大矩形面积。 在编程实践环节,必须高度关注栈的操作细节,以及如何精确地初始化和操纵栈来应对直方图问题。代码实现中,通常配置两个栈,一个用于储存直方图的高度值,另一个用于标记直方图的下标位置。当面对新高度时,需审慎判断当前高度与栈顶高度的相对关系,并据此抉择是执行入栈操作还是计算面积。针对“低点”(即当前高度小于栈顶),应直接将当前高度纳入栈中;而对于“高点”,则需执行弹出栈顶元素的操作,并基于该栈顶元素的高...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值