父子页面之间跨域通信的方法

由于同源策略的限制,JavaScript跨域的问题,一直是一个比较棘手的问题,为了解决页面之间的跨域通信,大家煞费苦心,研究了各种跨域方案。之前也有小网同学分享过一篇“跨域,不再纠结” 开始照着尝试时还是有些不够明白的地方,深入了解之后,这里给大家补充一点更具体的做法。 先来看看哪些情况下才存在跨域的问题: 其中编号6、7两种情况同属于主域名相同的情况,可以设置domain来解决问题,今天就不讨论这种情况了。 对于其他跨域通信的问题,我想又可以分成两类: 其一(第一种情况)是a.com下面的a.js试图请求b.com下某个接口时产生的跨域问题。 其二(第二种情况)是当a.com与b.com下面的页面成父子页面关系时试图互相通信时产生的跨域问题,典型的应用场景如a.com/a.html使用iframe内嵌了b.com/b.html,大家都知道a.html内的js脚本试图访问b.html时是会被拒绝的,反之亦然。 第一种情况,目前主流的方案是JSONP,高版本浏览器支持html5的话,还可以使用XHR2支持跨域通信的新特性。 第二种情况,目前主要是通过代理页面或者使用postMessageAPI来做,这也是今天要讨论的话题。 第二种情况,有这样一些类似的案例:a.com/a.html使用iframe内嵌了b.com/b.html,现在希望iframe的高度能自动适应b.html的高度,使iframe不要出现滚动条。我们都知道跨域了,a.html是没办法直接读取到b.html的高度的,b.html也没办法把自己的高度告诉a.html。 直接说可以用代理页面的方法搞定这个问题吧,但是怎么代理法,先来看下面这张图: b.html与a.html是不能直接通信的。我们可以在b.html下面再iframe内嵌一个proxy.html页面,因为这个页面是放在a.com下面的,与a.html同域,所以它其实是可以和a.html直接通信的,假如a.html里面有定义一个方法_callback,在proxy.html可以直接top._callback()调用它。但是b.html本身和proxy.html也是不能直接通信的,所谓代理页面的桥梁作用怎么实现呢? b.html内嵌proxy.html是通过一段类似下面这样的代码: 这个iframe的src属性b.html是有权限控制的。如果它把src设置成a.com/proxy.html?args=XXX,也就是给url加一个查询字符串,proxy.html内的js是可以读取到的。对的,这个url的查询字符串就是b.html和proxy.html之间通信的桥梁,美中不足的是每次通信都要重写一次url造成一次网络请求,这有时会对服务器及页面的运行效率产生很大的影响。同时由于参数是通过url来传递的,会有长度和数据类型的限制,搜集的资料显示: IE浏览器对URL的长度现限制为2048字节。 360极速浏览器对URL的长度限制为2118字节。 Firefox(Browser)对URL的长度限制为65536字节。 Safari(Browser)对URL的长度限制为80000字节。 Opera(Browser)对URL的长度限制为190000字节。 Google(chrome)对URL的长度限制为8182字节。 上面的方法,通过迂回战术实现了b.html跟a.html通信,但是倒过来,a.html怎么跟b.html通信呢?嵌入在b.html里面的proxy.html可以用top快速的联系上a.html,但是要想让a.html找到proxy.html就不容易了,夹在中间的 b.html生生把它们分开了,a.html没法让b.html去找到proxy.html然后返回给它。只能采用更迂回的战术了。 顺着前面b.html到a.html的通信过程,逆向的想一下,虽然a.html没有办法主动找到proxy.html,但是proxy.html可以反过来告诉a.html它在哪里: 在proxy.html加这么一段脚本: 也就是必须由proxy.html先主动发送一个消息给a.html,a.html得到proxy.html页面window的引用,就可以反过来向它发送请求了。 现在a.html可以把消息发给proxy.html了,但是proxy.html怎么把消息转送到b.html?似乎这才是难点,因为它们之间才真正有着“跨域”这一道鸿沟。 这回我们不再用前面那个iframe内嵌代理页面的方法再在proxy.html内嵌一个b.com下面的代理页面了,这样实在会给人感觉嵌的太深了,四层。但是为了跨越这道鸿沟,b.com下面也加一个代理页面是免不的。不过现在我们要利用一下window.name。window.name有一个特性,就是页面在同一个浏览器窗口(标签页)中跳转时,它一直存在而且值不会改变。比如我们在a.html中设置了window.name=”a”,然后location.href=”http://b.com/b.html”跳转后,b.html可以读取window.name的值为”a”;而且window.name的值长度一般可以到达2M,ie和firefox甚至可以达到32M,这样的存储容量,足够利用起来做跨域的数据传递了。好吧,我们现在要做的就是当proxy.html拿到a.html发送过来的数据后把这个数据写入window.name中,然后跳转到b.com下面的代理页面,我们这里假设是bproxy.html。bproxy.html读取到window.name值后,通知给它父页面b.html就简单了。我们再来看这个过程可以用图大概示意一下: 图例中绿色的双向箭头表示可以通信,橙色的双向箭头表示不能直接通信。 最后我们简单看一下双向通信的实测效果: b.html每次加载的时候都先给a.html发一个”连接请求”,让a.html可以找到proxy.html。所以页面第一次加载的时候会产生三个请求: 每次b.html向a.html发送消息的时候会产生一个请求: 每次a.html向b.html发送消息的时候会产生两个请求,其中一个是a.com/proxy.html向b.com/bproxy.html跳转产生的,另一个是b.html重新向a.html发起“连接请求”时产生的: 最后简单看一下实测的几个测试页面代码: 代码片段一,a.com/a.html: 代码片段二,a.com/proxy.html: 代码片段三,b.com/b.html: 代码片段四,b.com/bproxy.html: 好吧,现在我必须把话锋调转一下了。前面讲的这么多,也只是抛出来一些之前我们可能会采用的跨域通信方法,事实上代理页面、url传参数和window.name、甚至还有一些利用url的hash值的跨域传值方法,都能百度到不少相关资料。但它们都逃不开代理页面,也就不可避免的要产生网络请求,而事实上这并不是我们的本意,我们原本希望它们能够直接在客户端通信,避免不必要的网络请求开销——这些开销,在访问量超大的站点可能会对服务器产生相当大的压力。那么,有没有更完美一点的替代方案呢? 必须给大家推荐postMessage。postMessage 正是为了满足一些合理的、不同站点之间的内容能在浏览器端进行交互的需求而设计的。利用postMessage API实现跨域通信非常简单,我们直接看一下实例的代码: 代码片段五,A.com/a.html: 代码片段六,b.com/b.html: 代码的关键是message事件是一个拥有data(数据)和origin(来源)属性的DOM事件。data属性是发送的实际数据,origin属性是发送来源。Origin属性很关键,有了这个属性,接收方可以轻易的忽略掉来自不可信源的消息,也就能有效避免跨域通信这个开口给我们的源安全带来的隐患。接口很强大,所以代码很简单。我们可以抓包看一下,这个通信过程完全是在浏览器端的,没有产生任何的网络请求。同时这个接口目前已经得到了绝大多数浏览器的支持,包括IE8及以上版本,参见下面的图表: 但是为了覆盖ie6等低版本浏览器,我们完整的方案里面还是要包含一下兼容代码,就是最开始介绍的代理页面的方法了,但必须是以postMessage为主,这样即便最后会有某些浏览器因为这种通信产生一些网络请求,比例也是非常低的了。 作者: lyndon 来源: 腾讯大讲堂 发布时间: 2014-08-08 08:59 原文链接

