JavaScript:语言精粹

2,514 阅读14分钟

本文根据Douglas Crockford的《The Good Parts of JavaScript and the Web》的课程内容整理而成。 还参考了一些其他资料在文章结尾部分标出。

另外我将课程视频翻译一下,链接在这里呀《JavaScript语言精粹》

  • 第一节:这就是JavaScript
  • 第二节:函数是第一公民
  • 第三节:进击的Ajax
  • 第四节:ES5的新世界
  • 第五节:函数趣事
  • 第六节:安全的本质
  • 第七节:同步的控制
  • 第八节:更好的未来

##第一节:这就是JavaScript

  • JavaScript历史
  • Object
  • Number
  • Boolean 和 String
  • Array
  • Date,RegEx,&Type
  • JavaScript语法
  • JavaScript语句

JavaScript历史

在伊利诺伊大学厄本那 - 香槟分校的国家超级计算应用中心,有许多孩子正在为互联网开发应用程序。那时有许多协议被考虑用于在互联网上向人们传输信息,这些方法有WAIS,Archie,Gopher,FTP,Finger,和其他一些协议还有万维网,人们并不知道哪一个会赢。所以他们写了一个适用于所有人的应用程序,他们叫它 Mosaic(全球最早一款可以显示图片的浏览器)。因为这种方式实现了在万维网上的浏览功能,万维网赢得了胜利。他们做的事情是他们想出了一个叫做图片标签的东西,它能够在网页上显示图片,这是其他方式无法轻易做到的,因为网页可以显示图像,是它让万维网赢了从此进入了快速的发展。

这个项目中的一些人来到了加州,在那里他们成立了一个叫网景的公司,网景公司制作了第一款商业浏览器叫网景导航者(Netscape Navigator),这是一个巨大的转折。他们还增加了一系列新功能,他们还想让终端用户的程序变得更简单。它们想做一个类似Mac上HyperCard的程序,HyperCard是一个可以创建简单的应用程序的应用。他们也想让浏览器实现这些功能,所以他们把这项工作交给Brendan Eich。他曾经是Silicon Graphics的内核程序员,

他的想法时写一个scheme的解释器去实现,但是他被告诉不要用scheme。去做一个人们喜欢的,流行的语言,类是于Java或者VB,这语言是给小孩准备的。所以他花了10天创建了新的交互形式的浏览器属性,然后又花了10天去设计和实现了一个新的语言。他拿来了

  • Java中的语法
  • Scheme中的函数
  • Self中原型的概念

网景给它取名 LiveScript。网景公司浏览器的大获成功引起了微软的注意。同时,在太阳公司设计出了Java语言,可以通过Java虚拟机来摆脱微软。然后也用Java语言做了一个浏览器叫“HotJava”,也非常成功。微软哪能对它们会坐视不管。所以为了一起抵抗微软,网景和太阳公司说我们联盟吧。第一步的计划是,在Netscape浏览器中加入Java,然后太阳公司不接着开发“HotJava”浏览器了。第二步,太阳公司跟网景说,你别整你那LiveScript了,你直接用我的Java。网景公司不同意,首先是因为Netscape浏览器用Java的方式是用LiveScript接口与浏览器进行通信的。如果大改的话,影响发版啊。我哪等的起。要不我把名改成从LifeScript改为JavaScript吧。咱就说这是Java的一个子集,Java的小弟弟。太阳公司说也行吧。于是哥俩手拉手出去开个发布会,说了这个谎。所以到今天还有人以为他俩是亲兄弟呢,清醒一点,一点血缘关系都没有,两个妈两个爹的~哈哈。

微软那边也没闲着,先是买了一个做浏览器的公司叫Spyglass,然后把它们的浏览器改个名叫IE。下一步,差啥了?对,缺个JavaScript。别闲着,弄吧。微软团队做事那叫一个认真啊,不管是JavaScript的错误,bug,还是设计缺陷,一样没改的都给逆向实现了。做完了也不能叫JavaScript,因为Sun拥有JavaScript商标。那我们就叫它Jscript吧。

网景公司开始担心,这样整不完了嘛,赶紧我得整个语言的标准。然后他们去找到W3C。W3C说,滚,没工夫搭理你。接着又去找了ISO,ISO也没吱声。最后总算找到了欧洲计算机制造商协会(ECMA)。ECMA说那咱得成立个委员会啊。然后微软加入了委员会并且占了主导地位,最后这个标准也是基于微软的文档制作的。那这个标准我们也得起个名,那就用工作委员会名称把叫 ECMAScript。Douglas在课上说这真TM难听~哈哈哈哈

