《JavaScript 权威指南》读书笔记 3 - 类型、值和变量

JavaScript 中的数据类型分为两类:原始类型(primitive type)和对象类型(object type)。原始类型包括数字、字符串和布尔值

JavaScript 中有两个特殊的原始值:null(空)和 undefined(未定义),它们不是数字、字符串或布尔值。它们通常代表了各自特殊类型的唯一的成员

除此之外的就是对象了。对象是属性(property)的集合,每个属性都由「名/值对」(值可以是原始值或者对象)构成。JavaScript 对象很多时候也是 JSON/map/hash/dict,只是在不同语言中叫法不一样

普通对象是「命名值」的 无序 集合。数组则是一种有序集合对象

JavaScript 还定义了另一种特殊对象 —— 函数。如果用来初始化(使用 new 运算符)一个新建的对象,我们把这个函数称作 构造函数(constructor)。每个构造函数定义了一类(class)对象 —— 由构造函数初始化的对象组成的集合,常用的 JavaScript 核心类有 Array, Function, Date, RegExp, Error 等

JavaScript 解释器(interpreter)有自己的内存管理机制,可以自动对内存进行垃圾回收 GC(garbage collection)。当 不再有任何引用指向一个对象,解释器就会自动释放它占用的内存资源

JavaScript 是一种面向对象的语言,几乎一切皆对象。数据类型本身可以定义方法(method)来使用

从技术上讲,只有 JavaScript 对象才能拥有方法。然而数字、字符串和布尔值也可以拥有自己的方法。但是 null 和 undefined 是无法拥有方法的值

JavaScript 数据类型还可以分为:可以拥有方法和不可以拥有方法类型、可变(nutable)类型和 不可变(imutable)类型

JavaScript 程序可以更改对象属性值和数组元素的值。数字、布尔值、null 和 undefined 属于不可变类型 —— 比如,修改一个数值的内容本身就说不通。字符串可以看成由字符组成的数组,你可能会认为它是可变的。然而在 JavaScript 中,字符串是不可变的。可以访问字符串任意位置的文本,但不能修改其内容

JavaScript 可以自由地进行数据类型转换。比如程序期望使用字符串的地方使用了数字, JavaScript 会自动将数字转换为字符串。期望使用布尔值的地方使用了非布尔值也会自动进行相应转换

JavaScript 变量是无/弱类型的(untyped),变量可以被赋予任何类型的值,也可以动态改变不同类型的值。JavaScript 采用 词法作用域(lexical scoping)。不在任何函数内声明的变量称做全局变量(global variable),函数内声明的变量具有函数作用域(function scope),且只在函数内可见

数字

JavaScript 不区分 整数和浮点数。所有的数字均用浮点数值表示。JavaScript 采用 IEEE 754 标准定义的 64 位浮点格式表示数字

当一个数字直接出现在 JavaScript 程序中,我们称为数字直接量(numberic literal)。JavaScript 支持多种格式的籽安直接量。注意,在任何数字直接量前添加负号(-)可以得到它们的负值。但负号是 一元 求反 运算符,并不是数字直接量语法组成部分

整型直接量

十进制整数,例如:

0
3
1000000

十六进制值,指直接量以「」或为前缀,其后跟随十六进制数串的直接量。十六进制值是 0 ~ 9 之间的数字和 a(A) ~ f(F) 之前的字母构成,a ~ f 的字母对应的表示数字 10 ~ 15

0x2Af5         // 8192 + 2560 + 240 + 5 = 10996(十进制)
/*
+-------------------------------------------------+
|                                                 |
|       2          A          F          5        |
|                                                 |
|       3          2          1          0        |
|                                                 |
|    2*16^3      A*16^2     F*16^1     5*16^0     |
|                                                 |
|    2*4096      10*256     15*16       5*1       |
|                                                 |
|     8192   +    2560   +   240    +    5        |
|                                                 |
|       十六进制 2AF5 转换成十进制为10996         |
|                                                 |
+-------------------------------------------------+
*/

ECMAScript 标准 不支持 八进制直接量,ECMAScript 6 严格模式下不能使用八进制

浮点型直接量

浮点型直接量可以含有小数点,采用传统实数的写法。此外,还可以使用指数记数法表示浮点型直接量,即在实数后跟字母 e 或 E,后面再跟正负号,其后再加一个整形指数。这种记数方法表示的数值,是由前面的实数乘以 10 的指数次幂,例如:

3.14
2134.789
.33          // 0.33
6.02e23      // 6.02 乘以 10 的 23 次方
1.47e-32     // 1.47 乘以 10 的负 32 次方

