2015年2月10日星期二

阮一峰的网络日志

阮一峰的网络日志


JavaScript 有多灵活?

Posted: 09 Feb 2015 10:53 PM PST

JavaScript 是一种灵活的语言,表达力极强,我来举一个例子,保证让很多人大吃一惊。

本文受到了 Kyle Simpson 的文章《Iterating ES6 Numbers》的启发。

首先,在 Number.prototype 对象上,部署一个 add 方法。

  Number.prototype.add = function (x) {    return this + x;  };  

上面代码为 Number 的实例定义了一个 add 方法。(如果你对这种写法不熟悉,建议先阅读我写的《JavaScript 面向对象编程》。)

由于 Number 的实例就是数值,在数值上调用某个方法,数值会自动转为实例对象,所以就得到了下面的结果。

  8['add'](2)  // 10  

上面代码中,调用方法之所以写成8['add'],而不是8.add,是因为数值后面的点,会被解释为小数点,而不是点运算符。

将数值放在圆括号中,就可以使用点运算符调用方法了。

  (8).add(2)  // 10  

其实,还有另一种写法。

  8..add(2)  // 10  

上面代码的第一个点解释为小数点,第二个点解释为点运算符。为了语义清晰起见,下面我统一采用圆括号的写法。

由于add方法返回的还是数值,所以可以链式运算。

  Number.prototype.subtract = function (x) {    return this - x;  };    (8).add(2).subtract(4)  // 6  

上面代码在Number对象的实例上部署了subtract方法,它可以与add方法链式调用。

如果使用方括号调用属性,写法会很古怪。

  8["add"](2)["subtract"](4)  // 6  

我们还可以部署更复杂的方法。

  Number.prototype.iterate = function () {    var result = [];    for (var i = 0; i <= this; i++) {      result.push(i);    }    return result;  };    (8).iterate()  // [0, 1, 2, 3, 4, 5, 6, 7, 8]  

上面代码在 Number 对象的原型上部署了 iterate 方法,可以将一个数值自动扩展为一个数组。

总之,现在我们可以在数值上直接调用方法了,但是后面一对圆括号看着有点碍眼,有没有可能去掉圆括号呢?也就是说,能不能将下面的表达式

  (8).double().square()  

写成另一种样子?

  (8).double.suqare  

这是可以做到的。

ES5规定,每个对象的属性都有一个取值方法get,用来自定义该属性的读取操作。

  Number.prototype = Object.defineProperty(    Number.prototype, "double", {      get: function (){return (this + this)}     }  );    Number.prototype =  Object.defineProperty(    Number.prototype, "square", {      get: function (){return (this * this)}     }  );  

上面代码在 Number.prototype 上定义了两个属性 double 和 square ,以及它们的取值方法 get 。

因此,在任一数值上,读取这两个属性,就可以写成下面的样子。

  (8).double.square  // 256  

也可以改用方括号运算符。

  8["double"]["square"]  // 256  

(完)

文档信息

2015年2月8日星期日

阮一峰的网络日志

阮一峰的网络日志


强类型 JavaScript 的解决方案

Posted: 07 Feb 2015 09:10 PM PST

JavaScript 是一种弱类型(或称动态类型)语言,即变量的类型是不确定的。

  x = 5; // 5  x = x + 'A'; // '5A'  

上面代码中,变量x起先是一个数值,后来是一个字符串,类型完全由当前的值决定,这就叫弱类型。

弱类型的好处是十分灵活,可以写出非常简洁的代码。但是,对于大型项目来说,强类型更有利,可以降低系统的复杂度,在编译时就发现类型错误,减轻程序员的负担。

一直有人尝试,让 JavaScript 变成强类型语言。在官方最终支持强类型之前,本文介绍三种现在就可用的解决方案。

(题图:摄于花莲,台湾,2012年6月)

一、TypeScript

TypeScript 是微软2012年推出的一种编程语言,属于 JavaScript 的超集,可以编译为 JavaScript 执行。 它的最大特点就是支持强类型和 ES6 Class

