本章内容
标识符:变量、函数、属性的名字,或者函数的参数;标识符的格式规则如下:
// 单行注释
/*
*多行注释
*(块级注释)每行前面加*是可以不写,但是写的话可以提高注释的可读性。
*/
“use strict”
ECMAScript5引入了严格模式的概念。在顶部添加,是为了不破坏ECMAScript3语法而特意选定的语法,是一个编译指示。定义一种不同的解析和执行模型,为了将一些不确定的行为、不安全的操作得到处理,并抛出错误。也可以指定函数在严格模式下执行:
function doSomething(){
“use strict”;
//函数体
}
可以省略分号,解析器会确定语句的结尾,但是强烈不推荐这样,要求每个语句结尾都加分号,可以避免很多错误,加分号在某种情况下会增进代码的性能,解析器就不用花时间推测应该在哪里插入分号了;
语句块中只有一条语句的时候可以不加花括号“{}”但是不建议这样写,我们要求一条语句的时候也加花括号,质这样可以让编码意图更加清晰,而且也能降低修改代码时的出错几率;
现已推出ECMAScript6,其关键字和保留字与ECMAScript5的关键字和保留字有不同:ECAMAScript3、ECMADScript5、ECMAScript6关键字和保留字如下:
ECMAScript 的全部关键字(带*号上标的是第 5版新增的关键字):
break | do | instanceof | typeof | case | else | new | var |
---|---|---|---|---|---|---|---|
catch | finally | return | void | continue | for | switch | while |
debugger* | function | this | with | default | if | throw | delete |
in | try |
__以下是 ECMA-262第 3版定义的全部保留字: __
abstract | short | boolean | export | interface | static | enum | int |
---|---|---|---|---|---|---|---|
static | byte | extends | long | super | char | final | native |
synchronized | class | float | package | throws | const | goto | private |
transient | debugger | implements | protected | volatile | double | import | public |
__ 第 5版把在非严格模式下运行时的保留字缩减为下列这些: __
class | enum | extends |
---|---|---|
super | const | export |
import |
第五版严格模式下:
implements | package | public |
---|---|---|
interface | private | static |
let | protected | yield |
第六版新增了let和const关键字
总结:
定义变量:
var message; // 定义一个名为message的变量,该变量可以保存任何值,未初始化的变量的值默认 // 为undefined。
var message = "hi"; // 为变量message赋一个字符串为“hi”的值。像这样初始化变量并不会把它 //标记为字符串类型; 初始化的过程就是给变量赋一个值那么简单。
message = 10; // 该值又被一个数字值 100取 代。虽然我们不建议修改变量所保存值的类 //型,但这种操作在 ECMAScript中完全有效
用 var操作符定义的变量将成为定义该变量的作用域中的局部变量:
function test(){
var message = "hi"; //局部变量
}
test();
console.log(message); //错误
//如果在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁
function test(){
message = "hi"; //全局变量省略了 var 操作符,因而 message 就成了全局变量
} //只要调用过一次 test()函 数,这个变量就有了定义,就可以在函数外部 //的任何地方被访问到。
test();
console.log(message);
虽然省略 var 操作符可以定义全局变量,但这也不是我们推荐的做法。因为在局 部作用域中定义的全局变量很难维护,而且如果有意地忽略了 var 操作符,也会由于 相应变量不会马上就有定义而导致不必要的混乱。给未经声明的变量赋值在严格模式 下会导致抛出 ReferenceError 错误!
var message = "hi", // 使用不同的类型初始化变量的操作可以放在一条语句中完成。
found = false,
age = 29;
__在严格模式下,不能定义名为 eval 或 arguments 的变量,否则会导致语法错误。 __
用于检测给定变量的数据类型——typeof:
“undefined”——如果这个值未定义;
“boolean”——如果这个值是布尔值;
“string”——如果这个值是字符串;
“number”——如果这个值是数值;
“object”——如果这个值是对象或null;
“function”——如果这个值是函数;
var message = "good time";
console.log(typeof(message); //string
console.log(typeof message); //string typeof是操作符不是函数所以圆括号可以使用但是也不是必须
console.log(typeof 999); // typeof的操作数可以是变量也可以是字面量;
console.log(typeof null); //object 因为null被认为是一个空的对象引用。
Safari 5及之前版本、Chrome 7及之 前版本在对正则表达式调用 typeof 操作符时会返回"function",而其他浏览器在这种情况下会返回 “object”。
__从技术角度讲,函数在 ECMAScript中是对象,不是一种数据类型。然而,函数也 确实有一些特殊的属性,因此通过 typeof 操作符来区分函数和其他对象是有必要的。
__
第 3版引入这个值是为了正式区分空对象指针与未经初始化的变量
var message ;
console.log(message == undefined); //true 未初始化的变量的值会默认为undefined;
console.log(age); // 未声明的值会出错
console.log(typeof message); //undefined;
console.log(typeof age); //undefined; 未声明的变量执行typeof也是返回undefined。
var car = null;
console.log(typeof car); // object ;null是表示一个空对象的指针
如果定义的变量准备在将来用于保存对象,那么最好将该对象初始化为null。
console.log(null == undefined); // true ;实际上undefined值是派生自null值的,因此ECMA-262规定他们相等性测试返回true;
位于 null 和 undefined 之间的相等操作符(==)总是返回 true,不过要注意的是,这个 操作符出于比较的目的会转换其操作数
__只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存 null 值。这样做不仅可以 体现 null 作为空对象指针的惯例,而且也有助于进一步区分 null 和 undefined。 __
boolean字面值:true和false //是区分大小写的,True和False都是标识符,不是Boolean值
转型函数boolean();转换规则:
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “”(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | n/a(not applicable不适用) | undefined |
var message = "hello world !";
if (message){
console.log("value is true");
}
if语句会自动执行相应的Boolean转换函数。
这种类型使用 IEEE754格式来表示 整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。为支持各种数值类型,ECMA-262 定 义了不同的数值字面量格式。
十进制:
var intNum = 55; //整数
八进制:字面值的第一位必须为零0;然后八进制数字序列(0~7),如果超出范围,那么将解析为十进制。八进制在严格模式下会无效,会导致支持的JavaScript引擎抛出错误;
var octalNum1 = 070; //八进制的56
var octalNum2 = 079; //无效的八进制 79
var octalNum3 = 08; //无效的八进制 8
十六进制:十六进制的字面值的前两位必须时0x,后跟任何十六进制的数字(09及AF)。其中A~F可以大写也可以小写:
var hexNum1 = 0xA; // 十六进制的10
var hexNum2 = 0x1f; //十六进制的31
注意:
浮点数就是该数值中包含一个小数点,并且小数点后面必须至少有一位数,对然小数点前面可以没有整数,但是我们不推荐这种写法。
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; // 有效但是不推荐
由于保存浮点数值需要的内存空间时保存整数的两倍,因此ECMAScript会不失时机地将浮点数值转换为整数值。
var floatNum1 = 1.; //小数点后面数字所以解析为1
var floatNum2 = 10.0; //整数 ;解析为10
对于极大或极小的数值,可以用e表示法(即科学记数法)表示的浮点数值表示法,用e表示法表示的数值等于e前面的数值乘以10的指数次幂:
var floatNum = 3.12e7; // 等于31200000
var floatNum2 = 3.1e-7; // 等于0.00000031
默认情况下,ECMAScript会将那些小数点后面带有6个0以上的浮点数转换为以e表示法表示数值。
浮点数的最高精度是17位小数,但在进行算数计算时其精确度远远不如整数。列如,0.1加0.2的结果不是0.3,而是 0.30000000000000004.这个小小的舍入误差会导致无法测试特定的浮点数值,所以永远不要测试某个特定的浮点数;
var result = Number.MAX_VALUE + Number.Max_VALUE;
console.log(isFinite(result); //false
NaN,即非数值(not number)是一个特殊的数值,用来表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。在ECMAScript中,任何数值除以0都会返回NaN,因此不会影响其他代码的执行。
1.任何涉及NaN的操作都会返回NaN:
console.log(NaN/10); // 返回NaN
2.NaN与任何值都不想等包括NaN本身:
console.log(NaN == NaN); //false
3.函数NaN可以接受一个参数,该参数可以是任何类型,接收到数值后,会尝试将这个值转换为数值即调用number()函数;任何不能被转换为数值的值都会导致这个函数返回true;
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false(10是一个数值)
alert(isNaN("10")); //false(可以被转换成数值 10)
alert(isNaN("blue")); //true(不能转换成数值)
alert(isNaN(true)); //false(可以被转换成数值 1)
__isNaN()函数也适用与对象。__在基于对象调用 isNaN() 函数时,会首先调用对象的 valueOf()方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用 toString()方法,再测试返回值。
将非数值转为数值有三个函数:Number()、parseInt()和parseFloat()。Number()转型函数可以用于任何数据类型,而parseInt()和parseFloat()专门用于把字符串转换为数值。
如果是 Boolean 值,true 和 false 将分别被转换为 1和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。 __
如果是字符串,遵循下列规则:
如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,“123"会变成 123__,而"011"会变成 11(注意:前导的零被忽略了);
如果字符串中包含有效的浮点格式,如"1.1”,则将其转换为对应的浮点数值(同样,也会忽 略前导零);
如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整 数值;
如果字符串是空的(不包含任何字符),则将其转换为 0;
如__果字符串中包含除上述格式之外的字符,则将其转换为 NaN。 __
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符串值。
(一元操作符的操作与Number()函数相同)
由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的时parseInt()函数。
它会忽略字符串前面的空格,直至找到第一个非空格字符。__如果第一个字符不是数字字符或者符号,parseInt()就会返回NaN。也就是说用parseInt()转换空字符串会返回NaN(Number()对空字符串返回0)。parseInt()函数在解析时遇到一个非数字字符时停止。
var ba ="122f";
console.log(parseInt(ba)); // 返回122
var ma = "122.5";
console.log(ma); // 返回122 因为小数点不是数字字符
parseInt()也可以解析八进制和十六进制:
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(十六进制数)
在使用parseInt()时,ECMAScript 5 JavaScript引擎中,已经不具有解析八进制的能力了。在非严格模式下也是如此。
为解决上述困惑,函数parseInt()提供了__第二个参数:转换时使用的基数(即多少进制):
var num = parseInt("0xAF", 16); //175
var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN
var num1 = parseInt("10", 2); //2 (按二进制解析)
var num2 = parseInt("10", 8); //8 (按八进制解析)
var num3 = parseInt("10", 10); //10 (按十进制解析)
var num4 = parseInt("10", 16); //16 (按十六进制解析)
不指定基数意味着让 parseInt()决定如何解析输入的字符串,因此为了避免错误的解析,我们建议无论在什么情况下都明确指定基数。因此始终将 10 作为第二个参数是非常必要的。
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
String类型用于表示由0或多个16位Unicode字符组成的字符序列,即字符串。可以用双引号和单引号表示:用双引号和单引号表示的字符串完全相同;
String 数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其 他用途的字符。
\n 换行
\t 制表
\b 空格
\r 回车
\f 进纸
\\ 斜杠
\' 单引号('),在用单引号表示的字符串中使用。例如:'He said, \'hey.\''
\" 双引号("),在用双引号表示的字符串中使用。例如:"He said, \"hey.\""
\xnn 以十六进制代码nn表示的一个字符(其中n为0~F)。例如,\x41表示"A"
\unnnn 以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)。例如,\u03a3表示希腊字符Σ
这些字符字面量可以出现在字符串中的任意位置,而且也将被作为一个字符来解析:
var text = "This is the letter sigma: \u03a3.";
//变量 text 有 28个字符,其中 6个字符长的转义序列表示 1个字符
alert(text.
length
); // 输出 28
这个属性返回的字符数包括 16 位字符的数目。如果字符串中包含__双字节字符__,那么 length 属性可能__不会精确__地返回字符串中的字符数目。
ECMAScript中的字符串是不可变的,要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。
var lang = "Java";
lang = lang + "Script";
首先创建一个能容纳 10个字符的 新字符串,然后在这个字符串中填充"Java"和"Script",后一步是销毁原来的字符串"Java"和字 符串"Script",因为这两个字符串已经没用了.
两种方法:
__toString():__几乎每个值都有的 toString()方法:
var age = 11;
var ageAsString = age.toString(); // 字符串"11"
var found = true;
var foundAsString = found.toString(); // 字符串"true"
但 null 和 undefined 值没有这个方法。
在调用数值的 toString()方法时,可 以传递一个参数:输出数值的基数。默认情况下,toString()方法以十进制格式返回数值的字符串表 示。而通过传递基数,toString()可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。
var num = 10; alert(num.toString()); // "10"
alert(num.toString(2)); // "1010"
alert(num.toString(8)); // "12"
alert(num.toString(10)); // "10"
alert(num.toString(16)); // "a"
String()方法,能将任何类型的值转换为字符串:
如果值有 toString()方法,则调用该方法(没有参数)并返回相应的结果;
如果值是 null,则返回"null";
如果值是 undefined,则返回"undefined"。
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // "10"
alert(String(value2)); // "true"
alert(String(value3)); // "null"
alert(String(value4)); // "undefined"
__要把某个值转换为字符串,可以使用加号操作符,把它与一个字符 串("")加在一起。 __
ECMAScript中的对象其实就是__一组数据和功能的集合__。对象可以通过执行 new 操作符后跟要创建的对象类型的名称来创建。
在 ECMAScript中, (就像 Java 中的 java.lang.Object 对象一样)Object 类型是所有它的实例的基础。换句话说, Object 类型所具有的任何属性和方法也同样存在于更具体的对象中。
Object 的__每个实例__都具有下列属性和方法:
constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor) 就是 Object()。
hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例 的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例 如:o.hasOwnProperty(“name”))。
isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原型) 。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句 (本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符串形式指定。
toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同。
__由于在 ECMAScript中 Object 是所有对象的基础,因此所有对象都具有这些基本的属性和方法。 __
ECMA-262不负责定义宿主对象,因此宿主对象可能会也 可能不会继承 Object。
只能操作一个值的操作符叫做一元操作符。
执行前置递增和递减操作时,变量的值都是在语句被求值以前改变的。(在计算机科学领域,这种 情况通常被称作副效应。)
var age =29;
console.log(++age); // 30 输出前执行++操作
console.log(--age); //29 输出前执行--操作
执行后置递增和递减操作时,变量的值都是在语句被求值之后改变的。
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 等于 22
var num4 = num1 + num2; // 等于 21
所有这 4个操作符对任何值都适用,也就是它们不仅适用于整数,还可以用于字符串、布尔值、浮 点数值和对象。在应用于不同的值时,递增和递减操作符遵循下列规则。
在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字符串变量变成数值变量。
在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN(第 4章将详细讨论)。字符串变量变成数值变量。
在应用于布尔值 false 时,先将其转换为 0再执行加减 1的操作。布尔值变量变成数值变量。
在应用于布尔值 true 时,先将其转换为 1再执行加减 1的操作。布尔值变量变成数值变量。
在应用于浮点数值时,执行加减 1的操作。
在应用于对象时,先调用对象的 valueOf()方法以取得一个可供操作的值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规则。对象变量变成数值变量。
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
} };
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(由于浮点舍入错误所致)
o--; // 值变成数值-2
在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换:
布尔值 false 和 true 将被转换为 0和 1;
字符串值会被按照一组特殊的规则进行解析;
而对象是先调用它们的 valueOf()和(或)toString()方法,再转换得到的值。
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
} };
s1 = +s1; // 值变成数值 1
s2 = +s2; // 值变成数值 1.1
s3 = +s3; // 值变成 NaN
b = +b; // 值变成数值 0
f = +f; // 值未变,仍然是 1.1
o = +o; // 值变成数值-1
在将一元减操作符应用于数值时,该值会变成负数(如上面的例子所示)。而当应用于非数值时, 一元减操作符遵循与一元加操作符相同的规则,后再将得到的数值转换为负数:
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
` } };
s1 = -s1; // 值变成了数值-1
s2 = -s2; // 值变成了数值-1.1
s3 = -s3; // 值变成了 NaN
b = -b; // 值变成了数值 0
f = -f; // 变成了-1.1
o = -o; // 值变成了数值 1 `
一元加和减操作符主要用于基本的算术运算,也可以像前面示例所展示的一样用于转换数据类型。
ECMAScript 中的所有数 值都以 IEEE-754 64位格式存储,但位操作符并不直接操作 64位的值。而是先将 64位的值转换成 32位 的整数,然后执行操作,后再将结果转换回 64位。
负数同样以二进制码存储,但使用的格式是二进制补码(正数的二进制反码加一)。
(1) 求这个数值绝对值的二进制码(例如,要求18的二进制补码,先求 18的二进制码);
(2) 求二进制反码,即将 0替换为 1,将 1替换为 0;
(3) 得到的二进制反码加 1。
在处理有符号整数时,是不能访问位 31的。 默认情况下,ECMAScript 中的所有整数都是有符号整数。
在 ECMAScript中,当对数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成 32 位数值,然后执行位操作,后再将 32位的结果转换回 64位数值。但这个转换过程也导致了一个严重的副效应,即在对特殊的 NaN 和 Infinity 值应用位操作时,这两个值都会被当成 0来处理;
如果对__非数值应用位操作符__,会先使用 Number()函数将该值转换为一个数值(自动完成),然后 再应用位操作。得到的结果将是一个数值
执行按位非的结果就是返回数值的__反码__。
var num1 = 25; // 二进制 00000000000000000000000000011001
var num2 = ~num1; // 二进制 11111111111111111111111111100110
alert(num2); // -26 按位非操作的本质:操作数的负值减 1
按位非是在数值表示的底层执行操作,因此速度更快,(实现一个数值的负数减1,用按位取反操作速度更快。)
`var result = 25 & 3; `
alert(result); //1
__按位与操作只在两个数值的对应位都是 1时才返回 1,任何一位是 0,结果都是 0。 __
按位或操作在有一个位是1的情况下就返回1,而只有在两个位都是0的情况下才返回 0。
var result = 25 | 3;
alert(result); //27
__这个操作在两个数值对应位上只有一个 1时才返回 1,如果对 应的两位都是 1或都是 0,则返回 0。 __
var result = 25 ^ 3;
alert(result); //26
var oldValue = 2; // 等于二进制的 10
var newValue = oldValue << 5; // 等于二进制的 1000000,十进制的 64
左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数,在向左移位后,原数值的右侧多出空位。左移操作会以 0来填充这些空位,左移不会影响操作数的符号位。
__有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即 正负号标记)。有符号的右移操作与左移操作恰好相反,即如果将 64向右移动 5位,结果将变回 2: __
var oldValue = 64; // 等于二进制的 1000000
var newValue = oldValue >> 5; // 等于二进制的 10 ,即十进制的 2
在移位过程中,原数值中也会出现空位。只不过这次的空位出现在原数值的左侧、符号位的 右侧。而此时 ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值。
无符号右移操作符由 3个大于号(>>>)表示,这个操作符会将数值的所有 32位都向右移动。对正 数来说,无符号右移的结果与有符号右移相同。
var oldValue = 64; // 等于二进制的 1000000
var newValue = oldValue >>> 5; // 等于二进制的 10 ,即十进制的 2
无符号右移是以 0来填充空位,而不是像有符号右移那样以符号位的值来填充空位。所以,对正数的无符号右移与有符号右移结果相同。无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值的二进制补码形式表示,因此就会导致无符号右移后的结果非常之大。
var oldValue = -64; // 等于二进制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 等于十进制的 134217726
逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再 对其求反:
如果操作数是一个对象,返回 false;
如果操作数是一个空字符串,返回 true;
如果操作数是一个非空字符串,返回 false;
如果操作数是数值 0,返回 true;
如果操作数是任意非 0数值(包括 Infinity),返回 false;
如果操作数是 null,返回 true;
如果操作数是 NaN,返回 true;
如果操作数是 undefined,返回 true
同时使用两个逻辑非操作符,实际 上就会模拟 Boolean()转型函数的行为。
在有一个操作数不是布尔值的情况 下,逻辑与操作就不一定返回布尔值:
如果第一个操作数是对象,则返回第二个操作数;
如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该对象;
如果两个操作数都是对象,则返回第二个操作数;
如果有一个操作数是 null,则返回 null;
如果有一个操作数是 NaN,则返回 NaN;
如果有一个操作数是 undefined,则返回 undefined
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。第一个操作数是false的话,无论第二个值无论是什么都不会返回true; 在使用逻辑与操作符时要始终铭记它是一个短路操作符;
var found = true;
var result = (found && someUndefinedVariable); // 这里会发生错误
alert(result); // 这一行不会执行
当执行逻辑与操作时会发生错误,因为变量 someUndefinedVariable 没有声 明。由于变量 found 的值是 true,所以逻辑与操作符会继续对变量 someUndefinedVariable 求值。 但 someUndefinedVariable 尚未定义,因此就会导致错误。这说明不能在逻辑与操作中使用未定义的值。
如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值:
如果第一个操作数是对象,则返回第一个操作数;
如果第一个操作数的求值结果为 false,则返回第二个操作数;
如果两个操作数都是对象,则返回第一个操作数;
如果两个操作数都是 null,则返回 null;
如果两个操作数都是 NaN,则返回 NaN;
如果两个操作数都是 undefined,则返回 undefined。
与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为 true,就不会对第二个操作数求值了。
乘法、除法和求模。如果参与乘性计算的某 个操作数不是数值,后台会先使用 Number()转型函数将其转换为数值。
如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
如果有一个操作数是 NaN,则结果是 NaN;
如果是 Infinity 与 0相乘,则结果是 NaN;
如果是 Infinity 与非 0数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数 的符号;
如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的 规则。
如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
如果有一个操作数是 NaN,则结果是 NaN;
如果是 Infinity 被 Infinity 除,则结果是 NaN;
如果是零被零除,则结果是 NaN;
如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作 数的符号;
如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
如果操作数都是数值,执行常规的除法计算,返回除得的余数;
如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
如果被除数是有限大的数值而除数是零,则结果是 NaN;
如果是 Infinity 被 Infinity 除,则结果是 NaN;
如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
如果被除数是零,则结果是零;
如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
如果有一个操作数是 NaN,则结果是 NaN;
如果是 Infinity 加 Infinity,则结果是 Infinity;
如果是-Infinity 加-Infinity,则结果是-Infinity;
如果是 Infinity 加-Infinity,则结果是 NaN;
如果是+0加+0,则结果是+0;
如果是-0加-0,则结果是-0;
如果是+0加-0,则结果是+0。
不过,如果有一个操作数是字符串,那么就要应用如下规则:
如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来
如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值, 然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符 串"undefined"和"null"
如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
如果有一个操作数是 NaN,则结果是 NaN;
如果是 Infinity 减 Infinity,则结果是 NaN;
如果是-Infinity 减-Infinity,则结果是 NaN;
如果是 Infinity 减-Infinity,则结果是 Infinity;
如果是-Infinity 减 Infinity,则结果是-Infinity;
如果是+0减+0,则结果是+0;
如果是+0减-0,则结果是-0;
如果是0减0,则结果是+0;
如果有一个操作数是字符串、布尔值、null 或 undefined,则先在后台调用 Number()函数将 其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果 就是 NaN;
如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到 的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString() 方法并将得到的字符串转换为数值。
如果两个操作数都是数值,则执行数值比较。
如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执 行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面 的规则执行比较。
如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
在比较字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。如果要真正按字母表顺序比较字符串,就必须把两个操作数转换为相同的大 小写形式(全部大写或全部小写),然后再执行比较。
var result = "23" < "3"; //true
确实,当比较字符串"23"是否小于"3"时,结果居然是 true。这是因为两个操作数都是字符串, 而字符串比较的是字符编码("2"的字符编码是 50,而"3"的字符编码是 51)。
var result = "23" < 3; //false
此时,字符串"23"会被转换成数值 23,然后再与 3 进行比较,因此就会得到合理的结果
var result = "a" < 3; // false,因为"a"被转换成了 NaN
由于字母"a"不能转换成合理的数值,因此就被转换成了 NaN。根据规则,任何操作数与 NaN 进行 关系比较,结果都是 false。于是,就出现了下面这个有意思的现象:
var result1 = NaN < 3; //false
var result2 = NaN >= 3; //false
按照常理,如果一个值不小于另一个值,则一定是大于或等于那个值。然而,在与 NaN 进行比较时, 这两个比较操作的结果都返回了 false。
相等__和__不相等——先转换再比较,全等__和__不全等——仅比较而不转换。
这两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性。:
如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而 true 转换为 1;
如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类 型值按照前面的规则进行比较; 这两个操作符在进行比较时则要遵循下列规则。
null 和 undefined 是相等的。
要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示: 即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则,NaN 不等于 NaN。
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象, 则相等操作符返回 true;否则,返回 false
== =:它只在两个操作数未经转换就相等的情况下返回 true;
!==:它在两个操作数未经转换就不相等的情况 下返回 true。
由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,我们推荐使用全等和不全等操作符。
本质上,这行代码的含义就是基于对 boolean_expression 求值的结果,决定给变量 variable 赋什么值。如果求值结果为 true,则给变量 variable 赋 true_value 值;如果求值结果为 false, 则给变量 variable 赋 false_value 值。
乘/赋值(*=);
除/赋值(/=);
模/赋值(%=);
加/赋值(+=);
减/赋值(-=);
左移/赋值(<<=);
有符号右移/赋值(>>=);
无符号右移/赋值(>>>=);
使用它们不会带来任何性能的提升。
var num = 10;
num = num + 10;
其中的第二行代码可以用一个复合赋值来代替:
var num = 10;
num += 10;
在用于赋值时,逗号操作符总会返回表达式中的后一项:
var num = (5, 1, 4, 8, 0); // num 的值为 0
for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。
for (var propName in window) {
document.write(propName);
}
我们使用 for-in 循环来显示了 BOM中 window 对象的所有属性。每次执行循环 时,都会将 window 对象中存在的一个属性名赋值给变量 propName。这个过程会一直持续到对象中的 所有属性都被枚举一遍为止。与 for 语句类似,这里控制语句中的 var 操作符也不是必需的。但是, 为了保证使用局部变量,我们推荐上面例子中的这种做法。
使用 label 语句可以在代码中添加标签,以便将来使用。
其中,__break 语句会立即退出循环,强制继续执行循环后面的语句。__而 continue 语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行。
break 和 continue 语句都可以与 label 语句联合使用,从而返回代码中特定的位置。这种联合使用的情况多发生在循环嵌套的情况下:
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
__添加这个标签的结果将导致 break 语句不仅会退出内部的 for 语句(即使用变量 j 的循环),而且也会退出外部的 for 语句(即使用变量 i 的循环)。__
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 `
__continue 语句会强制继续执行循环——退出内部循环,执行外部循环。__当 j 是 5 时,continue 语句执行,而这也就意味着内部循环少执行了 5次,因此 num 的结果是 95
with 语句的作用是将代码的作用域设置到一个特定的对象中,with 语句的作用是将代码的作用域设置到一个特定的对象中。
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
上面几行代码都包含 location 对象。如果使用 with 语句,可以把上面的代码改写成如下所示:
with(location){
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
使用 with 语句关联了 location 对象。这意味着在 with 语句的代码块内部,__每个变量首先被认为是一个局部变量,__而如果在局部环境中找不到该变量的定义,就会查询 location 对象中是否有同名的属性。如果发现了同名属性,则以 location 对象属性的值作为变量的值。
严格模式下不允许使用 with 语句,否则将视为语法错误。 由于大量使用 with 语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用 with 语句。
可以在 switch 语句中使用任何数据类型(在很多其他语言中只能使用数值),无论是字符串,还是对象都没有 问题。其次,每个 case的值不一定是常量,可以是变量,甚至是表达式。
switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换。
ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过 return 语句后跟要返回的值来实现返回值。
位于 return 语句之后的任何代码 都永远不会执行。
另外,return 语句也可以不带有任何返回值。(return;)在这种情况下,函数在停止执行后将返回 undefined 值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下。
推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。
严格模式对函数有一些限制:
不能把函数命名为 eval 或 arguments;
不能把参数命名为 eval 或 arguments;
不能出现两个命名参数同名的情况。 如果发生以上情况,就会导致语法错误,代码无法执行。