JavaScript语法

一、基本语法

1. 语句

  • 1.1 每一行是一个语句,语句不需返回值,表达式有返回值。

2. 变量

  • 2.1 严格地说,var a = 1 与 a = 1是不完全一样,delete命令无法删除前者。不用var声明的语句不利于表达意图,且容易创建全局变量。
  • 2.2 用var声明同一个变量并赋值有覆盖性。
  • 2.3 用var命令声明的变量存在变量提升,声明语句都会被提升到代码的头部。

3. 标识符

  • 3.1 变量名首个不能是数字,不能包含 * 和运算符,不能用保留字,大小写是不同的,中文可做变量名。

4. 注释

  • 4.1 也可用html的单行注释(在行首,否则为运算符)。

5、区块

  • 5.1 JavaScript的区块不构成单独的作用域。

6、语句点

  • 6.1 else代码块总是跟随离自己最近的那个if语句。
  • 6.2 switch、case语句都可以使用表达式,在比较运行结果时,采用的是===,而不是==,比较时不会发生类型转换。

二、数据类型

1. 对象

  • 狭义的对象(object)
  • 数组(array)
  • 函数(function)

2. 类型

  • number、string、boolean、function、undefined、object(空数组和null也是)

3. 三种确定类型方法

  • typeof运算符
  • instanceof运算符
  • Object.prototype.toString方法

4. 布尔值

  • false: undefined、null、false、0、NaN、 " "或' '(空字符串)
  • ture :特别注意空数组([])和空对象({})

三、数值

1. 数值范围

1.1 所有数字都是以64位浮点数形式储存
1.2 JavaScript 浮点数的64个二进制位,从最左边开始:
第1位:符号位,0表示正数,1表示负数
第2位到第12位:指数部分
第13位到第64位:小数部分(即有效数字)
1.3 能表示的数值范围为2^1024 到2^-1023(开区间)(否则返回Infinity)

2. 数值精度

2.1 从-(2^53-1) 到(2^53-1),都可以精确表示
2.2 若只有整数才能完成的运算,会自动把64位浮点数转成32位整数
2.3 浮点数不是精确的值(小数的比较,如0.1+0.2===0.3 //false
2.4 小数点前的数字多于21位和其后的零多于5个会自动转为科学计数法

3. 数值进制

3.1 十进制:没有前导0的数值。
3.2 八进制:有前缀0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
3.3 十六进制:有前缀0x或0X的数值。
3.4 二进制:有前缀0b或0B的数值。

4.特殊数值

  • +0===-0
    (1 / +0) === (1 / -0) // false +Infinity!=-Infinity
    NaN === NaN // false
    Infinity > (<) NaN // false
  • isNaN为true的值,有可能不是NaN,而是一个字符串、对象和数组。

5. 全局方法

5.1 parselnt

  • parseInt:将字符串转为整数,只返回字符串头部可以转为数字,第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
    parseInt('+') // NaN
    parseInt('+1') // 1
  • parseInt会将科学计数法的表示方法视为字符串
  • 进制转换(2到36之间)
    parseInt('1000', 2) // 2进制-8
    parseInt('1000', 8) // 8进制512
    parseInt('10', 37) // NaN
    parseInt('10', 1) // NaN
    parseInt('10', 0) // 10
    parseInt('10', null) // 10
    parseInt('10', undefined) // 10
    5.2 parseFloat:将一个字符串转为浮点数(会将空字符串转为NaN)
    (用法与parseInt类似)

四、字符串

1. 转义符

转义符 表达 码值
\0 null (\u0000)
\b 后退键 (\u0008)
\f 换页符 (\u000C)
\n 换行符 (\u000A)
\r 回车键 (\u000D)
\t 制表符 (\u0009)
\v 垂直制表符 (\u000B)
' 单引号 (\u0027)
" 双引号 (\u0022)
\ 反斜杠 (\u005C)
  • 在非特殊字符前面使用反斜杠,则反斜杠会被省略
  • charCodeAt:返回每个字节对应的十进制值
  • 在JavaScript引擎内部,所有字符都用Unicode表示

五、对象

1. 新建对象

var o1 = {};
var o2 = new Object();
var o3 = Object.create(Object.prototype); //用在需要对象继承的场合

2. 注意事项

2.1 如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),也不是数字,则必须加上引号,保留字可以不加引号当作键名
2.2 行首是大括号为语句(即代码块)。在大括号前加上圆括号为表达式(即对象)。