首先,安装TypeScript。

  $ npm install -g typescript  

然后,为变量指定类型。

  // greet.ts  function greet(person: string) {    console.log("Hello, " + person);  }    greet([0, 1, 2]);  

上面是文件 greet.ts 的代码,后缀名 ts 表明这是 TypeScript 的代码。函数 greet 的参数,声明类型为字符串,但在调用时,传入了一个数组。

使用 tsc 命令将 ts 文件编译为 js 文件,就会抛出类型不匹配的错误。

  $ tsc greeter.ts  greet.ts(5,9): error TS2345: Argument of type 'number[]'     is not assignable to parameter of type 'string'.  

二、Flowcheck

Flowcheck 是一个轻量级的类型断言库,可以在运行时(runtime)检查变量类型是否正确。

首先,安装Flowcheck。

  $ npm install -g flowcheck  

然后,编写一个声明了变量类型的脚本。

  function sum(a: number, b: number) {    return a + b;  }    sum('hello','world')  

接着,使用下面的命令,将脚本转换为正常的 JavaScript 文件。

  $ browserify -t flowcheck -t [reactify --strip-types] \  input.js -o output.js  

转换后的文件如下。

  var _f = require("flowcheck/assert");    function sum(a, b) {      _f.check(arguments, _f.arguments([_f.number, _f.number]));    return a + b;  }  

可以看到,代码中插入一个断言库。每次运行函数之前,会先执行断言,如果类型不符就报错。

  $ node output.js  // throw new TypeError(message);              ^  TypeError:     Expected an instance of number got "hello",     context: arguments / [number, number] / 0    Expected an instance of number got "world",    context: arguments / [number, number] / 1  

三、Flow

Flow 是 Facebook 在2014年发布的一个类型检查工具,用来检查 React 的源码。

安装命令如下。

  $ npm install --global flow-bin  

如果安装不成功(我就是如此),就需要自己从源码编译了。

Flow 的用法很多,我只举几个例子。前文介绍的两种工具,只能检查声明了类型的变量,而 Flow 可以推断变量类型。

  // hello.js  /* @flow */  function foo(x) {    return x*10;  }  foo("Hello, world!");  

上面是文件 hello.js ,该文件的第一行是注释,表明需要使用 Flow 检查变量类型。

  $ flow check  hello.js:7:5,19: string  This type is incompatible with  /hello.js:4:10,13: number  

运行 flow check 命令,得到报错信息:预期函数 foo 的参数是一个数值,但是实际为一个字符串。

Flow 也支持变量的类型声明。

  /* @flow */  function foo(x: string, y: number): string {    return x.length * y;  }  foo("Hello", 42);  

另一个有趣的功能是,Flow 可以将类型注释(annotation),转为类型声明。

  // annotation.js  /**    @param {number} x    @return {number}   */  function square(x) {    return x * x;  }  square(5);  

运行 flow port 命令,会得到下面的结果。

  $ flow port annotation.js  function square(x: number) : number {     return x * x;   }  

Flow 的更多介绍,可以阅读《Exploring Flow, Facebook's Type Checker for JavaScript》

本文的原始幻灯片点击这里(里面有更多内容)。

(完)

文档信息

2015年2月3日星期二

阮一峰的网络日志

阮一峰的网络日志


图灵访谈

Posted: 02 Feb 2015 07:47 PM PST

上周,我接受了图灵教育访谈,谈了自己的人生经历。

我的目的是卖书,如果你还没买《如何变得有思想》,请考虑一下吧。只有出版社赚到钱,我才有机会出下一本。

下面是书面访谈的原文。

================================================

Q - 图灵,A - 阮一峰

Q: 请介绍一下自己。

A: 我是70后,在上海出生和长大,大学糊里糊涂读了经济学。工作了几年,又去读了世界经济的研究生,毕业后,在上海一所本地高校当了老师,教财经类的课程。最近,去了支付宝的前端团队,在玉伯负责的"体验技术部"工作,目前主要从事JavaScript和Node.js的开发。

我翻译了《软件随想录》《黑客与画家》,出版了技术专著《ECMAScript 6入门》和博客文集《如何变得有思想》