JavaScript 中的算术运算

JavaScript 中的算术运算在 溢出(overflow)、下溢(underflow)或被零整除时不会报错,当数字运算结果超过了 JavaScript 所能表示的数字上限(溢出),结果为一个特殊的无穷大(infinity)值,相应的也有负无穷大(-infinity)值

下溢是当运算结果无限接近于零并比 JavaScript 能表示的最小值还小的时候发生的一种情况。这种情况下,JavaScript 将会返回 0。当一个负数发生下溢时,JavaScript 返回一个特殊的值「负零」,这个值几乎和正常的零完全一样

实零带除在 JavaScript 中并不报错:它会返回正或者负无穷大。但有一个例外,零除以零是没有意义的,这种整除运算结果也是一个非数字(not-a-number)值,用 NaN 表示

1/0                      // => Infinity
-1/0                     // => -Infinity
Number.NEGATIVE_INFINITY // => -Infinity
Number.MAX_VALUE         // => 1.7976931348623157e+308
Number.MAX_VALUE + 1     // => Infinity (经测试在 Chrome 里面并不是)
0/0                      // => NaN
Number.MIN_VALUE / 2     // => 0 发生下溢
-Number.MIN_VALUE / 2    // => -0 负零
-1/Infinity              // => -0
NaN == NaN               // => false
isNaN('hello')           // => false
isFinite(123)            // => true 参数不是 NaN, Infinity 或 -Infinity 时返回 true
isFinite(-1/0)           // => false

JavaScript 中的非数字值(NaN)和任何值都不相等,包括 NaN,NaN == NaN 返回 false 但是可以使用 isNaN 判断一个值是不是 NaN

二进制浮点数和四舍五入错误

IEEE-754 浮点表示法是一种二进制表示法,但是并不能精确表示十进制分数,在任何使用二进制浮点数的编程语言中都会有这个问题

下面的代码中 x 和 y 的值非常 接近 彼此和最终正确值。这种计算结果可以用途大多数的计算任务,这个问题也只有在比较两个值是否相等的时候才会出现

0.3 - 0.2           // => 0.09999999999999998
0.2 - 0.1           // => 0.1
var x = 0.3 - 0.2;
var y = 0.2 - 0.1;
x == y              // => false

日期和时间

JavaScript 语言核心包括 Date() 构造函数,用来创建表示日期和时间对象,大致使用方法如下:

var then = new Date(2011, 0, 1);                // 2011 年 1 月 1 日
var later = new Date(2011, 0, 1, 17, 10, 30)    // 下午 5 点 10 分 30 秒
var elapsed = now - then;                       // 日期减法:计算时间间隔的毫秒数
later.getFullYear();                            // => 2011
later.getMonth();                               // => 0 月份从 0 开始
...

文本

字符串(string)是一组 16 位值组成的不可变的有序序列,每个字符通常来自于 Unicode 字符集。字符串的长度(length)是其所含 16 位值的个数。字符串索引从零开始

""  // 空字符串
'testing'
"3.14"
"Wouldn't you prefer O'Reilly's book?"
"This string\nhas Two lines"  // 显示为两行
"one\
long\
line"   // 显示为单行,但是可以分行书写

转义字符

JavaScript 中转文字符用反斜线(\)加一个字符表示,比如 \n 就是一个转义字符,表示一个换行符

转义字符含义Unicode
\oNUL 字符\u0000
\b退格符\u0008
\t水平制表符\u0009
\n换行符\u0009
\v垂直制表符\u0009
\f换页符\u0009
\r回车符\u0009
\”双引号\u0009
\’单引号\u0009
\反斜线\u0009
\xXX2位十六进制数XX指定的 Latin-1 字符 
\uXXXX4位十六进制数XX指定的 Unicode 字符 

字符串的使用

加号(+)运算符作用于字符串表示链接,字符串通过访问 length 属性得到长度

var s = "hello world"
s.charAt(0)                 // => "h" 下标为 0 的字符
s.substring(1, 4)           // => "ell" 下标从 1 ~ 4 的字符
s.slice(1, 4)               // => "ell" 同上
s.slice(-3)                 // => "rld" 最后三个字符
s.indexOf("l")              // => 2 字符 l 首次出现的下标
s.lastIndexOf("l")          // => 10 字符 l 最后一次出现的下标
s.split(", ")               // => ["hello", "world"] 分割字符串
s.replace("h", "H")         // => "Hello, world" 全文字替换
s.toUpperCase()             // => "HELLO, WORLD"

