Name | Speaking JavaScript |
---|---|
Author | Axel Rauschmayer |
Edition | 1st |
Release Date | February 2014 |
ISBN-13 | 978-1-4493-6503-5 |
Medium | 电子书 |
Rating | 4 |
看完第八章。后面的内容我觉得不用看了,当参考书翻就好了。重点学习下 ES6 然后开始写代码。
历史原因
JavaScript 参考了很多语言的特性,所以它是个杂揉体。很多时候,学习 JavaScript 不止是学语言特性本身,还有学习它的 common pattern。
JavsScript 在 ES3 之前没有异常处理机制,所以它的语言特性里面,遍布了各类隐式转换和 failed silently。比如:
>>> '1' < 3 // true
>>> 1/0 // Infinity
>>> Number("abcd") // NaN
从规范上看,JS 中的数字都是浮点数(1.0 === 1
),但是 JS 解释器为了效率,会在内部实现上尽量用整型。
Closure
A closure is a function plus the connection to the variables of its surrounding scopes.From Speaking JavaScript
The IIFE Pattern: Introducing a New Scope
IIFE (immediately invoked function expression, pronounced “iffy”),可以用来创建一个 Scope。
var result = [];
for (var i=0; i < 5; i++) {
result.push(function () { return i }); // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)
for (var i=0; i < 5; i++) {
(function () {
var i2 = i; // copy current i
result.push(function () { return i2 });
}());
}
ES6 引入了 let
替代 var
以实现 block scope。
Expressions vs Statements
Expression 是指可以返回一个右值的式子,如 myvar
,1+2
。Statement 表示一个行为,它往往是由 expression 组成的。比如 var salutation;
是一行 statement,它由一个 declaration expression 组成。
Using ambiguous expressions as statements
有些语句可能有歧义:
// 既可以表示一个有 foo 属性的 Object,
// 也可以表示一个 block,里面有一个 label foo 调用了 bar(3, 5)。
{
foo: bar(3, 5)
}
// 既可以表示一个 Named Function Expression,返回一个函数对象,
// 也可以表示一个函数声明,给 foo 变量赋值为一个函数。
function foo() {}
所以 JS 规范要求,一个 expression statement 必须:
- 不以大括号开头
- 不以
function
关键字开头
这会有一些影响,比如你向 eval
传递一个 Object literal 时,必须用括号包起来:
> eval('{ foo: 123 }')
123
> eval('({ foo: 123 })')
{ foo: 123 }
比如你用 IIFE (Immediately Invoked function expression) 时,必须这样写:
> (function () { return 'abc' }())
'abc'
// 函数声明需要一个函数名
> function () { return 'abc' }()
SyntaxError: function statement requires a name
// 函数声明不能马上被调用
> function foo() { return 'abc' }()
SyntaxError: Unexpected token )
Automatic Semicolon Insertion
JS 解析器提供了一种自动插入分号的机制,用来使分号变成可选的。它判断是否需要插入分号有这几个依据:
- A line terminator (e.g., a newline) is followed by an illegal token.
- A closing brace is encountered.
- The end of the file has been reached.
比如:
if (a < 0) a = 0
console.log(a)
// a = 0 后不能出现 console
// console 一行是文件尾
if (a < 0) a = 0;
console.log(a);
function add(a,b) { return a+b }
function add(a,b) { return a+b; } // closing brace
这种机制可能会带来一些问题:
return
{
name: 'John'
};
// 转换成下面的代码:
// 返回 undefined;然后跟着一个块,块里面有一个 label 叫 name
return;
{
name: 'John'
};
func()
[ 'ul', 'ol' ].foreach(function (t) { handleTag(t) })
// 转换成下面的代码:
// 'ul', 'ol' 被逗号表达式了,返回 'ol'
// JS 解析器认为 func() 可能返回一个对象,可以取它的 'ul' 属性
func()['ol'].foreach(function (t) { handleTag(t) });
对于 JS 这种语法设计不够精妙的语言来讲,最好是自己加分号,不要相信解析器(它也没办法做到精准)。
Types, Primitives, Wrapping and Unwrapping Primitives
JavaScript 有六种类型,分别是:bool
, number
, string
, object
, null
, undefined
,其中除了 object
其他五种都被叫做 Primitive Values。bool
, number
, string
有对应的 Wrapper Object Class,分别是 Boolean
, Number
, String
。
> String(123) // number 转换成 string
'123'
> let a = new String(123) // 定义一个 String 类实例
> a
[String: '123']
> a.valueOf() // String 类实例 unwrap 成 primitive
'123'
> a === '123' // primitives 与 object 作比较时永远不相等
false