举国之力完成与Windows,Linux并驾齐驱的国产操作系统是否可行?

回答者:shotgun 我搞信息安全的,所以只评价信息安全部分,举国之力纠集了数万程序员开发出来“自主可控”的操作系统。 然后,有千分之一的程序员被某些外国情报部门买通了,“自主可控”何在? 有百分之一的程序员没有安全编程意识,留下了各种安全漏洞,“自主可控”何在? 有十分之一的分包公司偷偷用开源的项目代码交差,“自主可控”何在? 回答者:北极,Simple Gifts 我觉得很多人有“国产情结”,知乎上每隔一段时间就有人会问国产操作系统的问题,比如: 开发一个 Windows 级别的操作系统难度有多大? – 科技 如何看待中科院联合上海联彤发布的「中国操作系统」(COS)? – Linux 中国那么多人才为什么不做自己国家的操作系统,而用美国的Windows ? – 操作系统 那么多国家“国产操作系统”为什么都要用linux内核? – 互联网 在可见的将来,我们能看到国产操作系统崛起吗? – 操作系统 如何建设国产操作系统生态圈? – Linux 作为国人,应该如何看待国产操作系统(桌面、移动)的努力? – 谷歌 (Google) 如何评价倪光南院士希望将Windows操应用软件移植到国产操作系统上? – 互联网 现如今成熟的操作系统市场,国产操作系统还有没有突围的可能? – 手机 为什么没有企业出来开发一个国产的手机操作系统? – 移动互联网 我国有国产的电脑操作系统吗? – 国产操作系统 类似的还有国产CPU之类的问题,我不一一列举。 既然题主问的是“举国之力”,那么我认为也是“可能”的,但我不认为“可行”。 先说为什么是可能的: 如果不考虑市场商业价值,那么投入大量的钱就可以了,操作系统开发,应该算是“体力密集型”的工作。 以Windows 2000为例,内核和内核周边的部分约1000万行代码(网上有泄露的,下一份就可以统计出来/Linux 2.6.x差不多也是这个数),驱动部分大概是内核部分的十几倍,上层应用不详,不过这已经不是最困难的部分了。 一个操作系统工程师一年实际完成的代码量大概约为1000行,考虑到操作系统开发周期接近十年,包括前期预研、需求分析、总体设计等等,所以需要投入的人力资源大概是:10000*10人/年(注:这里算出来是一亿行,因为考虑的是代码重写等因素),再加上一半左右的测试人员、配置管理员、技术支持人员等, 差不多是200000人/年。北上广普通码农的工资水平大概是20~40万/年,以40万计算,这些人工作十年,在不涨工资的情况下是40*200000万元的工资支出,大概800亿。 考虑到企业还要正常运行,工资支出只是其中的一少部分,但我们假设IT公司其它方面支出少,假设工资支出占1/3(注:国内企业平均水平大概是1/4),又因为企业实际负担工资大概是税前工资的1.3~1.5倍(各种社保什么的),所以开发一个操作系统大概需要投入:800*3*1.5=3600亿。 […]

node.js 初体验

PS: ~ 此篇文章的进阶内容在为《Nodejs初阶之express》   ~ 2014/09/24 更新《Express 4.X 启航指南》   欢迎阅读和评论:)   最近写的文章收到许多朋友的反馈,感谢大家的支持和建议,让我对坚持写博客充满热情,一个月一篇文章确实有点少,所以以后尽力多做分享,做好的分享,希望能对朋友们有用。   到新公司的这段时间学到了很多新东西,有好多东西需要去总结去探索,不过事情得一件一件来,今天咱们先从Node开始。注:以后出现的Node即node.js。 先搞点前戏热热场 – 为什么写这篇文章:   1.前段时间单位有新项目启动,服务端要做的工作不多也不算麻烦,就是处理一些中间层的服务,而且我们团队里面个个都会JavaScript,领导就决定试试服务器端的JavaScript,结果本人有幸被派去研究了几天Node,怀着鸡冻的心情开始了node.js的篇章,这篇文章也就是为这几天研究的总结。   2.一个JavaScript工程师如果没听过node.js那么我想你是不是错过了什么,每个优秀的前端工程师都有必要去了解后台处理流程,那么如果又能从JavaScript出发,岂不是一件很美妙的事么。   3.互联网的火热使得JavaScript风光无限,且服务端的JavaScript也并不是什么新技术了,相关的框架也有不少,只是node.js的成功让他爆发式的出现在我们的视线中,让很多前端工程师看到了从前端写到后端的另一种实现希望。注:node.js 是一个允许开发人员使用 JavaScript 语言编写服务器端代码的框架。   4.今年8月曾在某大公司最后一轮(第五轮)的面试被问到Node.js的问题,相对应的回答那是相当之糟糕,结果怎样你们懂的,感觉这个问题是导致没有通过的关键点之一…那家公司是我在读大学的时候就无比向往的公司,现在回想起那次经历和过程,谈不上惋惜,毕竟我真的尽力了 – 其实这篇文章更多的也是为了完成自己一个小小的心结…好吧,又扯远了。   5.欢迎各种转载,不过请注明出处,谢谢。 Node是个啥?   写个东西还是尽量面面俱到吧,所以有关基本概念的东西我也从网上选择性的拿了些下来,有些地方针对自己的理解有所改动,对这些概念性的东西有过了解的可选择跳过这段。   1.Node 是一个服务器端 JavaScript 解释器,可是真的以为JavaScript不错的同学学习Node就能轻松拿下,那么你就错了,总结:水深不深我还不知道,不过确实不浅。   2.Node 的目标是帮助程序员构建高度可伸缩的应用程序,编写能够处理数万条同时连接到一个物理机的连接代码。处理高并发和异步I/O是Node受到开发人员的关注的原因之一。   3.Node 本身运行Google V8 JavaScript引擎,所以速度和性能非常好,看chrome就知道,而且Node对其封装的同时还改进了其处理二进制数据的能力。因此,Node不仅仅简单的使用了V8,还对其进行了优化,使其在各种环境下更加给力。(什么是V8 JavaScript 引擎?请“百度知道”)   4.第三方的扩展和模块在Node的使用中起到重要的作用。下面也会介绍下载npm,npm就是模块的管理工具,用它安装各种 Node 的软件包(如express,redis等)并发布自己为Node写的软件包 。 安装Node   在这简单说说在window7和linux两种环境下安装Node。安装的时候一定要注意Python的版本,多次因为Python版本的问题安装失败,建议2.6+的版本,低版本会出现Node安装错误,查询Python版本可在终端中输入:pyhton -v   1.先介绍linux下的安装吧,Node在Linux环境下的安装和使用都非常方便,建议在Linux下运行Node,^_^…我使用的是Ubuntu11.04    a.安装依赖包:50-100kb/s大概每个包一分钟就能下载安装完成   sudo apt-get install g++ curl libssl-dev apache2-utils   sudo […]