现在用的大多数版本是1999年12月出版的IE第三版。然后做了第四版,版本持续了十年最后被放弃了。 在2009年,出版了第五版定义了两种语言,严格的和默认的。2015年,第六版发布。后边我们会用到ES6。现在我们回过头来想想,JavaScript不好的地方来自哪呢?

  • 一个是遗留下来的,任何语言中发生的很多事情都是重复以前语言中发生的错误
  • 另外一些是好的愿望,一些特性被加到语言中,希望它变得简单,但是失败了。
  • 最后就是匆忙了,十天时间对于设计和实现编程语言来说太短。

Object

在JavaScript中,对象是一个可变键值对的集合。每个属性都有一个在该对象中唯一的键(key)字符串。这个键(key)可以存放任何值。然后你可以对对象进行读取,设置和删除。

  • Get:可以使用点表示法或方括号表示法从对象获取属性,方括号中的表达式是一个字符串,这样可以动态访问
  • Set:通过简单的赋值操作
  • Delete:可以使用delete操作符从对象中删除属性,少看被用过

需要注意的是 键必须是字符串 ,将任何类型放到方括号中,但JavaScript会将其转换为字符串。一旦创建一个对象,就会拥有这些方法。

可以用对象自面量的方法去创建一个对象。如果对象中属性命名的字段是合法的标识符,就不必加上引号。不然要加上引号。

大多数经典的面向对象语言,它们都是创建类,然后对象是类的实例,并且类继承自其他的类。JavaScript有一个更简单,更先进的设计。它是基于原型(prototype),其中对象继承自对象。 这是一种委托(delegation )继承的方式。我们用Object.create()方法去实习。

下面的这个例子,

  • 我们先用字面量的方法来创建一个mother的对象,有a、b两个属性。所有通过对象字面量的方法创建的对象都连接到Object.prototype,这个JavaScript中标准的对象。
  • 然后使用object.create(mother)方法创建一个daughter的对象,继承自mother。
  • 如果让daughter的b加2,本身没有值b是继承mother的值b。所以加完等于4,把它存放在daughter对象中。

读取操作是沿着原型链进行查找的,储存操作将始终在最外的对象中


Number

在JavaScript中,Number是一个比Java更简单的数字系统,没有ints(原始类型整数) and integers(包装类型整数)。它基于IEEE-754标准的64位二进制浮点,在Java和其他语言中被叫成双重浮点。

  • 这样就有一个缺陷就是交换律不在生效。
  • 最大数字是9千万亿,以上数字会失真。

因为我们用二进制浮点表示小数部分,所以小数部分是进行模拟的,这样就会出现。

 0.1 + 0.2 == 0.30000000000000004;

Number是一个基本包装类型,所以他有继承自number.prototype的方法。

不过与对象不同的是,对象的生命周期。

let a = 0.30000000000000004;

let b = a.toFixed(2) //生命周期存在与这一行代码中。

------------------

let a = new Number(0.30000000000000004); //在调用方法时会创建一个Number类型的一个实例
let b = a.toFixed(2); //在实例上调用指定的方法
a = null;             //销毁这个实例

这意味着我们不能在运行时调加方法。

Java在拥有一个单独的数学对象,当时Java是因为考虑到计算机的配置,准备在低配的电脑中将数学函数的功能删除,但计算机的配置越来越高,这并没有发生。JavaScript也拿来了这个Math对象。

  • 还有一个特殊的数字NaN, NaN代表没有定义或者错误的运算。NaN不等于NaN
  • 值Infinity代表极大值

Boolean 和 String

Boolean有两个值true 和 false

String字符串是不可改变的,一旦你创建一个字符串,它就无法更改。所以说无论你在 string 类型上调用何种方法,都不会对值有改变。

String可以用单引号或者双引号的字面量方式来表示。建议双引号程序之外的字符串比如URL等。 单引号用于程序之内的,比如属性等。

字符串和数字之间可以相互转化:字符串转化成为数字

  • 用Number( )函数
  • 用一元加操作符
  • 用parseInt函数

parseInt是从Java借鉴来的东西,它会将值转换为数字,但会在第一个非数字字符处停止解析,并且不返回任何原因。这个设计非常糟糕,所以不推荐使用它。

数字转化成为字符串:

  • 用toString方法
  • 用String 函数

字符串有如下这些方法


Array

数组是基本数据结构之一。当JavaScript的第一个版本并没有数组,我们只能使用对象。通过传递数字,数字变成字符串,类似数组一样的工作。现在有了数组的数据类型,它继承自object,索引转换为字符串。

我们可以创建一个数组用对象字面量,数组有一个特定的长度属性,并且该属性总是比最高整数下标大1。可以通过设置它的当前长度去添加数组。

Arrays有一套比对象更有趣的方法,对象几乎没有来自原型的有用方法,这些方法都存储在array.prototype中,非常有用。