3. 属性

  • 3.1 读取对象的属性:点运算符(数值键名不能使用(被当成小数点)
    方括号运算符(键名必须放在引号里面,否则会被当作变量处理。但数字键不加引号,因为会被当作字符串处理)
o.p // "Hello World"
o['p'] // "Hello World"
  • 3.2 用Object.keys方法查看一个对象本身的所有属性。
  • 3.3 delete命令用于删除对象的属性,删除成功后返回true,属性就会返回undefined。
    • 删除一个不存在的属性,delete不报错,而且返回true。
    • 属性存在,且不得删除,delete命令会返回false。
    • delete命令不能删除var命令声明的变量,只能用来删除属性。

4. in

  • 用于检查对象是否包含某个属性(检查的是键名,不是键值),包含(true),否则(false)。(但不能识别对象继承的属性)

5.for...in循环

  • 5.1 用来遍历一个对象的全部属性。
  • 5.2 遍历的是对象所有可遍历的属性,跳过不可遍历的属性,遍历继承的属性。
  • 5.3 用hasOwnProperty只遍历对象本身的属性

6. with

  • 6.1 操作同一个对象的多个属性时,提供一些书写的方便
with (o) {
  p1 = 1;
  p2 = 2;
}
// 等同于
o.p1 = 1;
o.p2 = 2;
  • 6.2 with区块内部的变量,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量,因为with区块没有改变作用域,它的内部依然是当前作用域。

六、数组

1.本质

数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。

2. 类似数组的对象

  • 2.1 类似数组的对象是函数的arguments对象,以及大多数DOM元素集,还有字符串。
  • 2.2 数组的slice方法将类似数组的对象,变成真正的数组。
    var arr = Array.prototype.slice.call(arrayLike);
  • 2.3 length属性不过滤空位空位,空位与某个位置是undefined,是不一样的。使用数组的forEach方法、for...in结构、以及Object.keys方法进行遍历,空位都会被跳过。
  • 2.4 遍历类似数组的对象,可以采用for循环,也可以采用数组的forEach方法。

七、函数

1. 函数声明

  • 1.1 function命令声明的代码区块,就是一个函数
    -用function命令声明函数
function print(s) {
  console.log(s);
}
  • 1.2 采用变量赋值的写法
var print = function(s) {
  console.log(s);
};
  • 1.3 Function构造函数
var foo = new Function(
  'return "hello world"'
);

// 等同于

function foo() {
  return 'hello world';
}
  • Function构造函数可以不使用new命令,返回结果完全一样,但不直观,一般不用这种方法。

2. 函数重复声明

  • 后面的声明就会覆盖前面的声明

3.不能在条件语句中声明函数

  • 函数的toString方法返回函数的源码,内部的注释也可以返回
  • 变量在函数内部定义,是一个局部变量,函数之外无法读取。
  • 函数内部定义的变量,会在该作用域内覆盖同名全局变量。

4.arguments 对象

  • arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数。这个对象只有在函数体内部,才可以使用。
  • 还可以为参数赋值(严格模式不允许这种用法)
  • 判断函数调用时到底带几个参数
function f() {
  return arguments.length;
}

5. 闭包(定义在一个函数内部的函数)

  • 5.1 JavaScript有两种作用域:全局作用域和函数作用域。函数内部可以直接读取全局变量。
  • 在函数外部无法读取函数内部声明的变量,闭包就是将函数内部和函数外部连接起来的一座桥梁。
  • 可以看作是函数内部作用域的一个接口。
  • 是封装对象的私有属性和私有方法。
  • 链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
  • 在函数的内部,再定义一个函数得到函数内的局部变量
function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); // 999
//函数f1的返回值就是函数f2,由于f2可以读取f1的内部变量,所以就可以在外部获得f1的内部变量了。
  • 上述代码闭包就是函数f2,即能够读取其他函数内部变量的函数。
  • 注意:外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

6. 调用

// 语句
function f() {}
// 表达式
var f = function f() {}
  • 行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
  • 不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
//最后的分号都是必须的

7. eval

  • 将有独自存在的意义字符串当作语句执行
  • 没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题。
  • eval有安全风险。为了防止这种风险规定,如果使用严格模式,eval内部声明的变量,不会影响到外部作用域。