apt-get指令的autoclean,clean,autoremove的区别

下面总结一下有关apt-get的常用但容易混淆的指令: apt-get autoclean: 如果你的硬盘空间不大的话,可以定期运行这个程序,将已经删除了的软件包的.deb安装文件从硬盘中删除掉。如果你仍然需要硬盘空间的话,可以试试apt-get clean,这会把你已安装的软件包的安装包也删除掉,当然多数情况下这些包没什么用了,因此这是个为硬盘腾地方的好办法。 apt-get clean: 类似上面的命令,但它删除包缓存中的所有包。这是个很好的做法,因为多数情况下这些包没有用了。但如果你是拨号上网的话,就得重新考虑了。 apt-get autoremove: 删除为了满足其他软件包的依赖而安装的,但现在不再需要的软件包。 其它: apt-get remove 软件包名称: 删除已安装的软件包(保留配置文件)。 apt-get –purge remove 软件包名称: 删除已安装包(不保留配置文件)。

程序员风格的修真小说

终有一天我手中的编译器将成为我灵魂的一部分,这世界在我的眼中将被代码重构,我将看到山川无尽银河无垠都汇成二进制的数字河流,过往英雄都在我脑海眼前一一浮现,而我听到无数码农跪倒在我的程序面前呼喊。 他们叫我代码之神。 到那个时候,我想我一定可以找回你。 一丶 这是一个属于代码的修真世界。 这世界里的每一个人,每一个东西,包括高山大海,刀剑风云,其本质都是一串数字流。 打个比方,如果你知道一块石头的内部数据结构,并且参透其中玄妙,你就能用程序改变它的一切。如果能参透自身这一个复杂的操作系统,就能重新编码自己,获得更大的能力。 所以你的程序水平的高低,决定了你的牛逼程度。 我们这些修真者,都叫程序员。 有人的地方,就有江湖。有江湖的地方,就有代码。 刚入门的时候,师傅跟我说,我们程序员修的,是一份境界。短短几句的代码里,要有最完美的逻辑,跟最精妙的算法。这本《算法导论》,你暂且拿去研修。 我们程序员,外修语言,内修算法。以数据为根,算天算地算自己。 听起来真的好酷。 但这个江湖,并不平静。几大门派,上有微软谷歌,下至百度阿里,每个门派风格迥异,暗地里都有无数摩擦。 师傅说,我们知乎派,理论见长。三大软狗、哦不,三大软神坐镇,还有无数默默搬砖的程序员,如今也算在乱世立稳了脚跟。 师傅还说,江湖虽乱,但我们修真之人,说到底还是要修自身,恩恩怨怨都是过眼云烟,自身境界才是万源之本。 我点了点头。 师傅又拍了拍我的小脑瓜,慈祥一笑。他说,如果下次天涯派那群人还过来闹事,我们一定要秉承我们的自身理念来处理他们。 我知道了,我回师傅道,我跟刘看山一定会好言相劝,么么他们个哒哒。 不。师傅转身过来,鹰眼之中精光毕露,胡须颤动的嘴唇之中,一个字一个字地吐出来。 灰飞烟灭,一个不留。 二丶 自我开始修真起,我练的便是C++的功夫。 虽然大师兄跟我说过,不管你学的事什么语言,都是殊途同归。我们修真之人,都不要在乎这些差别,要参透的是程序的本质。 然后他又说,不过,用Java的都是傻逼。 大师兄跟我一样,C++的功底深厚,面向对象的各种技能用的精通,只是可惜,他还没有对象。 我永远忘不了那一天,我们知乎派的山门被一众凶恶之徒所踏破,山石飞舞,浮尘弥漫,门派服务器都暂停运行。 大师兄坐在大殿房顶之上,喝一壶陈年的竹叶青。姿势潇洒,闷骚至极。 是他们,谁都知道,天涯派不止一次来闹事。 我从来没见过大师兄出过手。 天涯派的来人,在烟尘之中现出数个魁梧身影,还夹带了一声大笑和开场白: 哈哈哈哈哈哈哈,知乎派,hello world! 大师兄的眼皮都没有眨一下。 他的右手之上字符串环流浮现,左手抬起酒壶一饮而尽,右手对着虚空就是一指,那一串字符都消散在空气之中。 刹那间风云突变,一阵狂风似有形一般,沿着大师兄所指方向似一条狂龙横冲了过去,一个照面便将几个大汉吹得撞出山门之外,摔了个七荤八素。 那一霎我屏住呼吸。 大师兄整了整风中凌乱的发型,说,这就叫快速傅里叶变换,将风压重新编码,所到之处,寸草不生。你们都还在解码自己,我已经开始操纵世界——天涯跟知乎,就是在这里的差距,懂? 都他妈的给老子滚。 从那一刻开始,我才知道,有些人已经可以编码这个世界本身。 这才是叫修真。 三丶 在知乎里修行了十年,师傅说我可以下山了。 我已经熟知C++的基本技能,但师傅告诫我千万不要说自己精通C++。他说,这世界上,没有人可以说,他已经精通C++,所以即算你装逼的时候,也要装得像个样子。比如,你可以说你精通java。 我点头称是。 这十年来,我每日苦读《算法导论》和《C++ primer》,精通数据库原理跟操作系统,同龄人之中无人是我敌手,自认为天下哪里都可去得。 是为年轻气盛,是为势不可挡。 我下山之后,连连在江湖之中,将一些有一点点小名气的程序员斩于马下。 他们之中,有些是根基不稳,有些是反应迟钝,有些是冥顽不灵,有些是莽撞愚蠢。 当然,我现在说起来是云淡风轻,那是因为我在装逼。其实也经过了一番苦战,有过一些辛酸。终于有一天,我将天下程序员排行榜第一千位的马特给击败,成功登上天下程序员排行榜。 马特这个程序员,有一些狡猾。他占据第一千位,已经很久没有变过。他精通计算机图形学,经常使用一些幻境击败对手。他比他上面几位更加难缠,所以通常没有人会去挑战他。因为你赢了他,也只能到第一千位,还不如去挑战他上面的更划算一些。 可惜他遇到了我,因为我比他,更精通计算机图形学。 于是这也成为一个不大不小的消息,在江湖里传播,从此我有了一个外号,他们叫我杀马特。 俗话说树大招风,人不能太出名。 […]

