计算机 / 读书笔记 · 2022年8月13日 0

Professional JavaScript for Web Developers, 3rd Edition, Part 2

第 3 章 基本概念

1.语法

1.变量名、函数、操作符区分大小写

2.标识符

  • 第一个字符必须是一个字母、下划线或一个美元符号;
  • 其他字符可以是字母、下划线、美元符号或数字;
  • 标识符中的字母也可以包含扩展的ASCII或Unicode字母字符。

3.注释

使用//或/**/作为注释。

4.严格模式

可以在脚本的开头添加“use strict”;让整个脚本启用严格模式,或者在函数内部上方添加以让函数使用严格模式:

function doSomething() {
  "use strict";
  //函数体
}

5.语句

语句可以用或者不用作为结尾;

2.关键字和保留字

3.变量

定义变量时可以使用var关键字也可以不使用。使用var关键字的话创建的变量为当前作用域中的局部变量,退出当前作用域这个变量就销毁了。不使用var关键字则声明的是一个全局变量,退出当前作用域后仍然可以访问这个变量。

严格模式下不能定义名为eval或arguments的变量。

4.数据类型

5种基本数据类型:Undefined,Null,Boolean,Number和String。

1种复杂数据类型,Object,本质上是一种无序的名值对。

1.typeof操作符

typeof是操作符而不是函数,所以可以省略括号。

返回值

  • ‘undefined’,如果这个值未定义(声明了变量,但是未赋予具体的值);
  • ‘boolean’
  • ‘string’
  • ‘number’
  • ‘object’,如果这个值是对象或者null,因为null被认为是一个空的对象的引用;
  • ‘function’,如果这个对象是函数;

在ECMAScript中,函数是对象,不是一种数据类型,但是函数有一些特殊的属性,因此typeof将其特别区分了出来。

2.Undefined类型

Undefined表示声明了但是未初始化的变量,用来正式区分空对象指针null。

未初始化的变量只能执行一项操作,那就是typeof操作符。

未声明的变量typeof操作符也会返回undefined。

3.Null类型

null用来专门指代要用来保存对象,但是还未赋值的空指针。

undefined值派生自null值,因此ECMA-262规定它们的相等性测试要返回true。

当一个变量是用来保存对象引用的,就应该将其初始化为null。

4.Boolean类型

一定要使用true和false,大小写不能搞错。

各种数据类型转换为Boolean类型的规则:

数据类型转换为true的值转换为false的值
Booleantruefalse
String任何非空字符串“”(非空字符串)
Number任何非零数字值(包括无穷大)0和NaN
Object任何对象null
Undefinedundefined只有一个值,只能转为falseundefined

null不能转换为Boolean,而undefined可以。

5.Number类型

严格模式下八进制字面量无效。

如果数值可以用整型表示,那么JavaScript引擎会尽量将其用整型表示以节省空间;

所以Number的实现是一个32位int或者一个double。

特殊值:

  • Number.MIN_VALUE 5e-324
  • Number.MAX_VALUE 1.7976931348623157e+308
  • Infinity, -Infinity,计算结果的数值如果超出了这些范围,那么就用Infinity或-Infinity表示;另外提供isFinite函数来判断一个值是否是有限的;另外也可以使用Number.NEGATIVE_INFINITFY和Number.POSITIVE_INFINITY;
  • NaN,表示一个本来要返回数值的操作数未返回数值的情况,比如任何数值除以非数值。任何涉及NaN的操作结果都会返回NaN。可以用isNan函数判断是否为NaN,任何不能被转换为数值的值都会被isNaN函数返回false。对于Object类型,isNaN会先尝试调用其valueOf方法,判断该函数返回值是否可以转换为数值,如果不能再调用其toString方法,再测试其返回值是否能转换为数值。

数值转换

有3个函数可以把非数值转换为数值:Number(),parseInt()和parseFloat()。第一个函数可以用于任何类型,而后两个则专门用于字符串。

Number函数的转换规则:

  • 对于Boolean输入,true和false分别被转换为1和0;
  • 对于null输入,返回0;
  • 对于undefined,返回NaN;
  • 对于字符串,如果不能转换为数字,则将其转换为NaN;
  • 对于对象,先尝试转换其valueOf方法返回值,再尝试转换其toString方法返回值;

空字符串会被转换为0。空字符串”不是null也不是undefined。

对于’12blue’这种字符串,Number会转换为NaN,而parseInt会转换为12。

ECMAScript 3 JavaScript引擎支持八进制字面量,而ECMAScript 5 JavaScript引擎不支持。

parseInt函数可以通过第二个参数来指定解析字面量时使用的进制。

6.String类型

String类型用于表示由零或多个16位Unicode字符组成的字符串序列。

转义序列

  • ‘\xnn’ 以十六进制nn表示的一个字符,如’\x41’表示’A’
  • ‘\unnnn’以十六进制代码nnnn表示的一个Unicode字符,如\u03a3表示希腊字母Σ。

length属性可以返回字符串中字符数。

ECMAScript中的字符串是不可改变的。

除了null和undefined方法没有toString方法,其他类型都有toString方法。

String()方法则可以对任何类型使用,该方法会调用输入对象的toString方法,对于null和undefined则会分别返回’null’和’undefined’。

7.Object类型

通过new操作符可以创建新的对象。

var o = new Object();

如果不需要给构造函数传递参数,可以省略掉后面的括号。

每个Object类型都具有下面的属性和方法:

  • constructor,构造函数;
  • hasOwnProperty(propertyName),检查给定的属性是否在当前对象实例中存在,propertyName必须是以字符串形式作为参数;
  • isPrototypeOf(object),检查传入的对象是否是当前对象的原型;
  • propertyIsEnumerable(propertyName),检查给定的属性是否能够使用for-in语句,propertyName必须是以字符串形式作为参数;
  • toLocaleString,返回对象的字符串表示,该字符串与执行环境的地区对应;
  • toString,返回对象的字符串表示;
  • valueOf,返回对象的字符串、数值或布尔值表示。通常与toString方法返回值相同。

对于DOM和BOM中的对象,他们属于宿主对象,由宿主环境提供实现和定义,他们不属于ECMA-262定义的对象,所以宿主对象可能不会继承Object。

5.操作符

1.一元操作符

递增和递减操作符

一元加和减操作符 一元加和减操作符会返回一个数值型的结果。

2.位操作符

JavaScript会将整型数值转为32位有符号数然后再进行位操作,最后将位操作结果再转为double。

NaN和Infinity会被当做0处理。

无符号右移>>>

有符号右移>>

3.布尔操作符

4.乘性操作符

ECMAScript定义二楼3个乘性操作符:乘法、除法和求模。引擎会将非数值类型的操作数转换为数值类型。

  • Infinity和0相乘结果位NaN;
  • Infinify除以Infinity,结果为NaN;
  • 0除0,结果为NaN;
  • 非零的有限数除以零,结果为Infinitfy或-Infinity;

5.加性操作符

  • Infinitfy加-Infinity,结果为NaN;
  • +0加-0,结果为+0;
  • Infinity减Infinity,结果为NaN;
  • +0减+0,结果为+0;
  • -0减+0,结果为-0;
  • -0减-0,结果为+0;

如果有一个操作数是字符串,那么两个操作数都得转换为字符串。

6.关系操作符

操作数中有数值类型时需要都转换为数值进行比较;

否则按照字符串逐个字符进行比较。

7.相等操作符

相等和不相等,先转换再比较

  • 有布尔值,需要都转换为数值;
  • 一个是字符串,另一个是数值,需要都转为数值;
  • 一个是对象,另一个不是,需要调用对象的valueOf方法再比较;

比较规则

  • null 和undefined相等
  • 比较相等性之前,不能将null和undefined转为其他任何值
  • 有NaN,相等操作符返回false,不相等操作符返回true
  • 如果两个数都是对象,则比较他们是不是同一个对象,如果都指向同一个对象,则相等操作符返回true,否则返回false

全等(===)和不全等(!==),仅比较而不转换

8.条件操作符

9.赋值操作符

10.逗号操作符

逗号操作符会返回表达式中的最后一项。

6.语句

1.for-in语句

可以使用for (property in expression) statement或者for (var property in expression) statement,为了保证使用局部变量,最好把var加上。

如果要迭代的对象的值为null或undefined,ECMAScript不会执行这个循环。老旧版本则会抛出异常,所以为了兼容性最好在执行之前测试对象是否为null或undefined。

2.label语句

定义一个break和continue可以调整的标签。

label: statement

3.break和continue语句

break和continue可以联合label,指定break/continue外层循环。

        var num = 0;
        
        outermost:
        for (var i=0; i < 10; i++) {
             for (var j=0; j < 10; j++) {
                if (i == 5 && j == 5) {
                    break outermost;
                }
                num++;
            }
        }
        
        alert(num);    //55
        var num = 0;
        
        outermost:
        for (var i=0; i < 10; i++) {
             for (var j=0; j < 10; j++) {
                if (i == 5 && j == 5) {
                    continue outermost;
                }
                num++;
            }
        }
        
        alert(num);    //95

4.with语句

with(expression) statement;

使用with语句关联对象后,代码的作用域被设置到这个特定的对象中,代码中的变量先被认为是局部变量,如果局部环境没有定义这个变量,再查找这个对象中是否有这个变量。

严格模式不允许使用with语句。

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

可以通过with语句简化为

        with(location){
            var qs = search.substring(1);
            var hostName = hostname;      //unavailable when viewing from a local file
            var url = href;
        }

5.switch语句

ECMAScript的switch语句特色在于可以使用任何类型,甚至可以使用表达式。

switch语句在比较值时使用的是全等操作符,因此不会发生类型转换。

7.函数

严格模式对函数的限制:

  • 不能把函数命名为eval或arguments
  • 不能把参数命名为eval或arguments
  • 不能出现两个命名参数同名的情况;

ECMAScript函数定义的参数个数与调用时传递的参数个数可以不同,调用时传递的参数会保存在arguments数组里(数组长度与调用时传递的参数个数一致)。在函数内部可以通过arguments数组访问函数参数列表。通过arguments访问的函数参数和通过命名参数访问的函数参数效果是一样的,他们的值总会保持同步(但他们的内存空间是独立的),但是如果调用时只传了一个参数,那么修改arguments[1]是不会将变化反映到第二个命名参数的。

严格模式下对arguments的重写操作无效,即对arguments的修改不会反映到命名参数上。

未传递值的命名参数的值默认为undefined。

ECMAScript函数不能实现重载。

两个名字相同的函数,后面的函数会覆盖掉前面的函数。

ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数。

这个按值传递参数,相当于ECMAScript不能实现C++中的那种通过引用传递参数的功能:

int increment(int &x);