第三章 基本概念

本章内容

  • 语法
  • 数据类型
  • 操作符
  • 语句
  • 函数

3.1 语法


3.1.1 区分大小写,ECMAScript中的一切(变量、函数名和操作符)都区分大小写。


3.1.2 标识符

标识符:变量、函数、属性的名字,或者函数的参数;标识符的格式规则如下:

  1. 第一个字符必须是一个字母、下划线、或者是一个美元符号$;
  2. 其他的字符可以是字母、下划线、美元符号或者是数字;
  3. 标识符中的字母也可以包括扩展的ASCII或者Unicode字母字符,但是不推荐这样写;
  4. 按照惯例,标识符采用驼峰式大小写格式、也就是第一个字母小写,剩下的每个单词都是首字母大写:firstSecond、myCar;

3.1.3 注释

// 单行注释
/*
*多行注释
*(块级注释)每行前面加*是可以不写,但是写的话可以提高注释的可读性。
*/


3.1.4 严格模式

“use strict”
ECMAScript5引入了严格模式的概念。在顶部添加,是为了不破坏ECMAScript3语法而特意选定的语法,是一个编译指示。定义一种不同的解析和执行模型,为了将一些不确定的行为、不安全的操作得到处理,并抛出错误。也可以指定函数在严格模式下执行:
function doSomething(){
“use strict”;
//函数体
}


3.1.5 语句

  1. 可以省略分号,解析器会确定语句的结尾,但是强烈不推荐这样,要求每个语句结尾都加分号,可以避免很多错误,加分号在某种情况下会增进代码的性能,解析器就不用花时间推测应该在哪里插入分号了;

  2. 语句块中只有一条语句的时候可以不加花括号“{}”但是不建议这样写,我们要求一条语句的时候也加花括号,质这样可以让编码意图更加清晰,而且也能降低修改代码时的出错几率;


3.2 关键字和保留字

现已推出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关键字

总结

  1. 使用保留字标识符可能会也可能不会出错,具体取决与特定的引擎。一般来说。最好不要使用关键字和保留字作为标识符和属性名,以便与将来的ECMAScript版本兼容。
  2. ECMA-262第 5版对 eval 和 arguments 还施加了限制。在严格模式下,这两个名字也不能作为标识符或属性名,否则会抛出错误。

3.3 变量

定义变量:
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 的变量,否则会导致语法错误。 __


3.4 数据类型

  • ECMAScript有五种基本数据类型:Undefined、Null、Boolean、Number和String。还有一种复杂数据类型:Object;
  • Object本质上是由一组无序的名值对组成;
  • ECMAScript中不支持任何创建自定义类型的机制;

3.4.1 typeof操作符

用于检测给定变量的数据类型——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.4.2 undefined 类型

第 3版引入这个值是为了正式区分空对象指针与未经初始化的变量

var message ;
console.log(message == undefined); //true 未初始化的变量的值会默认为undefined;
console.log(age); // 未声明的值会出错
console.log(typeof message); //undefined;
console.log(typeof age); //undefined; 未声明的变量执行typeof也是返回undefined。


3.4.3 null 类型

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。 __


3.4.4 boolean 类型

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转换函数。


3.4.5 number 类型

这种类型使用 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

注意:

  1. 在算数计算时。所有以八进制和十六进制表示的数值最终都将被换成十进制数值;
  2. 可以保存+0和-0,正零和负零被认为时相等的。

1. 浮点数

浮点数就是该数值中包含一个小数点,并且小数点后面必须至少有一位数,对然小数点前面可以没有整数,但是我们不推荐这种写法。

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.这个小小的舍入误差会导致无法测试特定的浮点数值,所以永远不要测试某个特定的浮点数;