php判断字符串长度 isset()速度比strlen()更快

在php里当需要判断一个字符串长度时,我们首先想到的是strlen()函数,不错,strlen()返回的就是字符串的长度,这样使用没有任何问题。不过,如果要从php程序优化的角度来看,使用strlen()判断字符串长度未免是最好的写法。 程序的优化,需要经验的积累,那是知识的沉淀,厚积薄发的体现。 有经验的程序员发现,php判断字符串长度,使用isset()在速度上比strlen()更快,执行效率更高。 因此,今天就分析一下strlen()和isset()这两个函数。 PHP strlen() 函数 定义和用法 strlen() 函数返回字符串的长度。 语法 strlen(string) 参数:string 描述:必需。规定要检查的字符串。 实例 <?php echo strlen(“Hello world!”); ?> 输出: 12 PHP isset() 函数 isset函数是检测变量是否设置。 格式: bool isset ( mixed var [, mixed var [, …]] ) 返回值: 若变量不存在则返回 FALSE 若变量存在且其值为NULL,也返回 FALSE 若变量存在且值不为NULL,则返回 TURE 同时检查多个变量时,每个单项都符合上一条要求时才返回 TRUE,否则结果为 FALSE 如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL […]

不要使用(include/require)_once

最近关于apc.include_once_override的去留, 我们做了几次讨论, 这个APC的配置项一直一来就没有被很好的实现过. 在这里, 我想和大家在此分享下, 这个问题的原因, 以及对我们的一些启示. 关于使用include还是include_once(以下,都包含require_once), 这个讨论很长了, 结论也一直有, 就是尽量使用include, 而不是include_once, 以前最多的理由的是, include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载. 诚然, 这个理由是对的, 不过, 我今天要说的, 是另外一个的原因. 我们知道, PHP去判断一个文件是否被加载, 是需要得到这个文件的opened_path的, 意思是说, 比如: <?php set_include_path(“/tmp/:/tmp2/”); include_once(“2.php”); ?> 当PHP看到include_once “2.php”的时候, 他并不知道这个文件的实际路径是什么, 也就无法从已加载的文件列表去判断是否已经加载, 所以在include_once的实现中, 会首先尝试解析这个文件的真实路径(对于普通文件这个解析仅仅类似是检查getcwd和文件路径, 所以如果是相对路径, 一般是不会成功), 如果解析成功, 则查找EG(include_files), 如果存在则说明包含过了, 返回, 否则open这个文件, 从而得到这个文件的opened_path. 比如上面的例子, 这个文件存在于 “/tmp2/2.php”. 然后, 得到了这个opened_path以后, PHP去已加载的文件列表去查找, 是否已经包含, 如果没有包含, 那么就直接compile, 不再需要open file了. […]