Q: 你是怎么接触到互联网的?

A: 2000年前后,我第一次上网,一下子就着迷了。那时候,只有图书馆的机房能上网,除了吃饭,我从早上8点开馆一直待到晚上10点闭馆,只做三件事:在化云坊fanso.com听歌,在chinaren.com下棋,在水木清华BBS灌水。

Q: 你是怎么开始学习计算机的?

A: 我对计算机一直有兴趣,但从没想过去编程。因为我是文科生,学校里只教Word和Excel,对计算机没概念。大学快毕业了,为了打游戏和上网,才买了第一台个人电脑,CPU是奔腾133MHz。研究生时,我想考计算机二级C语言,买了指定教材,但发现看不懂。

那个时候是互联网泡沫,很容易申请免费的个人主页空间。我在网易(yeah.net)和亿唐(etang.com)申请了个人主页,从此开始接触到网页制作。中国青年出版社引进的台湾"旗标计算机丛书",对我帮助很大。那套书图文并茂,通俗易懂,我从那里学会了最简单的HTML语言。

Q: 你后来怎么学会编程?

A: 学了HTML以后,发现网页要做得漂亮,必须懂CSS。学了CSS以后,发现制作动态网页,必须懂一门计算机语言,就去学了asp。很快发现,asp不如php功能强,就去学了php和数据库MySQL。用了开源数据库,就离不开了Linux系统了。这个时候,又重新去学C语言,这一次学会了。

Q: 你是怎么开始写博客的?

A: 2003年以前,我制作网页都是使用微软的FrontPage ,需要一张张地制作,非常麻烦。后来听说博客软件可以动态生成网页、更换样式、站内搜索,就很动心。

我最早使用的博客软件是asp语言写的,忘了叫什么名字。2003年底,我看到了王建硕的博客,非常震惊,原来博客可以玩得这么精彩。他用的软件是MovableType,我照他的样子搭建了一个,一直用到现在。遗憾的是,王建硕已经换成WordPress了,MovableType也停止更新了,国内还用这个软件的人屈指可数。互联网时代就是这样,一切变得太快了,我觉得自己是个怀旧的人。

Q: 你的博客是怎么出名的?

A: 我其实不知道,一开始我只把博客当作私人园地,并没有想到有人会来看。但是,不知道是否错觉,Google对于MovableType生成的网页,会给很高的权重。我的很多文章排在Google的第一页,很多人这样发现了我的博客。

我的文风可能也有点帮助。我喜欢用口语,喜欢用短句,别人比较容易看懂。另外,比我水平更高、写得更好的人,很多都放弃写博客了,只有我还在写。所以,我的体会是,如果你认认真真写,认认真真排版,保证别人可以看懂,还时不时插入一些漂亮的插图,或者一段趣闻轶事,你坚持这么做,就可以出名。

Q: 你的博客早期都是谈文学的,怎么会转变为一个技术博客?

A: 大学里,我喜欢读小说和传记,曾经以为社会科学是自己一辈子的专业方向。后来发现,在中国搞社会科学没前途,除非愿意给政策背书。那时,我还喜欢写社会和政治评论,每次都有一大堆互相争吵、人身攻击的留言,无法得到任何共识。我还接到过有关部门的电话,要求删除文章

最终,我觉得文学、政治学、经济学、社会学之类的学科,都没多大用处,就渐渐不想走这条路了。它们也不是真的没用,就是在中国不行,改变不了现实,只会让自己走入绝境。在我看来,走技术这条路至少有一个好处。我曾经在一篇文章里写过:"(在国内,)如果你想不撒谎、不干坏事、并且被公正地对待,那么可能你只能去编程了。"

Q: 很多人批评你的技术文章,错误非常多,你怎么看?

A: 我一直是外行,从来不敢说自己是专家。对我来说,博客首先是一种知识管理工具,其次才是传播工具。我的技术文章,主要用来整理我还不懂的知识。我只写那些我还没有完全掌握的东西,那些我精通的东西,往往没有动力写。炫耀从来不是我的动机,好奇才是。