2. 数值范围

  1. ECMAScript能够表示的小数值保 存在 Number.MIN_VALUE 中——在大多数浏览器中,这个值是 5e-324
  2. 能够表示的大数值保存在 Number.MAX_VALUE 中——在大多数浏览器中,这个值是1.7976931348623157e+308
  3. 如果某次计算的 结果得到了一个__超出 JavaScript数值范围的值__,那么这个数值将被自动转换成特殊的 Infinity 值.如果这个数值是负数,则会被转换成-Infinity(负无穷),如果这个数值是正数,则会被转 换成 Infinity(正无穷);
  4. Infinity不是能够参与计算的数值。__isFinite()__判断一个数值是否在最小和最大的数值之间。是的话会返回true。
    var result = Number.MAX_VALUE + Number.Max_VALUE;
    console.log(isFinite(result); //false

3 NaN

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()方法,再测试返回值。

4. 数值转换

将非数值转为数值有三个函数:Number()、parseInt()和parseFloat()。Number()转型函数可以用于任何数据类型,而parseInt()和parseFloat()专门用于把字符串转换为数值。

__Number()函数的转换规则如下。 __

 如果是 Boolean 值,true 和 false 将分别被转换为 1和 0。
 如果是数字值,只是简单的传入和返回。
 如果是 null 值,返回 0。
 如果是 undefined,返回 NaN。 __
 如果是字符串,遵循下列规则:
 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,
“123"会变成 123__,而"011"会变成 11(注意:前导的零被忽略了);
 如果字符串中包含有效的浮点格式,如"1.1”,则将其转换为对应的浮点数值(同样,也会忽 略前导零);
 如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整 数值;
如果字符串是空的(不包含任何字符),则将其转换为 0
 如__果字符串中包含除上述格式之外的字符,则将其转换为 NaN。 __
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符串值。
(一元操作符的操作与Number()函数相同)

parseInt()函数的转换规则:

由于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 作为第二个参数是非常必要的。

parseFloat()函数的转换规则:

  1. parseFloat()也是从第一个字符开始解析每个字符。而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字符位置。字符串中的第 一个小数点是有效的,而第二个小数点就是无效的了。
  2. __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类型用于表示由0或多个16位Unicode字符组成的字符序列,即字符串。可以用双引号和单引号表示:用双引号和单引号表示的字符串完全相同

1. 字符字面量

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 属性可能__不会精确__地返回字符串中的字符数目。

2. 字符串的特点

ECMAScript中的字符串是不可变的,要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。
var lang = "Java";
lang = lang + "Script";
首先创建一个能容纳 10个字符的 新字符串,然后在这个字符串中填充"Java"和"Script",后一步是销毁原来的字符串"Java"和字 符串"Script",因为这两个字符串已经没用了.

3. 转换为字符串

两种方法:

__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"
__要把某个值转换为字符串,可以使用加号操作符,把它与一个字符 串("")加在一起。 __


3.4.7 Object类型

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。


3.5 操作符

3.5.1 一元操作符

只能操作一个值的操作符叫做一元操作符。

1. 递增和递减操作符

执行前置递增和递减操作时,变量的值都是在语句被求值以前改变的。(在计算机科学领域,这种 情况通常被称作副效应。)
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

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 `
一元加和减操作符主要用于基本的算术运算,也可以像前面示例所展示的一样用于转换数据类型。


3.5.2 位操作符

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()函数将该值转换为一个数值(自动完成),然后 再应用位操作。得到的结果将是一个数值

1.按位非(NOT)

执行按位非的结果就是返回数值的__反码__。
var num1 = 25; // 二进制 00000000000000000000000000011001
var num2 = ~num1; // 二进制 11111111111111111111111111100110
alert(num2); // -26 按位非操作的本质:操作数的负值减 1
按位非是在数值表示的底层执行操作,因此速度更快,(实现一个数值的负数减1,用按位取反操作速度更快。)

2.按位与(AND)

  `var result = 25 & 3; `

alert(result); //1
__按位与操作只在两个数值的对应位都是 1时才返回 1,任何一位是 0,结果都是 0。 __

3.按位或(OR)

按位或操作在有一个位是1的情况下就返回1,而只有在两个位都是0的情况下才返回 0。
var result = 25 | 3;
alert(result); //27

4.按位异或(XOR)

__这个操作在两个数值对应位上只有一个 1时才返回 1,如果对 应的两位都是 1或都是 0,则返回 0。 __
var result = 25 ^ 3;
alert(result); //26

5.左移

var oldValue = 2; // 等于二进制的 10
var newValue = oldValue << 5; // 等于二进制的 1000000,十进制的 64
左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数,在向左移位后,原数值的右侧多出空位。左移操作会以 0来填充这些空位,左移不会影响操作数的符号位。

6.有符号的右移

__有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即 正负号标记)。有符号的右移操作与左移操作恰好相反,即如果将 64向右移动 5位,结果将变回 2: __
var oldValue = 64; // 等于二进制的 1000000
var newValue = oldValue >> 5; // 等于二进制的 10 ,即十进制的 2
在移位过程中,原数值中也会出现空位。只不过这次的空位出现在原数值的左侧、符号位的 右侧。而此时 ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值。

7.无符号的右移

无符号右移操作符由 3个大于号(>>>)表示,这个操作符会将数值的所有 32位都向右移动。对正 数来说,无符号右移的结果与有符号右移相同。
var oldValue = 64; // 等于二进制的 1000000
var newValue = oldValue >>> 5; // 等于二进制的 10 ,即十进制的 2
无符号右移是以 0来填充空位,而不是像有符号右移那样以符号位的值来填充空位。所以,对正数的无符号右移与有符号右移结果相同。无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值的二进制补码形式表示,因此就会导致无符号右移后的结果非常之大。
var oldValue = -64; // 等于二进制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 等于十进制的 134217726


3.5.3 布尔操作符

1.逻辑非 ( !)

逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再 对其求反:
 如果操作数是一个对象,返回 false;
 如果操作数是一个空字符串,返回 true;
 如果操作数是一个非空字符串,返回 false;
 如果操作数是数值 0,返回 true;
 如果操作数是任意非 0数值(包括 Infinity),返回 false;
 如果操作数是 null,返回 true;
 如果操作数是 NaN,返回 true;
 如果操作数是 undefined,返回 true
同时使用两个逻辑非操作符,实际 上就会模拟 Boolean()转型函数的行为。

2.逻辑与(&&)

在有一个操作数不是布尔值的情况 下,逻辑与操作就不一定返回布尔值:
 如果第一个操作数是对象,则返回第二个操作数;
 如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该对象;
 如果两个操作数都是对象,则返回第二个操作数;
 如果有一个操作数是 null,则返回 null;
 如果有一个操作数是 NaN,则返回 NaN;
 如果有一个操作数是 undefined,则返回 undefined
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。第一个操作数是false的话,无论第二个值无论是什么都不会返回true; 在使用逻辑与操作符时要始终铭记它是一个短路操作符;
var found = true;
var result = (found && someUndefinedVariable); // 这里会发生错误
alert(result); // 这一行不会执行
当执行逻辑与操作时会发生错误,因为变量 someUndefinedVariable 没有声 明。由于变量 found 的值是 true,所以逻辑与操作符会继续对变量 someUndefinedVariable 求值。 但 someUndefinedVariable 尚未定义,因此就会导致错误。这说明不能在逻辑与操作中使用未定义的值。

3.逻辑或(||)

如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值:
 如果第一个操作数是对象,则返回第一个操作数;
 如果第一个操作数的求值结果为 false,则返回第二个操作数;
 如果两个操作数都是对象,则返回第一个操作数;
 如果两个操作数都是 null,则返回 null;
 如果两个操作数都是 NaN,则返回 NaN;
 如果两个操作数都是 undefined,则返回 undefined。
与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为 true,就不会对第二个操作数求值了。


3.5.4乘性操作符

乘法、除法和求模。如果参与乘性计算的某 个操作数不是数值,后台会先使用 Number()转型函数将其转换为数值。

1.乘法(*)

 如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 与 0相乘,则结果是 NaN;
 如果是 Infinity 与非 0数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数 的符号;
 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的 规则。

2.除法(/)

 如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果是零被零除,则结果是 NaN;
 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作 数的符号;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

3.求模(求余%)

 如果操作数都是数值,执行常规的除法计算,返回除得的余数;
 如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
 如果被除数是有限大的数值而除数是零,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
 如果被除数是零,则结果是零;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。


3.5.5 加性操作符

1.加法(+)

 如果有一个操作数是 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"

2.减法(-)

 如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
 如果有一个操作数是 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() 方法并将得到的字符串转换为数值。

3.5.6 关系操作符(<、>、<=、>=)

 如果两个操作数都是数值,则执行数值比较。
 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
 如果一个操作数是对象,则调用这个对象的 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。


3.5.7 相等操作符

相等__和__不相等——先转换再比较,全等__和__不全等——仅比较而不转换。

1.相等和不相等(== 、 !=)

这两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性。:
 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而 true 转换为 1;
 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类 型值按照前面的规则进行比较; 这两个操作符在进行比较时则要遵循下列规则。
 null 和 undefined 是相等的。
 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
 如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示: 即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则,NaN 不等于 NaN。
 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象, 则相等操作符返回 true;否则,返回 false

2.全等和不全等(=== 、!==)

== =:它只在两个操作数未经转换就相等的情况下返回 true;
!==:它在两个操作数未经转换就不相等的情况 下返回 true。
由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,我们推荐使用全等和不全等操作符。


3.5.8 条件操作符(variable = boolean_expression ? true_value : false_value; )

本质上,这行代码的含义就是基于对 boolean_expression 求值的结果,决定给变量 variable 赋什么值。如果求值结果为 true,则给变量 variable 赋 true_value 值;如果求值结果为 false, 则给变量 variable 赋 false_value 值。


3.5.9 赋值操作符(=)

 乘/赋值(*=);
 除/赋值(/=);
 模/赋值(%=);
 加/赋值(+=);
 减/赋值(-=);
 左移/赋值(<<=);
 有符号右移/赋值(>>=);
 无符号右移/赋值(>>>=);
使用它们不会带来任何性能的提升。
var num = 10;
num = num + 10;
其中的第二行代码可以用一个复合赋值来代替:
var num = 10;
num += 10;


3.5.10 逗号操作符(,)

在用于赋值时,逗号操作符总会返回表达式中的后一项:
var num = (5, 1, 4, 8, 0); // num 的值为 0


3.6 语句

  1. 使用 while 循环做不到的,使用 for 循环同样也做不到。也就是说,for 循环只是把与循环有关的代码集中在了一个位置。
  2. 有必要指出的是,在 for 循环的变量初始化表达式中,也可以不使用 var 关键字。该变量的初始化可以在外部执行。即使在循环内部声明的变量 i 是在循环内部定义的一个变量,但在循环外部仍然可以访问到它。

for-in语句

for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。
for (var propName in window) {
document.write(propName);
}
我们使用 for-in 循环来显示了 BOM中 window 对象的所有属性。每次执行循环 时,都会将 window 对象中存在的一个属性名赋值给变量 propName。这个过程会一直持续到对象中的 所有属性都被枚举一遍为止。与 for 语句类似,这里控制语句中的 var 操作符也不是必需的。但是, 为了保证使用局部变量,我们推荐上面例子中的这种做法。

  1. __ECMAScript 对象的属性没有顺序。__因此,通过 for-in 循环输出的属性名的顺序是不可预测的。 具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。
  2. 如果表示要迭代的对象的变量值为 null 或 undefined,for-in 语句会抛出错误。 ECMAScript 5更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。

label语句

使用 label 语句可以在代码中添加标签,以便将来使用。

break语句和continue语句

其中,__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 语句的作用是将代码的作用域设置到一个特定的对象中,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语句

可以在 switch 语句中使用任何数据类型(在很多其他语言中只能使用数值),无论是字符串,还是对象都没有 问题。其次,每个 case的值不一定是常量,可以是变量,甚至是表达式。
switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换。


3.7函数

ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过 return 语句后跟要返回的值来实现返回值。
位于 return 语句之后的任何代码 都永远不会执行。
另外,return 语句也可以不带有任何返回值。(return;)在这种情况下,函数在停止执行后将返回 undefined 值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下。
推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。
严格模式对函数有一些限制:
 不能把函数命名为 eval 或 arguments;
 不能把参数命名为 eval 或 arguments;
 不能出现两个命名参数同名的情况。 如果发生以上情况,就会导致语法错误,代码无法执行。

3.7.1 理解参数

  1. ECMAScript函数不介意传递进 来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数, 在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不 会有什么怨言。
  2. ECMAScript中的参数在内部是用一个数组来表示的。函数接收 到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任 何元素,无所谓;如果包含多个元素,也没有问题。
  3. 实际上,在函数体内可以通过 arguments 对象来 访问这个参数数组,从而获取传递给函数的每一个参数。
  4. arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访 问它的每一个元素(即第一个元素是 arguments[0],第二个元素是 argumetns[1],以此类推),使 用 length 属性来确定传递进来多少个参数
  5. 命名的参数只提供便利,但不是必需的。解析器不会验证命名参数。 arguments 对象可以与命名参数一起使用,它的值永远与对应命名参数的值保持同步。 修改了arguments就等于修改了参数,但是这并不是说读取这两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。
  6. 如果只传入了一个参数,那么为 arguments[1]设置的值不会反应到 命名参数中。这是因为 arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名 参数的个数决定的。 没有传递值的命名参数将自动被赋予 undefined 值。这就跟定义了 变量但又没有初始化一样。
  7. 严格模式下,修改arguments的值对参数进行赋值会变得无效,重写arguments的值会导致语法错误,代码不会执行。
  8. ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数。

3.7.2 没有重载

  • 如果在 ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。
  • 通过检查传入函数中参数的类型和数量并作出不同的反应,可以模仿方法的重载。

JavaScript高级程序设计红宝书学习笔记第三章基本概念相关推荐

  1. JavaScript高级程序设计第四版学习--第二十四章

    title: JavaScript高级程序设计第四版学习–第二十四章 date: 2021-5-31 10:46:01 author: Xilong88 tags: JavaScript 本章内容: ...

  2. 《JavaScript高级程序设计(第四版)》红宝书学习笔记(2)(第四章:变量、作用域与内存)

    个人对第四版红宝书的学习笔记.不适合小白阅读.这是part2.持续更新,其他章节笔记看我主页. (记 * 的表示是ES6新增的知识点,记 ` 表示包含新知识点) 第四章:变量.作用域与内存 4.1 原 ...

  3. 《JavaScript高级程序设计(第四版)》红宝书学习笔记(1)

    个人对第四版红宝书的学习笔记.不适合小白阅读.这是part1,包含原书第二章(HTML中的Javascript)和第三章(语言基础).持续更新,其他章节笔记看我主页. (记 * 的表示是ES6新增的知 ...

  4. 《JavaScript高级程序设计(第四版)》红宝书学习笔记(第五章:基本引用类型,原始值包装类型,单例内置对象)

    第五章:基本引用类型 引用值(或者对象)是某个特定引用类型的实例.新对象通过使用new操作符后跟一个构造函数(constructor)来创建. 5.1 Date 这里不对Date进行详细深入,仅基于书 ...

  5. js 红宝书学习笔记精简版 第一至三章

    注: 本文js代码均已在本地实现过,如有异常问题,请在评论区留言.ctrl+f 可搜索有效内容, 加粗为重点 蓝色字体 为重中之重 (一) 什么是js 1995 年,JavaScript 问世. 完整 ...

  6. 红宝书读书笔记 第五章

    基本引用类型 Date https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date MD ...

  7. 红宝书背诵笔记 — 基础词

    红宝书基础词 基础词-Unit1 基础词-Unit2 基础词-Unit3 基础词-Unit4 基础词-Unit5 基础词-Unit6 基础词-Unit7 基础词-Unit8 基础词-Unit9 基础词 ...

  8. 红宝书背诵笔记 — 简单基础词语

    简单基础词 a开头的简单基础词 b开头的简单基础词 c开头的简单基础词 d开头的简单基础词 e开头的简单基础词 f开头的简单基础词 g开头的简单基础词 h开头的简单基础词 i开头的简单基础词 j开头的 ...

  9. 西瓜书学习笔记第2章(模型评估与选择)

    西瓜书学习笔记第2章(模型评估与选择) 2.1经验误差与过拟合 2.2评估方法 2.2.1留出法(hold-out) 2.2.2交叉验证法(cross validation) 2.2.3自助法(boo ...

最新文章

  1. python使用numpy的np.power函数计算numpy数组中每个数值的指定幂次(例如平方、立方)、np.power函数默认返回整数格式、np.float_power函数默认返回浮点数
  2. unity2D平面摄像机滑动缩放
  3. twsited快速基础
  4. .NET Core 3.0之深入源码理解Kestrel的集成与应用(一)
  5. 颠覆与重构——戴尔助力徐工集团等行业客户实现业务转型
  6. 华为面试分配_什么时候不做面试分配
  7. 通过json发送html代码_Python简单程序爬取天气信息,定时以邮件发送给朋友
  8. 软件工程--需求分析的任务详解
  9. matlab生成正弦系数表
  10. wps开机启动无法禁用问题
  11. 计算前复权和后复权价格?A股复权因子的使用
  12. 用stata计算同比增长率的两种方法
  13. 转载:mac下开启hidpi三种办法
  14. Java 8 新特性
  15. 【Python安装系统】win10系统从零开始安装Python并为不同项目设置开发环境——以安装TensorFlow2为例
  16. java爬虫抓取极客时间专栏页面
  17. 问题:如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?.md
  18. SAP通过事件触发后台JOB_SAP刘梦_新浪博客
  19. 企业数字化建设的三个典型误区
  20. mysql备份工具xtr,xtrbackup备份mysql与恢复

热门文章

  1. APP开发中的UI设计
  2. arrow function
  3. 计算机科班出身的优势?
  4. 怎么才能拿到9000月薪?用这位女生的经历告诉你!
  5. “经营为什么需要哲学”(首都机场集团公司 讲演(2011年6月8日))
  6. mac 搭建kafka系列教程
  7. [精简]什么是调和调式?
  8. 地下停车场FM调频广播覆盖方案
  9. Android笔记:权限中英文对照
  10. 苹果手机怎么下载手机铃声?图文教程,快速学会