八、运算符

1. 加法运算符

// 加法
1 + 1 // 2
1 + true // 2

// 字符串连接
'1.1' + '1.1' // "1.11.1"
'1' + 1 // "11"
'1' + true // "1true"
//只要有一个运算子是字符串,则两个运算子都转为字符串,执行字符串连接运算。
  • 运算子为对象,先自动转成原始类型的值(即先执行该对象的valueOf方法,如果结果还不是原始类型的值,再执行toString方法;如果对象是Date实例,则先执行toString方法)

2. 其他算术运算符(比如减法、除法和乘法)

  • 都不会发生重载。它们的规则是:所有运算子一律转为数值,再进行相应的数学运算。
1 - '2' // -1
1 * '2' // 2
1 / '2' // 0.5

3. 余数运算符(%)

  • 需要注意的是,运算结果的正负号由第一个运算子的正负号决定。
  • 为了得到正确的负数的余数值,需要先使用绝对值函数.

4.对象间的比较

[2] > [11] // true
// 等同于 [2].valueOf().toString() > [11].valueOf().toString()
// 即 '2' > '11'

5. 严格相等运算符

  • 5.1 如果两个值的类型不同,直接返回false。
    -5.2 类型的原始类型的值(数值、字符串、布尔值)比较时,值相同就返回true,值不同就返回false。
  • 5.3 同一类的复合类型值
    • 两个复合类型(对象、数组、函数)的数据比较时,不是比较它们的值是否相等,而是比较它们是否指向同一个对象。
    • 对于两个对象的比较,严格相等运算符比较的是地址,而大于或小于运算符比较的是值。
  • 5.4 undefined和null与自身严格相等。

6.相等运算符

  • 6.1 原始类型的值
    • 原始类型的数据会转换成数值类型再进行比较。
  • 6.2 对象与原始类型值比较
    • 对象(这里指广义的对象,包括数组和函数)与原始类型的值比较时,对象转化成原始类型的值,再进行比较。

7. 取反运算符

  • 形式上是一个感叹号,用于将布尔值变为相反值对于非布尔值的数据,取反运算符会自动将其转为布尔值。
!!x
// 等同于
Boolean(x)
//两次取反就是将一个值转为布尔值的简便写法。

8. 位运算符

  • 8.1 位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。虽然在JavaScript内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。
i = i | 0;
//将i(不管是整数或小数)转为32位整数。
//利用这个特性,可以写出一个函数,将任意数值转为32位整数。
  • 8.2 否运算
    ~ 3 // -4
  • 一个数与自身的取反值相加,等于-1。
  • 对一个整数连续两次“否运算”,得到它自身。
~~2.9 // 2
~~47.11 // 47
~~1.9999 // 1
//使用否运算取整,是所有取整方法中最快的一种。
  • 8.3 异或
  • “异或运算”有一个特殊运用,连续对两个数a和b进行三次异或运算,可以互换它们的值(详见维基百科)。这意味着,使用“异或运算”可以在不引入临时变量的前提下,互换两个变量的值。
var a = 10;
var b = 99;

a ^= b, b ^= a, a ^= b;

a // 99
b // 10
  • 异或运算也可以用来取整。
    12.9 ^ 0 // 12
  • 8.4 左移运算
  • 如果左移0位,就相当于将该数值转为32位整数,等同于取整,对于正数和负数都有效。
13.5 << 0
// 13
  • 8.5 开关作用
var mask = FLAG_A | FLAG_B | FLAG_D;
// 0001 | 0010 | 1000 => 1011
//对ABD三个变量进行“或运算”,得到掩码值为二进制的1011。

flags = flags | mask;
//有了掩码,“或运算”可以确保打开指定的开关。
flags = flags & mask;
//“与运算”可以将当前设置中凡是与开关设置不一样的项,全部关闭。
flags = flags ^ mask;
//“异或运算”可以切换(toggle)当前设置
//即第一次执行可以得到当前设置的相反值,再执行一次又得到原来的值。

flags = ~flags;
//“否运算”可以翻转当前设置,即原设置为0,运算后变为1;原设置为1,运算后变为0。

9. 逗号运算符

'a', 'b' // "b"
//返回后一个表达式的值。

