分析 JavaScript
JavaScript 建立在一些非常好的想法和少数非常坏的想法之上。
那些非常好的想法包括函数、弱类型、动态对象和一个富有表现力的对象字面量表示法。那些坏的想法包括基于全局变量的编程模型。
JavaScript 的函数主要是基于词法作用域的顶级对象。JavaScript 是第一个成为主流的 lambda 的语言。实际上,相对 Java 而言,JavaScript 与 Lisp 和 Scheme 有更多的共同点。它是披着 C 语言外衣的 Lisp。这使得 JavaScript 成为一个非常强大的语言。
现今大部分编程中都流行的要求强类型,其原理在于强类型允许编译器在编译时检测错误。我们能越检测和修复错误。付出的代价就越小。JavaScript 是一门弱类型的语言,所以 JavaScript 编译器不能检测出类型错误。这可能让从强类型语言转向 JavaScript 的开发人员感到恐慌。但事实证明,强类型并不会让你的测试工作轻松。并且我在工作中发现,强类型检查找到的那种错误并不是令我头痛的错误。另一方面,我发现弱类型是自由的。我无须建立复立的类层次,我永远不用做强制造型。也不用疲于应付类型系统想要的行为。建立
JavaScript 有非常强大的对象在字面量表示法。通过列出对象的组成部分,它们就能简单地被创建出来。
原型继承是 JavaScript 中有一个有争议的特性。JavaScript 有一个无类别的对象系统,在这个系统中,对象直接从其他对象继承属性。这真的很强大,但是对那些被训练使用类去创建对象的程序员来说,原型继承是一个陌生的概念。如果你尝试对 JavaScript 直接应用基于类的设计模式,你将会遭受挫折。但是,如果你学习使用 JavaScript的原型本质,那么你的努力会有所回报。
JavaScript 在关键思想的选择上饱受非议。虽然在大多数情况下,这些选择是合适的。但是有一个选择相当糟糕;JavaScript 依赖于全局变量来进行连接。所有的编译单元的所有顶级变量被撮合到一个被称为全局对象的公共命名空间中。这是一件糟糕的事情,因为全局变量是魔鬼,并且在 JavaScript 中它们是基础性的。幸好,我们也看到 JavaScript 也给我们提供了缓解这个问题的方法。
JavaScript 是一门有许多差异的语言。它包含很多错误和尖锐的边角,所以你可能会疑惑:「为什么我要使用 JavaScript 」有两个答案。第一个是你没有选择。WEB 已变成一个重要的应用开发平台,而 JavaScript 是唯一一门所有浏览器都可以识别的语言。很不幸,Java 在浏览器都可以识别的语言。否则想用强类型语言的人就有其他的选择了。但是 Java 确实失败了,而 JavaScript 仍蓬勃发展着,这恰恰说明 JavaScript 确有其过人之处。
另一个答案,尽管 JavaScript 有缺陷,但是它真的很优秀,它既轻量级又富有表现力。并且一旦你熟练掌握了它,就会发现函数式编程是一件很有趣的事。
但是为了更好使用这门语言,你必须知道它的局限,我将会无情地揭示它们。不要因此而气馁。这门语言的精华部分足以弥补它鸡肋的不足。
一个简单的 DEMO
如果你有一个 WEB 浏览器和任意一个文本编辑器,那么你就有一个运行了 JavaScript 程序所需要的一切。首先,请创建一个 HTML 文件,可以命名为 program.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<pre>
<script src="program.js"></script>
</pre>
</body>
</html>
接下来,在同一个文件夹里,创建一个脚本文件,可以命名为 program.js
document.writeln('hello world!')
空白
空白可能表现为格式化字符或注释的形式。空白通常没有意义,但是偶尔需要用它来分隔自符序列,否则它们就会被合并成一个单一的身上符号
var that = this
var 和 that 之间的空格是不能被移除的,但是其他的空格都可以被移除。
注释
JavaScript 提供两种注释形式,一种是用 /* */ 包围的块注释,另一种是以 // 开头的行注释,注释应该被充分的用来提高程序的可读性。必须注意的是,注释一定要精确地描述代码。没有用的注释比没有注释更糟糕。
用 /* */ 包围的块注释形式来自于一门叫 PL/I 的语言。PL/I 选择那些不常见的符号作为注释的符号标志,因为它们除了可能出现在字符串的字面上之外,不大可能在这门语言的程序中出现。在 JavaScript 中,那些字符也可能出现在正则表达式字面上,所以块注释对于被注释的代码块来说是不安全的。
/*
var rm_a = /a*/.match(s)
*/
导致了一个语法错误,所以,我建议避免使用 /* */ 注释,而用 // 注释代替它。
标识符
标识符由一个字母开头,其后可选择性地加上一个或多个字母、数字或下划线。标识符不能使用下面这些保留字。
abstract
boolean
break
byte
case
catch
char
class
const
continue
debugger
default
delete
do
double
else
enum
export
extends
false
final
final
finally
float
finally
float
for
……
在这个列表中大部分保留字尚未用在这门语言中,这个列表不包括一些本应该被保留而没有保留的字,诸如 undefined, NaN 和 Infinity 。JavaScript 不允许使用保留字,JavaScript 不允许使用保留字来命明变量或参数。更糟糕的是,JavaScript 不允许在对象字面量中,或者在一个属性存取表达式的点号之后,使用保留字作为对象的属性名。
标识符被用于语句、变量、参数、属性名、运算符和标记。
数字
JavaScript 只有一个单一的数字类型,它在内部被表示为 64 位的浮点数,和 Java 的 double 一样。不像大多数其他的编程语言,它没有分离出整数类型,所以 1 和 1.0 是相同的值。这提供了很大的方便,因为它完全避免了短整数的溢出问题,并且你需要知道的关于数字的一切就是它的一种数字,这样就避免了因数字类型导致的错误。
如果一个数字字面量有指数部分,那么这个字面量的值是由 e 之前的部分乘以 10 的 e 之后部分的次方计算出来的。所以 100 和 le2 是相同的数字。
负数可以用前缀运算符 - 来构成。
值 NaN 是一个数值,它表示一个不能产生正常结果的运算结果。NaN 不等于任何值,包括它自己。你可以函数 isNaN 检测 NaN。
值 Infinity 表示所有大于 1.79769313488261570e + 308 的值。
数字拥有方法。JavaScript 有一个对象 Math,它包含一套作用域数字的方法。例如,可以用 Math.floor( number ) 方法将一个数字转换成一个整数。
字符串
字符串字面量可以被包围在单引号或双引号中,它可能包含 0 个或多个字符。\ (反斜线符号)是转义字符。JavaScript 被创建的时候,Unicode 非一个 16 位的字符集,所以 JavaScript 中的所有字符都是 16 位的。
JavaScript 没有字符类型。要表示一个字符,只须创建仅一个字符的字符串的字面上之外,不大可能在这门语言的程序中出现。在 JavaScript 中,那些字符对也可能出现在正则表达式字面上,所以块注释对于被注释。
转义字符允许把那些正常情况下不被允许的字符插入到字符串,比如反斜线、引号和控制字符。\u 约定允许指定用数字表示的字符码位。
"A" === "\u0041"
字符串有一个 length 属性。例如 "seven".length 是 5。
字符串是不可变的。一旦字符串被创建,就永远无法改变它。但通过 + 运算符去连接其他的字符串从而得到一个新字符串是很容易的。两个包含着完全相同的字符且字符顺序也相同的字符串被认为是相同的字符串。
'c' + 'a' + 't' === 'cat'
是 true
字符串有一些方法
'cat'.toUpperCase() === 'CAT'