当然,我肯定只写那些我觉得对的东西,尽量对读者负责。但是没法保证,我觉得对的东西就是对的。网站流量越来越大,对我的争议也越来越多,好几次我都在文章前加上说明,这是初学者的笔记。我还会以这种方式写下去。我希望自己永远都能保持,那种不怕丢面子,敢于当众说蠢话的勇气。

Q: 你近期在忙什么?

A: 最近一两年,我的关注重点都将是Node(io.js)。我觉得,Node很适合作为前后端之间的中间层。我希望用Node、PostgreSQL、MongoDB、Nignx实现一个网站,会是一个开源项目。

如果有时间,我很希望能学一下Go语言,用它来写后端实现。我也很想学函数式编程,它带来了全新的思考方式,而且非常优雅。

[说明] 摄于艾西拉,摩洛哥,2014年8月

(完)

文档信息

2015年2月1日星期日

阮一峰的网络日志

阮一峰的网络日志


MVC,MVP 和 MVVM 的图示

Posted: 31 Jan 2015 07:00 PM PST

复杂的软件必须有清晰合理的架构,否则无法开发和维护。

MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用。它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 MVVM 架构的区别就不容易了。

昨天晚上,我读了《Scaling Isomorphic Javascript Code》,突然意识到,它们的区别非常简单。我用几段话,就可以说清。

(题图:摄于瓦伦西亚,西班牙,2014年8月)

一、MVC

MVC模式的意思是,软件可以分成三个部分。

  • 视图(View):用户界面。
  • 控制器(Controller):业务逻辑
  • 模型(Model):数据保存

各部分之间的通信方式如下。

  1. View 传送指令到 Controller
  2. Controller 完成业务逻辑后,要求 Model 改变状态
  3. Model 将新的数据发送到 View,用户得到反馈

所有通信都是单向的。

二、互动模式

接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller。

另一种是直接通过controller接受指令。

三、实例:Backbone

实际项目往往采用更灵活的方式,以 Backbone.js 为例。

1. 用户可以向 View 发送指令(DOM 事件),再由 View 直接要求 Model 改变状态。

2. 用户也可以直接向 Controller 发送指令(改变 URL 触发 hashChange 事件),再由 Controller 发送给 View。

3. Controller 非常薄,只起到路由的作用,而 View 非常厚,业务逻辑都部署在 View。所以,Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。

四、MVP

MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

1. 各部分之间的通信,都是双向的。

2. View 与 Model 不发生联系,都通过 Presenter 传递。

3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

五、MVVM

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。AngularEmber 都采用这种模式。

(完)

文档信息

2015年1月6日星期二

阮一峰的网络日志

阮一峰的网络日志


版权的边界

Posted: 06 Jan 2015 01:29 AM PST

最近,有两起全国关注的版权纠纷。

第一起是琼瑶起诉于正。

"......擅自采用其作品《梅花烙》的核心独创情节,改编创作电视剧本,并联合其他四个被告,共同摄制了电视连续剧《宫锁连城》并播出。北京第三中级人民法院认定于正对琼瑶进行事实抄袭,要求于正赔偿琼瑶500万,并在公开媒体刊登致歉声明,停止《宫锁连城》一切发行传播行为。"

第二起是美国电影协会投诉国内最大的字幕网站"射手网",侵犯影视作品和字幕作品著作权案。

"射手网由上海射手信息科技有限公司经营,该公司未经权利人许可,自2013年开始在"射手网"登载《驯龙高手》等影视作品的字幕,用户无需注册即可浏览、下载和使用,但该公司无法提供上述影视作品字幕文件的相关著作权许可证明材料。射手网在上海市文化市场行政执法总队开展调查后,于2014年11月23日关闭,并接受罚款10万元的行政处罚。"

这两起案件有一个共同之处:都涉及新型的、非传统的侵权形式,第一起案件涉及情节抄袭,第二起案件涉及字幕侵权,判例将对相关产业产生重大影响。本文无意对案件本身发表评论,只想探讨在版权保护越来越严格、权利边界越来越大的今天,怎样才能不侵权。