10.优先级

  • 从高到低依次为:小于等于(<=)、严格相等(===)、或(||)、三元(?:)、等号(=)。
  • 圆括号(())可以用来提高运算的优先级,优先级是最高的(圆括号不是运算符,而是一种语法结构。两种用法:一是把表达式放在圆括号之中,提升运算的优先级;二是跟在函数的后面,作用是调用函数。)

九、数据类型转换

1.强制转换

  • 1.1 Number()
    • 比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN。
      valueOf->若原始类型的值->Number
      valueOf->若对象->toString->若原始类型的值->Number
      valueOf->若对象->toString->若对象->错误
  • Number方法的参数是对象时,将返回NaN,除非是包含单个数值的数组
  • 1.2 String()
    • 数值:转为相应的字符串。
    • 字符串:转换后还是原来的值。
    • 布尔值:true转为"true",false转为"false"。
    • undefined:转为"undefined"。
    • null:转为"null"
    • 对象
      toString->若原始类型的值->String
      toString->若对象->valueOf->若原始类型的值->String
      toString->若对象->valueOf->若对象->报错
  • 1.3 Boolean()
    • undefined、null、-0、 0或+0、 NaN、' '(空字符串)
      转换结果为false,其他的值全部为true。
    • 注意,所有对象(包括空对象)的转换结果都是true,甚至连false对应的布尔对象new Boolean(false)也是true。

2. 自动转换

  • 预期什么类型的值,就调用该类型的转换函数。比如,某个位置预期为字符串,就调用String函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认转为数值。
  • 由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用Boolean、Number和String函数进行显式转换。
// 写法一
expression ? true : false

// 写法二
!! expression
有时也用于将一个表达式转为布尔值。它们内部调用的也是Boolean函数。
  • 字符串的自动转换,主要发生在加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。

十、错误处理机制

1. Error对象

  • 代码解析或运行时发生错误,JavaScript引擎就会自动产生、并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方,不再往下执行。
    • message:错误提示信息
    • name:错误名称(非标准属性)
    • stack:错误的堆栈(非标准属性)
if (error.name){
  console.log(error.name + ": " + error.message);
}

2. JavaScript的原生错误类型

  • 2.1 SyntaxError:是解析代码时发生的语法错误。
  • 2.2ReferenceError:是引用一个不存在的变量时发生的错误。
    另一种是,将一个值分配给无法分配的对象,比如对函数的运行结果或者this赋值。
console.log() = 1
// ReferenceError: Invalid left-hand side in assignment

this = 1
// ReferenceError: Invalid left-hand side in assignment
  • 2.3 RangeError是当一个值超出有效范围时发生的错误。
    • 数组长度为负数
    • Number对象的方法参数超出范围,以及函数堆栈超过最大值。
  • 2.4 TypeError是变量或参数不是预期类型时发生的错误。如对字符串、布尔值、数值等原始类型的值使用new命令,就会抛出这种错误,因为new命令的参数应该是一个构造函数。
  • 2.5 URIError是URI相关函数的参数不正确时抛出的错误,主要涉及
    • encodeURI()
    • decodeURI()
    • encodeURIComponent()
    • decodeURIComponent()
    • escape()
    • unescape()
  • 2.6 eval函数没有被正确执行时,会抛出EvalError错误。该错误类型已经不再在ES5中出现了,只是为了保证与以前代码兼容,才继续保留。

3. 自定义错误

4. throw语句

  • throw语句的作用是中断程序执行,抛出一个意外或错误。它接受一个表达式作为参数,可以抛出各种值。
  • throw可以接受各种值作为参数。JavaScript引擎一旦遇到throw语句,就会停止执行后面的语句,并将throw语句的参数值,返回给用户。

5. try…catch结构

  • 为了对错误进行处理,需要使用try...catch结构。
  • catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。还可以再抛出错误,甚至使用嵌套的try...catch结构
  • catch捕获错误之后,会判断错误类型(EvalError还是RangeError),进行不同的处理。
  • try...catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句。

6. finally

  • 执行finally代码块以后,程序就中断在错误抛出的地方。
  • 即使有return语句在前,finally代码块依然会得到执行,且在其执行完毕后,才会显示return语句的值。return语句的执行是排在finally代码之前,只是等finally代码执行完毕后才返回。

你可能感兴趣的:(JavaScript语法)