谈谈Javascript中的void操作符

由于JS表达式偏啰嗦,于是最近便开始采用Coffeescript来减轻负担。举个栗子,当我想取屋子里的第一条dog时,首先要判断house对象是否存在,然后再判断house.dogs是否存在,最后取house.dogs[0]。在JS需要这么写 1 2 var dog = (typeof house !== ‘undefined &amp;&amp; house !== null) &amp;&amp; house.dogs &amp;&amp; house.dogs[0] 在Coffee中,我只需要这么写: 1 dog = house?.dogs?[0]; 写到这里,读者会问,这跟标题《Javascript中的void》有一毛钱关系?Coffee的本质就是JS,之所以Coffee能工作的很好,是因为它生成出了高效而且健壮的JS代码,我们可以看看它的生成结果。 1 2 3 4 5 var dog, _ref; dog = typeof house !== “undefined” &amp;&amp; house !== null ? (_ref = house.dogs) != null ? _ref[0] : void 0 : void […]

人情债的博弈:为何会有“中国式让梨”?

你也许已经看过了漫画作者@笛子Ocarina 的“中国式让梨”。 这是一场典型的围绕人情债而展开的仪式性争斗。但为何会有这样的争斗呢?博弈理论对这样的现象有一个尝试性的解释。 从重复囚徒博弈到人情交换 今天我帮你个忙,明天你帮我一个。日常所说的人情,说白了就是这样的互惠行为。我牺牲自己的利益,为你带来更大的利益,指望你将来能为我做同样的事情,最终双方一起受益。 为啥我不担心你拿了好处跑路呢?因为我预测我们在未来还会碰面,双方的互动还会持续下去。形成长久的合作关系,最终都会受益更大;就算你真的打算为眼前利益背叛我,你也得掂量一下来自社会的谴责——这世界上可不止你我两个人。 就这个逻辑追根溯源,可以回到所有合作理论的基石:重复囚徒困境。如果你我只相遇一次,此后再也没有任何交集,那么纯为自己眼下利益着想是正常的,双方都会选择背叛,哪怕最终结果是双输。但是如果相遇次数很多,优势策略就变成了“回报好人、惩罚坏人”。这个思路下最著名的策略莫过于“一报还一报”(TFT)——你上一轮怎么对我,我这一轮就怎么回敬。其实它并不是在所有场合下都最优,但各种最优策略里都有它的影子。 而博弈论里的“人情交换”(Favor trading),则是在此基础上做了修正:双方不再是同时打出合作或者背叛,而是每次只有一方能够行动,善举是否得到回报要等到下一轮才知晓。这引入了一些额外的变数,但是大多数情况下,主流的行为依然是长期的合作互惠。一个存在“人情”概念的社会,其实是更好的。 孔融让梨:一个毫无益处的人情 现在问题来了。无论是博弈论上分析的人情,还是我们日常生活中感受到的大部分人情,都是代价小收益大的。朋友帮你个忙,你再帮回去,结果是双方都得到了好处,总体上对社会也有益。 可是,挑梨是一个“零和博弈”。一共两个梨,一方拿了大的,另一方就必然得拿小的,当两个孩子 都很喜欢梨的时候,代价和收益正好相当。在让梨的时候,无论双方交换多少次人情,都不会变得更好;就让梨本身而言,没有双赢也没有双输。照理说,这样的东西并没有多少积极效果。 只是,现实生活中没有人真的会去用博弈论计算每一次交易。就算这是一个毫无益处的人情,在我们看来,这也是人情。 其实一个梨子而已并没有什么要紧的,但是文化传统不这么认为。 人情的大与小 人情虽然好用,但记人情可是件负担很大的活儿。毕竟这东西不能定量,不能像记账本那样明明白白写下来。而且,正如我们不愿意欠债一样,欠人情债——尤其是并不算亲密无间的亲戚的债——也是让人不自在的事情。(因为传统中国家庭结构的原因,这样的债还偏偏很容易欠下。) 要怎么避免脑子记的人情太多最终炸掉?原则人人都懂,抓大放小嘛。大的人情记住,小的过去就过去了。但是,多大算大多小算小,不同人和不同文化的判断都是不一样的。而出于某种原因(不知是否和儒家经典里反复强调的禅让有关),“谦让”在中国传统文化里,被划分成了大事儿。就算谦让的只是梨子这种微不足道的小东西,挂上了这个名头也是大事儿。 又是大事儿,又不想欠人情,双方互不相让,眼看就要僵持下去,怎么办?只好靠仪式性斗争找台阶下了。 仪式的意义 有一个广为流传的说法:只有人会伤害同类,动物不会。这当然是无稽之谈,动物攻击、杀死甚至吃掉同类的场景比起人只多不少;但在一种场合下,动物是的确不会做出过分举动的,那就是仪式性斗争。 仪式性斗争的理论的原型是胆小鬼博弈,在此基础上经过了演化博弈论的改良。它假定在和实力相当的敌方对抗的时候,你可以选择往死里打,可以选择拖时间,也可以选择认输。理论推算和计算机模拟表明,大多数情况下这样的斗争结局是双方一起拖时间,最终一方挑个合适的时机或者借口,在形式上认输,而实际上默认打成接近平手。这样不但造成的损失最小,而且也最大程度地保全了面子——或者,在让梨的例子里,最大程度地减小了人情债。 当然,在让梨这个例子里,梨子实在是微不足道,输了也没有什么了不起;但还是那个问题:我们的传统文化认为这是大事儿,我们也只好按照大事儿去对待它了。 是道德在绑架,还是人在绑架? 人情往来,在原则上是没有错的;让梨虽说是小题大做,但后果也不过是耽误时间而已。我们真正反感的,是它以最极端的方式展现了道德上的虚伪:明明是在算计,却偏要装作礼貌。 所幸,总的来说道德并没有这么糟糕。在博弈论的模拟里,参赛的各方是程序,它们自己并没有在算计,是反复的博弈过程剔除了表现欠佳的程序,从而实现了算计的效果——这就像马蹄子很适合奔跑,但马自己对此一无所知一样。诚然,人类个体能算计,但多数人在多数时候还是没在算的;概率上讲,你能看到的绝大部分道德行为,其主体都是简单而真心地相信它好,而不是经过了周密的利弊分析。再说,动机又不是道德的全部,很多时候只要结果是好的,我们也不会去过问动机。 但是对于我来说更加可怕的是,这幅漫画展现的让梨场景是一个典型的双重绑架——古旧的文化传统绑架了成年人,成年人又带着传统继续绑架下一代。社会时时刻刻都在改变,道德标准也应该跟着社会的变化而前进,然而现实中传统的力量却总是在拖后腿;相信两千年前的古人能够完美指导今天的社会规范,和相信他们能完美指导今天的科学、技术、医疗、经济……是一样荒谬的,可是总会有人这么相信。更加糟糕的是,这些人还在利用自己的权力和地位——无论是社会上的还是家庭中的——去把这些想法强加给下一代人。 因此,虽然一个梨真的只是完全无足轻重的小事儿,我还是想说,让梨这种事情,去死吧。

js中function参数默认值

–在dreamweaver做网站时,函数定义是在一个*.js文件中,其中定义了一个func,有四个参数,function func(string1,url,flag,icon),然后在另一个asp中调用它func(a,b),那flag和icon的值是什么,怎么定义默认值?谢谢! –默认值应该是 undefined 在函数内预设数可以用 arguments[i] i就是你参数的位置 第一个为0 所以要设定 flag 的默认值 则可以这么写 function func(string1,url,flag,icon){ if(!arguments[2]) flag = “123”; if(!arguments[3]) icon = “456”; } 你试试 应该是这样 ——————————————————————————– 今天遇到一个问题,需要调用一个JS函数,想在函数中给它一个默认参数,以为跟其他语言一样。 <script> function test(id=0){ alert(id); } </script> <input type=”button” value=”test” onclick=”test()”> 运行结果报错,JS中不能这样传默认参数,上网查了一下,可以借助于arguments 实参数组,参考下例:   <script> function test(a){ var b=arguments[1]?arguments[1]:50 return a+’:’+b } alert(test(5)) alert(test(5,9)) </script> 跟其他语言的一点小区别。。 –var b=arguments[1]?arguments[1]:50 还可以写做: […]