《版权法》有一个基本原则,就是实体的产品才拥有版权,无形的思想不拥有版权。你有了一个想法,这个想法是没有版权的,你不能因为其他人也有类似的想法,就控告他们侵权。但是,如果你把这个想法写成文字、谱成歌曲、拍成影视,总之让其具有实体形式,事情就不一样了,其他人未经允许使用这些实体产品,就是侵权。这种规定是合理的,因为《版权法》保护的是创作行为,如果规定思想也受版权保护,他人的想法不得非法使用,将禁锢人类思考,从而影响创新。

可是,现实生活中,有时你很难分清楚,想法与实体产品的区别。让我来举几个例子。

(1)朋友聚会的时候,有人说了一个很好笑的段子,你一下子就记住了,第二天又说给其他人听。请问你有没有侵犯版权?

(2)某广告有一句很妙的广告语,你原封不动地、或者略加改动地把它用在自己的作品里。请问你有没有侵犯版权?

(3)你很喜欢某首流行歌曲,把歌词抄在笔记本上,请问你有没有侵犯版权?

这样的例子还有很多,我可以一口气说下去。它们共同的特征就是,你使用了他人的内容(实质是使用了他人产生的想法),这算不算侵权?如果你说,上面的例子都是个人合理使用(fair use),没到《版权法》追究的程度,那我改一下,假定当事人把内容用于商业产品,并广为传播,比如把笑话编成书出版、把他人的广告语用在自己的广告里、把歌词做成lrc文件放在网上供人下载,版权法要不要追究?

计算机和网络技术的发展,使得传播的速度和范围指数式扩大,而传播成本却急剧下降,这其中蕴含的巨大商业利益,造成权利人倾向于追究"引用内容"引发的侵权,而根据目前的判例,法院很可能会支持权利人的诉求。所以,思想实际上是受到现行《版权法》保护的,如果他人使用了你的想法,你有很大机会追究对方的责任。

这意味着什么:美国有电视剧《老友记》,你能不能照着拍一部三男三女的都市言情喜剧?韩国有一个歌手比赛节目,你能不能模仿搞一个中文版的《我是歌手》?你自己动手,为最爱的电影写了一个剧本,详细到每一个分镜头都做了精确的记录,或者你把每句对话都听写下来,变成了字幕文件,你能不能把它放上网?......

如果没有得到权利人的许可,目前的答案是不能。因为你侵犯了他人的创意。

其实,某种想法得到版权保护,在计算机领域早有先例。有一些非常令人震惊的专利,限制后来者不能使用某种创意。2004年4月,微软公司得到一个专利,内容是计算机上,在一个特定时间内按下多次按键来启动应用程序,即微软为双击鼠标启动程序申请了专利。你能想象吗,从今以后,每次双击鼠标都要向微软付钱吗?幸好微软没有动用这项专利......但是,苹果公司就真的用了。2012年8月,苹果起诉三星侵犯专利权,其中有一条是将手机做成圆角矩形!全世界这才发现,原来除了苹果公司,其他人是不能将手机做成圆角矩形的......

如果你问我对这些事情的看法,就像前面说过的,我认为思想不应该受到版权保护,这会影响到创新。另一方面,古语说"太阳底下无新鲜事",你又怎么能保证某个想法是你先有的,其他人再用都是受你影响?可惜,当代的《版权法》实践没有采纳这种观点。

于是,我们就面临了一种可悲的局面。一方面,思想的融合和激荡空前容易,另一方面,《版权法》越来越严,边界越来越宽,限制你使用别人的想法。1790的美国《版权法》规定,版权保护期是作者死后28年,1831年改为死后42年,1909年改为死后56年,1976年改为死后75年,1998年改为死后95年,这还不包括版权涵盖范围的扩展。幸好数学公式无法申请版权(因为这属于发现自然界规律,不属于创造),否则我们连算术都没法做了。

[说明] 本文原发表于2015年1月5日的《新世纪周刊》

(完)

文档信息