《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 |
---|---|---|
\o | NUL 字符 | \u0000 |
\b | 退格符 | \u0008 |
\t | 水平制表符 | \u0009 |
\n | 换行符 | \u0009 |
\v | 垂直制表符 | \u0009 |
\f | 换页符 | \u0009 |
\r | 回车符 | \u0009 |
\” | 双引号 | \u0009 |
\’ | 单引号 | \u0009 |
\ | 反斜线 | \u0009 |
\xXX | 2位十六进制数XX指定的 Latin-1 字符 | |
\uXXXX | 4位十六进制数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个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!
发表评论: