JavaScript 高级程序设计笔记(三)

第三章 基本概念

3.1 语法

ECMAScript 区分大小写,标识符必须按照下列格式:

  • 首字符必须是一个字母、下划线 _ 或美元符号 $
  • 其他字符可以是字母、下划线、美元符号2或数字

ECMAScript 标识符惯用驼峰大小写格式

ECMAScript 5 引入了严格模式,该模式下一些不确定的行为将得到处理,对某些不安全的操作会抛出错误。启用严格模式,可以在顶部添加:

"use strict"

它是一个编译指示,告诉 JavaScript 引擎切换到严格模式,也可以指定函数在严格模式下执行:

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

严格模式下,JavaScript 的执行结果会有很大不同

ECMAScript 语句以分号 ; 结尾,虽然可以省略,但不推荐

3.2 关键字和保留字

ECMA-262 的关键字(带*号的是第五版新增的关键字)

ECMA-262 第五版的保留字(非严格模式)

ECMA-262 第五版的保留字(严格模式)

3.3 变量

ECMAScript 变量是松散型的,即可以用来保存任何类型的数据,换句话说每个变量仅仅是个保存值的占位符而已。不过我们不建议修改变量所保存值的类型。

用 var 定义的变量只在该变量出生的作用域中生效。但是定义变量时去掉 var,则会创建一个全局变量

function test(){  
    message = "hi"; // 全局变量      
}
test();  
alert(message); // "hi"  

省略了 var,message 就成了全局变量,这种做法不推荐

3.4 数据类型

ECMAScript 有五种基本数据类型和一种复杂数据类型:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Object

最后一种复杂数据类型 Object,它本质是由一组无序的键值对组成。ECMAScript 不支持任何创建自定义类型的机制,所有值都是上述六种类型之一。

3.4.1 typeof 操作符

typeof 操作符用字符串的形式返回给定变量的数据类型,有下面几种结果:

  • "undefined" 这个值未定义
  • "boolean" 这个值是布尔值
  • "string" 这个值是字符串
  • "number" 这个值是数值
  • "object" 这个值是对象或 null
  • "function" 这个值是函数

typeof null 会返回 "object",因为 null 被认为是一个空对象的引用。

3.4.2 Undefined 类型

Undefined 类型只有一个值,即特殊的 undefined。使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined

var message;  
alert(message == undefined); //true  

对未声明的变量调用 typeof 也会返回 "undefined" 值

var message;             // 这个变量声明之后默认取得了 undefined 值   

// 下面这个变量并没有声明  
// var age

alert(typeof message);    // "undefined"  
alert(typeof age);        // "undefined"  

3.4.3 Null 类型

Null 类型同样也只有一个值,即特殊的 null。从逻辑角度看,null 值表示一个空对象指针。这也是用 typeof 操作符检测 null 值返回 "object" 的原因

var car = null;  
alert(typeof car);    // "object"  

如果定义的变量准备在将来用于保存对象,那么最后将该变量初始化为 null 而不是其他值。直接检查 null 值就可以知道相应的变量是否保存了一个对象的引用:

if (car != null){  
//  do something        
}

undefined 值是派生自 null 值的

alert(null == undefined);    //true  

3.4.4 Boolean 类型

该类型只有两个字面量:true 和 false,这两个值与数字值不是一回事,ture 不一定等于 1,false 也不一定等于 0

ECMAScript 中所有类型都可以通过转型函数 Boolean() 转换为其对应的 Boolean 值

3.4.5 Number 类型

使用 IEEE754 格式来表示整数和浮点数值

var intNum = 55;       // 整数  
var octalNum1 = 070;   // 八进制  
var hexNum2 = 0x1f;    // 十六进制  

浮点数需要的内存空间是整数的两倍,ECMAScript 会在允许的情况下自动优化将浮点数转换成整数值表示。极大或极小的浮点数可以用 e 表示法:

var floatNum = 3.125e7; //   31250000  

浮点数在计算时精度远不如整数,比如 0.1 + 0.2 结果不是 0.3

ECMAScript 最小值为 Number.MIN_VALUE,最大值为 Number.MAX_VALUE,超出范围自动转换为 特殊的 Infinity 值,负数是 -Infinity。我们可以用 isFinite() 函数来判断是否位于合理范围中

var result = Number.MAX_VALUE + Number.MAX_VALUE;  
alert(isFinite(result)); //false  

NaN 是一个特殊的数值,用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛错了)。它有两个特点要注意:

  • 任何涉及 NaN 的操作(NaN/10)都会返回 NaN
  • NaN 与任何值都不相等,包括 NaN 本身,比如 alert(NaN == NaN); //false

针对这两个特点,ECMAScript 定义了 isNaN() 函数,接受一个参数(可以是任意类型),返回一个 Bool 类型来说明是否“不是数值

alert(isNaN(NaN));    //true  
alert(isNaN(10));     //false 10 是一个数值  
alert(isNaN("10"));   //false 可以被转换成数值 10  
alert(isNaN("blue")); //true(不能被转换成数值)  
alert(isNaN(true));   //false(可以被转换成数值 1)  

基于对象调用 isNaN() 时,首先会调用对象的 valueOf() 方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值在调用 toString() 方法,再测试返回值。

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

Number() 转换时规则比较复杂,更常用 parseInt() 它主要是看其是否符合数值模式,也会忽略字符串前面的空格。如果排除掉空格后第一个字符不是数字字符或者符号,parseInt() 就会返回 NaN;如果第一个字符是数字字符,parseInt() 会继续解析第二个字符,直到解析完所有后续字符或遇到一个非数字字符。比如 "1234blue" 会被解析为 1234。

var num1 = parseInt("1234blue");    // 1234  
var num2 = parseInt("");            // NaN  
var num3 = parseInt("0xA");         // 10(十六进制)  
var num4 = parseInt(22.5);          // 22  
var num5 = parseInt("070");         // 56(八进制数)  
var num6 = parseInt("70");          // 70(十进制数)  
var num7 = parseInt("0xf");         // 15(十六进制数)  

对于 var num = parseInt("070"); ECMAScript 3 认为是 56(八进制),ECMAScript 5 认为 70(十进制)

为了消除歧义,可以指定第二个参数作为基数

var num1 = parseInt("10", 2);   //2(按二进制解析)  
var num2 = parseInt("10", 8);   //8(按八进制解析)  
var num3 = parseInt("10", 10);  //10(按十进制解析)  
var num4 = parseInt("10", 16);  //16(按十六进制解析)  

parseFloat() 也是从第一个字符开始解析知道末尾,字符串中第一个小数点有效,第二个就无效了。parseFloat() 只解析十进制,会始终忽略前导的零,也没有第二个参数作为进制基数。

var num1 = parseFloat("1234blue");  //1234(整数)  
var num2 = parseFloat("0xA");       //0  
var num3 = parseFloat("22.5");      //22.5  
var num4 = parseFloat("22.34.5");   //22.34  
var num5 = parseFloat("0908.5");    //908.5  
var num6 = parseFloat("3.125e7");   //31250000  

3.4.6 String 类型

String 类型用于表示由零个或多个 16 位 Unicode 字符组成的字符序列,单双引号表示都有效。它包括一些特殊的字符字面量:

ECMAScript 中的字符串是不可变的,赋新值完成后会销毁旧值

把一个值转换为一个字符串有两种方式

  1. 使用几乎每个值都有 toString() 方法,数值、布尔值、对象和字符串都有 toString() 方法,nullundefined 值没有

    var age = 11;
    var ageAsString = age.toString(); //字符串 "11" 
    var found = true;
    var foundAsString = found.toString(); //字符串 "true"
    
  2. 使用转换函数 String(),该函数支持了 nullundefined

    • 如果值有 toString() 方法,则调用
    • 如果值是 null,则返回 "null"
    • 如果值是 undefined,则返回 "undefined"

3.4.7 Object 类型

ECMAScript 中的对象其实就是一组数据和功能的集合,Object 类型是它所有实例的基础。Object 类型所具有的任何属性和方法也都存在于更具体的对象中。Object 每个实例都具有下列属性和方法(七个)

  • constructor 保存着用于创建当前对象的函数
  • hasOwnProperty(propertyName) 检查给定的属性在当前实例中是否存在 o.hasOwnProperty("name")
  • isPrototypeOf(object) 检查传入的对象是否是当前对象的原型
  • propertyIsEnumerable(propertyName) 检查给定的属性是否能用 for-in 枚举
  • toLocaleString() 返回当前语境下的字符串表示
  • toString() 返回对象的字符串表示
  • valueOf() 返回对象的字符串、数值或布尔值表示

3.5 操作符

ECMA-262 描述了一组操作符,包括算术操作符(加和减)、位操作符、关系操作符和相等操作符。ECMAScript 的操作符并不局限于数值,它适用于很多类型值,包括字符串、数组、布尔值、甚至对象。但在应用对象时,通常会调用它的 valueOf()toString() 方法,以便取得可操作值。

3.5.1 一元操作符

主要包括递增和递减,一元加和一元减操作符,它们不仅适用于整数值,还适用于浮点数、字符串、布尔值和对象,应用不同类型遵循一下规则:

  • 包含有效数字字符的字符串先转换为数字值在执行操作
  • 不包含有效数字字符的字符串,将变量值设为 NaN
  • 在应用于布尔值 false 时,现将其转换为 0;而 true 时,转换为 1
  • 应用于浮点数时正常执行
  • 应用于对象时,先调用对象的 valueOf() 方法,取得可操作值,然后再应用前面的规则。如果结果是 NaN,则再调用 toString() 方法

3.5.2 位操作符

位操作符并不直接操作 64 位的值,而是先将 64 位转换为 32 位再执行操作,最后再将结果转换回 64 位。

负数使用的是二进制的补码存储。

对于非数值应用位操作符,会先使用 Number() 函数将该值转换为一个数值,再应用位操作。NaN 和 Infinity 都被当做 0 处理。

3.5.3 布尔操作符

布尔操作符也可以应用于 ECMAScript 中任意类型的值,返回值依具体情况而视

  • 逻辑非

  • 逻辑与操作属于短路操作,即第一个操作数能决定结果不会对查看第二个

  • 逻辑或也属于短路操作

利用逻辑或的短路操作特性,为变量准备一个后备值,防止为 null 或 undefined 值

var myObject = preferredObject || backupObject;  

3.5.4 乘性操作符

ECMAScript 定义了 3 个乘性操作符:乘法、除法、取模。在操作符为非数值类型时会先使用 Number() 转换后执行操作。

  • 乘法

  • 除法

  • 取模

3.5.5 加性操作符

  • 加法,如果两个操作符都是数值,执行常规的加法,遵循下面规则:

    如果有一个操作符是字符串,则应用如下规则:

  • 减法

3.5.6 关系操作符

和前面一样,当关系操作符的操作数使用了非数值时,也要进行数据转换

大写字母的编码小于小写字母的编码

3.5.7 相等操作符

ECMAScript 提供了两组比较操作符:相等和不相等(先转换再比较),全等和不全等(仅比较不转换

  1. 相等和不相等(== 和 !=),在转换不同类型的数据时,遵循以下基本规则:

    比较时的一些特殊情况

  2. 全等和不全等比较时不转换,不同类型直接判别为不相等

3.6 语句

  • if 语句
  • do-while 语句
  • while 语句
  • for 语句
  • for-in 语句 输出的属性名顺序不可测,如果被迭代的对象为 null 或 undefined,则中止循环
  • label 语句 配合 for 等循环语句使用,可以被 break 和 continue 调用
  • break 和 continue 语句 跳出和跳过循环
  • switch 语句
    • 可以使用任何数据类型,每个 case 的值也不一定是常量,可以是变量或表达式
    • switch 语句在比较值时使用的全等操作,不会发生类型转换

3.7 函数

ECMAScript 中的函数在定义时不必指定是否有返回值,因为任何 ECMAScript 函数可以在任意时刻返回任意值,而未定义返回值的函数返回的是一个特殊的 undefined 值

3.7.1 理解参数

ECMAScript 函数不介意传递进来参数的个数和类型,它内部是用数组表示的,函数接受到的始终是这个数组,而不关心数组中包含哪些参数,函数体内可以通过 arguments 对象来访问这个参数数组。

arguments 对象只是与数组类似,但并不是 Array 的实例

function sayHi() {  
    alert("Hello " + arguments[0] + "," + arguments[1]);
}

ECMAScript 中没有函数签名的概念,命名参数只是提供便利,但不是必需,解析器也不会验证命名参数。

arguments 中的值永远与对应命名参数的值保持同步

function doAdd(num1, num2) {  
      arguments[1] = 10;
      alert(arguments[0] + num2);
}

每次执行 doAdd 函数都会重新第二个参数的值为 10,因为 arguments 对象中的值会自动反映到对应命名参数,所以修改了 arguments[1] 也就修改了 num2

注意:但是它们的内存空间是独立的,只不过值会同步;上述代码严格模式无效

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

3.7.2 没有重载

由于不存在函数签名的特性,所以不存在函数重载,定义两个同名函数,后定义的执行

function addSomeNumber(num){  
    return num + 100;
}
function addSomeNumber(num) {  
    return num + 200;
}
var result = addSomeNumber(100);  
//300

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!