一定要记住,在 JavaScript 中字符串是固定不变的,类似 replace() 和 toUpperCase() 的方法都 返回新字符串,原字符串本身并没有发生改变。在 ECMAScript 5 中字符串可以当做只读数组,可以通过下标访问单位字符

模式匹配

JavaScript 定义了 RegExp() 构造函数,用来创建表示文本匹配模式的对象。这些模式称为「正则表达式」(regular expression), JavaScript 采用 Perl 中的正则表达式语法。String 和 RegExp 对象均定义了正则模式匹配、查找和替换的函数

/^HTML/                       // 匹配以 HTML 开始的字符串
/[1-9][0-9]*/                 // 匹配一个非零数字,后面是任意个数字
/\bjavascript/i               // 匹配单词「javascript」,忽略大小写

var text = "testing: 1, 2, 3"
var pattern = /\d+/g          // 匹配所有包含一个或者多个数字的实例
pattern.test(text)            // => true 匹配成功
text.search(pattern)          // => 9 首次匹配成功的位置
text.match(pattern)           // => ["1", "2", "3"] 所有匹配组成的数组
text.replace(pattern, "#")    // => "testing: #, #, #"
text.split(/\D+/)             // => ["", "1", "2", "3"] 用非数字字符截取字符串

布尔值

JavaScript 中比较语句的结果通常都是布尔值,布尔值通常用于控制结构中。任意 JavaScript 的值都可以转换成布尔值。所有对象(数组)都会转换成 true, 面这些则都是 false

undefined
null
0
-0
NaN
""     // 空字符串

null 和 undefined

null 是 JavaScript 语言的关键字,执行 typeof 运算返回 「object」,也就是说,可以将 null 认为是一个特殊的对象值,含义是「非对象」。但实际上,通常认为 null 是它自有类型的唯一一个成员,它可以表示数字、字符串或对象是「无值」的

undefined 是一种取值,表明变量没有初始化,如果要查询对象属性或者数组元素的值时返回 undefined 则说明这个属性或者元素不存在。如果函数没有返回任何值,则返回 undefined引用没有提供实参的函数形参的值也只会得到 undefined。

undefined 不是关键字,是 JavaScript 预定义的全局变量,它的值就是「未定义」。ECMAScript 3 中,undefined 是 可读/写的变量,可以给它赋任意值。这个错误在 ECMAScript 5 中做了修正,变成了只读的。如果执行 typeof 运算得到 undefined 类型,则返回 “undefied”

null 和 undefined 都 不包含任何属性和方法

全局对象

全局对象的属性是全局定义的符号,JavaScript 程序可以直接使用。当解释器启动时,它将创建一个新的全局对象,并给它一组初始属性:

全局属性,比如 undefined, Infinity 和 NaN 全局函数,比如 isNaN(), parseInt(), eval() 构造函数,比如 Date(), RegExp(), String(), Object() 和 Array() 全局对象,比如 Math 和 JSON

全局对象的 初始属性 并不是保留字(可以被污染/重写),但它们应该当做保留字来对待。对于客户端的 JavaScript 来讲,Window 对象定义了一些额外的全局属性

包装对象

var s = "test", n = 1, b = true;
var S = new String(s);
var N = new Number(N);
var B = new Boolean(b);

s == S                  // => true
s === S                 // => false
typeof s                // => "string"
typeof S                // => "object"

可以通过 Number() 或 Boolean() 构造函数来显式创建包装对象,JavaScript 会在必要的时候将包装对象转换成原始值。上段代码中的对象 S, N 和 B 常常但不总是表现的和值 s, n 和 b 一样。「==」运算符将原始值和其包装对象视为相等,但「===」全等运算符将它们视为不等,通过 typeof 运算符可以看到原始值和其包装对象的不同

不可变的原始值和可变的对象引用

JavaScript 中原始值(undefined, null, 布尔值,数字和字符串)和对象(包括数组和函数)有着根本的区别,原始值是不可更改的,比如字符串的所有方法都是新返回一个值

var s = "hello";
s.toUpperCase();    // => "HELLO"
s                   // => "hello"

对象和原始值不同,首先,它他是 可变的 —— 值可以修改

var o = { x: 1};
o.x = 2;
oxy = 3;

var a = [1,2,3]
a[0] = 0;
a[3] = 4;

对象的比较并非值的比较,即使两个对象包含同样的属性及相同的值

var o = {x:1}, p = {x:1};
o === p                 // => false
var a = [], b = [];
a === b                 // => false

通常将对象

免责声明:

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。

本站信息来自网络收集整理,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!

发表评论:

抱歉,检测到您未登录,需要评论,请先