例如,有sort方法,我们可以在其中获取一组数字,它正在对字符串进行排序。sort可以采用一个函数参数来接收值对,并根据它们的相对大小返回-1,0或1。所以你可以覆盖这种可怕的行为。

arr.sort((a,b)=>a-b);  //数字从大到小排序

我的建议用对的那个,当名称是任意字符串时使用对象,当名称是连续整数时使用数组,不要被术语所迷惑。


Date,RegEx,&Type

Date函数,它的灵感来自Java的Date类,当它在1995年被推出时,还存在 Y2K(千年虫)bug,但终究我们幸免于难。它已被修复,所以我们现在可以用了。

我们也得到了正则表达式,它是从Perl 4借来。这是一个匹配正则表达式文字的正则表达式,但正则表达式必须连在一起写,所以对于很长的正则就变得很难读懂。

你可以通过Regulex这个网站,能够用铁路图来表示正则,强烈推荐。

在JavaScript中,所有的值都是对象,除null和undefined之外,它们有时被称为底值。它们很相似,但并不完全相同,所以不能互换。所以我建议只使用其中一个,选择使用的是undefined,因为这是语言本身使用的那个,它是变量和参数的默认值。如果试图检索对象中不存在一个属性,它不会报错,它会给你undefined。

JavaScript中有一个type运算符,它将返回一个字符串来标识数据类型。

  • 你传递一个数组,它将返回object,这不是一个技术上的错误,因为它是对象,但是这样很没有用。你可以用Array.isArray去判断是否是一个数组
  • 你传递一个null,它将返回object,这就是一个设计上的错误。没有啥理由。更糟糕的是,你想去判断是否是一个对象的时候,还有一个null值,因为它不是对象。(《js高程》上说null返回对象,是为了表示变量未来是一个对象。总之这是一个不好的设计吧。)

JavaScript有一点很蠢,它的每一个值都是真或者为假

  • 假值有false,null,undefined,空字符串,0,and NaN
  • 剩下所有值都是真,包括字符串0,和字符串false,所有的对象数组甚者它们是空的

JavaScript是一种松散类型的语言,任何这些类型都可以存储在任何变量中,或作为参数传递给任何函数。这很好,因为在强类型语言中,你最终会花费大量时间来对付类型系统,但其实效果并没有那么好。

因此在JavaScript中,对象是通过引用而不是通过值传递,这意味着不会复制对象。事实上,在JavaScript中没有简单的方法来复制一个对象。 “===”运算符比较对象引用,因此只有当两边都是同一个对象时它才会为真


JavaScript语法

JavaScript在语法上是C家族的一员,我们有标识符,可以以字母、下划线、美元符号开始

我们拥有与C类语言相同的运算符集,其中一些工作方式有点不同,这是你需要注意。JavaScript一个重大错误是加号运算符同时执行加法和连接。这是从Java学到的坏习惯,在Java中,它并不是那么糟糕,因为它强类型。JavaScript是松散的类型,如果它们都是数字,它会将它们相加。否则,它会将它们转换为字符串并将它们连接起来,这很糟糕。

我们已经谈过双平等号及其存在的问题,建议你总是使用三等号。

  • 逻辑符“&&”的工作方式,如果第一个操作数是真实的,则结果是第二个操作数的值。不然,结果为一个操作数的值,因此第二个操作数将不会判断,它确实会短路。
  • 逻辑“||”是工作与它相似的
  • “!”是逻辑非运算符
  • 如果你有!!,!两次,它会将值变为布尔值


JavaScript语句

我们有一套你期望在C语言中看到的语句,同样有一些差异。

我们有break标签,所以,如果你有嵌套循环和switch这些东西,这很好。

我们有for语句可以用来迭代数组,但我不建议使用它。在ES5中,我们有了forEach和map方法,你可以在数组的每个元素上调用一个函数。这几乎消除了对for循环的所有需求,因此我们不再使用for循环了。

我们有一个for in语句,它遍历对象的所有属性的名称,不幸的是,它还会遍历所有继承的属性,这些属性通常是你的方法。因此你的方法会与你的数据混淆并且变得一团糟,幸运的是,在ES5中我们得到了Object.keys。它接受一个对象并返回一个字符串数组,这些字符串只是对象的可枚举的属性。所以我也建议不要使用For in。

关于switch语句的只有一件事,JavaScript改进了switch语句,即switch值不需要是一个数字 它可以是一个字符串。

JavaScript中有异常处理,这很好。在ES3之前我们没有,这意味着你必须要写永远不会出错的程序,因为没有办法恢复。所以我们现在有异常,你可以throw任何价值。

异常处理非常简单,只有一个捕获块,它可以捕获一切,但它并不关心发生了什么


好啦~~~下一章是函数~ 这篇文章还有些想加的东西,我慢慢加~