<笔记>JavaScript基本概念

318 阅读29分钟

语法

ECMAScript 的语法大量借鉴了 C 及其他类 C 语言( 如 Java 和 Perl ) 的语法. 因此 , 熟悉这些语言的开发人员在接受 ECMAScript 更加宽松的语法时 , 一定会有一种轻松自在的感觉.

区分大小写

在 ECMAScript 中的一切都是区分大小写的 , 例如函数名、变量名、操作符等.

  • fun() 和 Fun()是两个不同的函数
  • test 和 Test 是两个不同的变量名

标识符

标识符是指 ECMAScript 中的变量名、函数名、属性名、参数名等带有标识作用的字符. 标识符的命名规则如下

  • 开头第一个字符必须是: 字母、下划线( _ )、一个美元符号( $ )
  • 其他字符必须是: 字母、数字、下划线( _ )、美元符号( $ )
  • 按照惯例 , 我们在 ECMAScript 中给标识符命名的时候 , 尽量使用驼峰命名法 , 即第一个单词的首字母小写 , 后面其他单词的首字母大写
  • 不能将保留字和关键字作为标识符的名称

注释

  • 单行注释: //这是一个单行注释
  • 多行注释: /* 这是一个多行注释 */

严格模式( strict mode )

严格模式 ( strict mode ) 是在 ECMAScript 5 中引入的 , 它为 JavaScript 定义了一种完全不同的解析和执行模型 , 在严格模式下 , 某些不安全的操作会抛出错误

  • 在全局模式使用严格模式:
    "use strict";   //在脚本文件顶部添加
    function name(){
        ...
    }
  • 在函数内部使用严格模式:
    function name(){
        "use strict";    //在函数内部使用严格模式
        ...
    }

语句

ECMAScript 中的语句以一个分号结尾 , 如果省略分号 , 则由解析器自行确定结尾

    var sum = a + b     //即使没有分号也是有效的 , 但不推荐使用
    var diff = a - b;   //推荐

使用分号结尾的好处:

  • 避免错误
  • 压缩代码不会出错
  • 增加代码的性能

如果有多条代码 , 必须使用代码块包裹起来

    if (test){          //如果代码块中只有一条语句 , 也不建议省略代码块
        test = false;
        alert(test);
    }

使用代码块的好处:

  • 明确代码所属部分
  • 避免修改代码出错

关键字和保留字

关键字是指 ECMA262 中一组具有特定用途的字符 , 这些关键字可能用于控制语句的开始和结束 , 也可能是用于执行特定的操作

保留字是指将来可能被用作关键字而保留的

关键字和保留字都不能用作标识符

变量

ECMAScript 中的变量是松散类型的 , 可以用来保存任何类型的数据 , 每个变量仅仅只是一个用来保存值的占位符而已

定义变量:

    var name    ///使用 var 操作符后面跟一个变量名来定义一个局部变量
  • 像这样只是定义并没有初始化的变量 , 会默认保存一个特殊的值-undefined
  • 所谓初始化 , 就是给变量赋值
  • ECMAScript 支持在定义变量的同时给变量赋值 , 并且可以在修改变量值的同时修改值的类型
    var message = "hi";     //声明变量 message 并初始化值为 "hi"
    message = 10;           //修改值和值得类型(string->number)
    //以上操作在 ECMAScript 中完全有效 , 但不推荐使用
  • 使用 var 操作符定义的变量将会成为当前作用域下的一个局部变量
  • 一个在函数内部创建的局部变量 , 会在函数被调用时生成 , 在函数运行结束后被销毁
    function test(){
        var message = "hi"; //此时 message 是函数 test 下的一个局部变量
    }
    alert(message);         //浏览器报错,没有这个变量
  • 省略 var 操作符创建的变量都是全局变量 , 但不建议这么做 , 因为很难维护
    function test(){
        message = "hi";
    }
    alert(message);         //得到 "hi"
  • 可以使用一条语句定义多个变量 , 但是要使用逗号把每个变量分开
    function test(){    //声明 num1 , num2 , num3 三个局部变量
        var num1,       //只声明 , 不初始化 (undefined)
            num2 = 1,   //既声明又初始化    (1)
            num3;       //都可以           (undefined)
    }
    function test2(){
        var num1 = num2 = num3 = 1;
        //这条声明同样会生成三个变量 , 只不过是两个全局变量和一个局部变量
        //等同于如下语句
        num3 = 1;       //全局变量 num3
        num2 = num3;    //全局变量 num2
        var num1 = num2;//局部变量 num1
    }

数据类型

ECMAScript 中有五种简单数据类型 ( 基本数据类型 ) : Undefined、Null、Boolean、Number、String . 除了简单数据类型还有一种复杂数据类型 : Object , Object 本质上是由一组无序的键值对组成 .

typeof 操作符

由于 ECMAScript 是松散类型的 , 所以需要一种手段来检测变量的数据类型 , typeof 操作符就是做这件事儿的.

对一个变量使用 typeof 操作符会得到下列字符串 :

  • "undefined" - 如果这个值未定义或者未初始化
  • "boolean" - 如果这个值是布尔值
  • "string" - 如果这个值是字符串
  • "number" - 如果这个值是数值
  • "object" - 如果这个值是一个对象或者null
  • "function" - 如果这个值是一个函数

以下是一些使用 typeof 操作符的例子

    function test(){
        alert(typeof "字符串");     // "string"
        alert(typeof ("字符串"));   // "string"
        alert(typeof 24);          // "number" 
    }

需要注意的是 : typeof 是一个操作符不是函数 , 它的后面可以跟上一个括号 , 但这不是必需的

Undefined 类型

Undefined 类型只有一个值 , 那就是特殊的 undefined

  • 我们在使用 var 声明变量但是并没有对其进行初始化时 , 这个变量的值默认就是undefined

  • 值为 undefined 的变量和没有定义的变量并不同 , 没有定义的变量不能进行任何操作

  • undefined 只能进行一项操作 , 就是用 typeof 操作符对其进行数据类型检测

    function test(){
        var message;        //声明变量但不初始化 , 默认值为 undefined
        
        alert(message);     // "undefined"
        alert(age);         // 报错 "age is not defined"
    }
  • 但是在使用 typeof 操作符对未定义的变量和未初始化的变量进行操作时 , 都返回了undefined
    function test(){
        var message;
        
        alert(typeof message);  // "undefined"
        alert(typeof age);      // "undefined"
    }

Null 类型

Null 类型只有一个值 , 那就是特殊的 Null

  • Null 表示的是一个空对象指针 , 所以在使用 typeof 操作符对其检测的时候 , 会返回 "object"
  • 如果定义的变量将来是用于存储复杂数据类型(object) , 那么最好将其初始化为 null
  • undefined 其实是派生自 null 的 , 所以使用相等操作符进行测试 , 会返回 true
    function test(){
        alert(null == undefined);   // "true"
    }

Boolean 类型

Boolean 类型是 ECMAScript 中使用的最多的一种类型 , 它只有两个字面值 : true 和 false

  • Boolean 类型的字面值是区分大小写的 , 只有 true 和 false 是 Boolean 类型 , 其他例如 True 或者 False 都只是标识符 , 不是 Boolean 数据类型
  • ECMAScript 中的所有类型的值都可以转化为对应的 Boolean 值 , 可以调用转型函数 Boolean()
数据类型 转换为 true 的值 转换为 false 的值
Boolean true false
String 任何非空字符串 ""
Number 任何非零的数值 0/NaN
Object 任何对象 null
Undefined n/a(不适用) undefined

Number 类型

ECMAScript 的 Number 类型使用了 IEEE754 格式来表示整数和浮点数值 ( 双精度数值 )

  • 最基本的数值字面量格式是十进制的整数
  • 除了十进制 , 整数还可以通过八进制和十六进制来表示
    • 八进制字面量的第一位必须是 0 , 后面是八进制数字序列 ( 0~7 )
    • 十六进制字面量的第一位必须是 0x , 后面跟十六进制数字系列 ( 0~9 和 A~F ) , 字母不分大小写
    • 不符合以上条件的通通以十进制来表示
  • 在进行算术计算的时候 , 所有数值都会转换成十进制数值进行计算

浮点数值

所谓浮点数值 , 就是这个数值中必须包含一个小数点 , 并且小数点后面必须至少有一位数字

  • 由于保存浮点数值需要的内存空间是保存整数值的两倍 , 因此 ECMAScript 会不失时机的将浮点数值转换为整数值
    • 如果小数点后面没有任何数字 , 那么这个数值就会被转换为整数
    • 如果这个浮点数本身表示的就是一个整数( 如 1.0 ) , 那么这个值也会被转换为整数
  • 默认情况下 , ECMAScript 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法表示的数值 ( 如 0.0000003 会被转换为 3e-7 (3 * 10^-7))
  • 浮点数值的最高精度是 17 位小数 , 但是在进行算数计算的时候它的精确度却远远不如整数 , 例如 , 0.1 + 0.2 的结果不是 0.3
    var num = 0.1 + 0.2;
    alert(num === 0.3);     // false
  • 关于浮点数值计算会产生误差的问题 , 是基于 IEEE754 数值的浮点计算的通病 , 所有使用 IEEE754 格式进行浮点数值计算的语言都有这个问题

数值范围

由于内存限制 , ECMAScript 并不能保存世界上所有的数值

  • ECMAScript 能够表示的最小数值保存在 Number.MIN_VALUE 中 , 能够表示的最大数值保存在 Number.MAX_VALUE 中
  • 如果计算的数值超过上述的数值范围 , 那么这个数值就会自动转换为一个特殊的值 Infinity
    • 如果这个值是负数 , 则会被转换为 -Infinity ( 负无穷大 )
    • 如果这个值是正数 , 则会被转换为 Infinity ( 正无穷大 )
    • 一个正数除以 0 , 会返回 Infinity
    • 一个负数除以 0 , 会返回 -Infinity
  • 如果在某次计算中 , 结果返回了一个正的或者负的 Infinity 值 , 那么这个值将无法进行下一次计算 , Infinity 不是一个可以进行计算的数值
  • 如果我们想要知道一个数值是不是一个可以计算的数值 , 我们可以使用 isFinite() 函数 , 当参数是一个可以进行计算的数值是 , 会返回一个 true
    function test(){
        alert(isFinite(Number.MAX_VALUE));   // false
        alert(isFinite(Number.MIN_VALUE));   // false
        alert(isFinite(1));                  // true
    }

NaN

NaN 即非数值 ( Not a Number ) 是一个特殊的值 , 这个值表示一个原本要返回数值的操作未返回数值的情况 ( 这样就不会抛出错误了 )

  • 在 ECMAScript 中 , 任何数值除以非数值 ( 不能转换为数值 ) 都会返回 NaN , 0 除以 0 也会返回 NaN
  • NaN 本身具有两个特点
    • 任何涉及 NaN 的操作或者计算都会返回 NaN
    • NaN 和任何值都不相等 , 包括 NaN 本身
  • 如果我们想要知道一个变量的值是不是 NaN , 我们可以使用 isNaN( ) 函数 , 这个函数的参数可以是任何类型的值 , 当 isNaN( ) 在接收到一个参数的时候 , 就会对参数进行转换 , 如果不能转换为数值 , 就会返回 true
    function test(){
        alert( isNaN(10) );                 // "false"
        alert( isNaN("string") );           // "true"
        alert( isNaN(true) );               // "false" (可以被转换为数值1)
    }

数值转换

在 ECMAScript 中 , 有三个函数可以将非数值转换为数值 : Number( )、parseInt( )、parseFloat( )

  • Number( ) 可以用于转换任何数据类型 , 其他两个函数则专门用于将字符串转换成数值
  • Number( ) 的转换规则 :
    • 如果是 Boolean 值 , true 和 false 将会分别被转换为 1 和 0
    • 如果是 Number 值 , 只是简单地传入和传出
    • 如果是 Null , 返回 0
    • 如果是 undefined 返回 NaN
    • 如果是字符串 :
      • 如果是空字符串 , 返回 0
      • 如果字符串中只包含数字 , 并且是一个有效的十六进制格式数值 , 转换为相同大小的十进制整数值
      • 如果字符串中只有数字(包括前面的正号和负号) , 转换为十进制整数 , 忽略最前面的0 ( "011" 会被转换为 11 )
      • 如果字符串只有数字和小数点 , 并且是一个有效的浮点数值格式 , 转换为浮点数值 , 忽略最前面的 0 ( "01.1" 会被转换为 1.1 )
      • 如果不是以上几种字符串 , 返回 NaN 如果是对象 :
      • 调用对象的 valueOf( ) 方法 , 然后按照前面的规则转换返回的值 , 如果转换的值是 NaN , 调用对象的 toString( ) 方法 , 然后按照前面的规则转换返回的字符串
  • parseInt( ) 的转换规则 :
    • 忽略字符串前面的空格 , 直到找到第一个非空格字符
    • 如果第一个字符不是数字 , parseInt( ) 就会返回 NaN
    • 也就是说 , 用 parseInt( ) 转换空字符串或者以非数字开头的字符串都会返回 NaN ( Number( ) 函数转换空字符串会返回 0 )
    • 如果字符串的第一个字符是数字字符 , parseInt() 会继续解析字符串直到解析完字符串或者遇到了一个非数字字符
    • parseInt( ) 函数可以识别八进制、十进制、十六进制格式的数字字符
    • 但是识别起来会有一些模糊的地方 , 所以 parseInt( ) 的第二个参数可以指定转换时使用的进制
        function test(){
    
            var num = parseInt("0xAF", 16);         // 指定十六进制 , 返回 175
    
            var num1 = parseInt("0xAF", 10);        // 指定十进制 , 返回 0
    
        }
    
    • 不指定基数意味着让 parseInt( ) 自行决定如何解析输入的字符串 , 为了避免错误的解析 , 我们应该无论在什么情况下都要明确的指定基数
  • parseFloat( ) 的转换规则
    • 与 parseInt( ) 规则类似 , 但有几点不同
    • 小数点在 parseFloat( ) 方法中是一个有效的浮点数字字符 , 但是只有第一个小数点是有效的
    • parseFloat( ) 能够识别所有的浮点数值格式 , 但是它只解析十进制值 , 所以它会忽略前导的零 , 十六进制的数字字符会被识别为 0
    • parseFloat( ) 只解析十进制的数字字符 , 所以没有第二个参数来指定解析的基数

String 类型

String 类型表示由零或多个 16 位 Unicode 字符组成的字符序列 , 即字符串 . 字符串可以用单引号或者双引号表示

  • 字符字面量 :

    • String 数据类型包含一些特殊的字符字面量 , 也叫做转移序列 , 用于表示非打印字符 , 或者具有其他用途的字符
    • 以下是一些常用的字符字面量 :
    字面量 含义
    \0 空字符
    \n 换行
    \\ 斜杠
    \' 单引号
    \" 双引号
    • 字符字面量可以出现在字符串中的任意位置 , 而且也将被作为一个字符来解析
  • 字符串的特点

    • ECMAScript 中的字符串是不可变的 , 字符串一旦创建 , 它们的值就不能改变
    • 如果想要改变某个变量中保存的字符串 , 首先要销毁原来的字符串 , 然后再用另一个包含新值得字符串来填充该变量
  • 转换为字符串

如果想要将一个值转换为字符串 , 我们可以使用几乎所有值都有的 toString( ) 方法 , 和所有值都可以用的 String( ) 函数

  • toString( ) 方法 :
    • Number、Boolean、Object、String 这四种类型的值都有一个toString( ) 方法 , 剩下的 Null 和 Undefined 类型没有这个方法 , 所以 null 和 undefined 调用 toString( ) 方法会报错
    • Number 类型的数值在使用 toString( ) 方法的时候可以传一个参数 , 用来指定输出数值的基数 , 默认情况下 toString( ) 方法会以十进制格式返回数值的字符串表示
    • toString( ) 可以输出二进制、八进制、十六进制 , 乃至其他任意有效进制格式表示的字符串值
  • String( ) 函数
    • 在不知道要转换的值是不是 null 或者 undefined 的情况下 , 我们可以使用转型函数 String( ) , 这个函数可以将所有类型的值转换为字符串
    • 如果这个值有toString( ) 方法 , 调用这个方法 ( 没有参数 )
    • 如果这个值是 null , 返回 "null"
    • 如果这个值是 undefined , 返回 "undefined"

Object 类型

ECMAScript 中的对象其实就是一组数据和功能的集合

  • 我们可以通过 new 操作符来创建一个 object 类型的实例 , 并且可以为它添加属性和方法
    function test(){
        var obj = new Object( );        // 创建一个 object 类型的实例对象
        var obj1 = new Object;
        // 如果我们在创建实例对象的时候不传递任何参数 , 后面的括号可以省略 , 但不建议这么做
    }
  • 在 ECMAScript 中 , Object 类型是所有实例对象的构造函数 , 所有实例对象都有 Object 的属性和方法
    • constructor : 保存着用于创建当前对象的函数 ( 构造函数 )
    • hasOwnProperty( propertyName ) : 用于检查给定的属性在当前实例对象中是否存在( 而不是在实例的原型中 ) , 参数必须是字符串的形式
    • propertyIsEnumerable( propertyName ) : 用于检查给定的属性是否能够使用 for-in 语句来枚举 , 参数必须是字符串的形式
    • isPrototypeOf( object ) : 用于检查传入的对象是否是当前对象的原型
    • toLocaleString( ) : 返回一个使用地区特定的分隔符把生成的字符串连接起来形成的字符串 , 就是一个带有格式的字符串 , 例如 1234 会变成 1,234 , 标准时间也会变成本地时间格式.
    • toString( ) : 返回对象的字符串表示
    • valueOf( ) : 返回对象的字符串、数值、布尔值表示 , 通常和 toString( ) 方法的返回值一致

操作符

ECMA-262 描述了一组用于操作数据值的操作符 , 包括算术操作符 ( 如加好和减号 )、位操作符、关系操作符和相等操作符

一元操作符

只能操作一个值得操作符叫做一元操作符

  • 递增和递减操作符
    • 递增和递减操作符都有前置型和后置型两种 , 是直接借鉴 C 语言的
    • 前置型 : 先自身加一 , 后计算整体
    • 后置型 : 先计算整体 , 后自身加一
    • 递增操作符
        function test(){
            var age = 23;
            var num = 2;
            alert(++age + num);     // 前置型 , 先自身加一 , 输出 26
            alert(age);             // 24
        }
        function test1(){
            var age = 23;
            var num = 2;
            alert(age++ + num);     // 后置型 , 先计算整体 , 输出 25
            alert(age);             // 24
        }
    
    • 递减操作符与递增操作符类似
  • 递增和递减操作符适用于任何值 , 除了整数可以使用 , 字符串、布尔值、浮点值和对象都可以使用
    • 当一个值使用递增或递减操作符的时候 , 首先会将这个值转换为 Number 类型的值 , 然后再尝试进行计算操作
    • 如果一个字符串中只包含数字 , 那么会先将字符串转换为数字值然后进行计算
    • 如果一个字符串中包含数字以外的字符 , 那么会将字符串转换为 NaN
    • 如果是一个 Boolean 类型的值 , true 会转换为 1 , false 会转换为 0
    • 如果是一个浮点值 , 直接进行计算操作
    • 如果是一个对象 , 先调用对象的 valueOf( ) 方法 , 返回一个可操作的值 , 如果操作后返回 NaN , 则在调用 toString( ) 方法后再应用前述规则
    • 所有类型转换后都将变为 Number 类型
  • 一元加和减操作符
    • 一元加操作符以一个加号 ( + ) 表示 , 放在数值的前面 , 对于数值不会产生任何影响
    • 一元减操作符以一个减号 ( - ) 表示 , 放在数值的前面 , 主要用于表示负数
    • 对于非数值 , 一元加和减操作符会首先使用 Number( ) 转型函数对值进行转换
    • 一元加和减操作符主要用于基本的算术运算 , 也可以用于转换数据类型

布尔操作符

  • 无论这个值是什么数据类型 , 布尔操作符都会首先使用 Boolean( ) 转型函数将它转换为一个布尔值
  • 逻辑非
    • 逻辑非操作符由一个叹号 ( ! ) 表示 , 可以应用于 ECMAScript 中的任何值
    • 逻辑非只是一个简单地布尔值取反 , 也可以用两个叹号来获取当前值的布尔值 , 等同于使用 Boolean( ) 函数
  • 逻辑与
    • 逻辑与操作符由两个和号 ( && ) 表示 , 有两个操作数
    • 逻辑与是一个短路操作符 :
      • 如果第一个操作数的布尔值是 false , 那么逻辑与操作符会返回第一个操作数 , 不对第二个操作数进行求值操作
      • 如果第一个操作数的布尔值是 true , 那么逻辑与操作符会返回第二个操作数
  • 逻辑或
    • 逻辑或操作符由两个竖线负号 ( || ) 表示 , 有两个操作数
    • 逻辑或也是一个短路操作符 :
      • 如果第一个操作数的布尔值是 true , 那么逻辑或操作符会返回第一个操作数 , 不对第二个操作数进行求值操作
      • 如果第一个操作数的布尔值是 false , 那么逻辑或操作符会返回第二个操作数
  • 短路操作符 , 简而言之 , 返回能够决定最后结果的那个操作数
    • 逻辑与 : 只要有一个 false , 返回的布尔值为 false , 所以只要第一个操作数的布尔值是 false , 那么结果肯定是 false
    • 逻辑或 : 只要有一个 true , 返回的布尔值为 true , 所以只要第一个操作数是 true , 那么结果肯定是 true

乘性操作符

ECMAScript 定义了三个乘性操作符 : 乘法、除法、取余 ( 取模 )

  • 这些操作符在操作数是非数值的情况下会自动调用 Number( ) 函数执行类型转换
  • 乘法 : 乘法由一个星号 ( * ) 表示 , 用于计算两个数值的乘积
  • 在处理特殊值的情况下 , 乘法操作符遵循以下规则 :
    • 如果操作数都是数值 , 那么进行正常的乘法计算 , 如果乘积超过了最大数值范围 , 则会返回 Infinity 或者 -Infinity
    • 如果有一个操作数是 NaN , 返回 NaN
    • 如果是 Infinity 和 0 相乘 , 返回NaN
    • 如果是 Infinity 和 非 0 数值相乘 , 则结果是 Infinity 或者 -Infinity , 取决于非 0 数值的正负
    • 如果是 Infinity 和 Infinity 相乘 , 返回 Infinity
    • 如果是操作数是非数值 , 调用 Number( ) 函数将其转换为数值 , 然后应用上述规则
  • 除法 : 除法由一个斜线符号 ( / ) 表示 , 执行第二个操作数除第一个操作数的计算
  • 在处理特殊值的情况下 , 除法操作符遵循以下规则 :
    • 如果操作数都是数值 , 那么进行正常的除法操作 , 如果商超过了最大数值范围 , 则会返回 Infinity 或者 -Infinity
    • 如果有一个操作数是 NaN , 返回 NaN
    • 如果是 Infinity 和 Infinity 相除 , 返回 NaN
    • 如果是零和零相除 , 返回 NaN
    • 如果是一个有限的的非零数值被零除 , 返回 Infinity 或者 -Infinity
    • 如果是 Infinity 被任何非零数值除 , 返回 Infinity 或者 -Infinity
    • 如果是操作数是非数值 , 调用 Number( ) 函数将其转换为数值 , 然后应用上述规则
  • 取余 ( 取模 ) : 取余操作符由一个百分号 ( % ) 表示 , 第一个操作数除第二个操作数 , 得到余数
  • 与另外两个乘性操作符类似 , 在处理特殊值的情况下 , 取余操作符遵循以下规则 :
    • 如果被除数无限大 , 除数有限大 , 返回 NaN
    • 如果被除数有限大 , 除数为零 , 返回 NaN
    • 如果是 Infinity 被 Infinity 除 , 返回 NaN
    • 如果被除数有限大 , 除数无限大 , 返回被除数
    • 如果被除数是零 , 返回零
    • 如果是操作数是非数值 , 调用 Number( ) 函数将其转换为数值 , 然后应用上述规则

加性操作符

  • 加法
    • 如果是 Infinity 加 -Infinity , 返回 NaN
    • 如果有一个操作数是字符串 , 先将另一个操作数转换为字符串 , 然后拼接字符串
    • 如果操作数都是字符串 , 直接拼接字符串
  • 减法
    • 如果是 Infinity 减 Infinity , 返回 NaN
    • 如果是 -Infinity 减 -Infinity , 返回 NaN
    • 如果有一个操作数不是数值类型 , 先使用 Number( ) 函数将字符串转换为数值 , 然后计算

关系操作符

关系操作符返回的都是布尔值 , 共有四种操作符分别是 : 小于 ( < )、大于 ( > )、小于等于 ( <= )和大于等于 ( >= )

  • 如果两个操作数都是数值 , 正常比较大小
  • 如果有一个操作数是数值 , 另一个非数值类型 , 将其转换为数值类型然后比较大小
  • 如果两个操作数都是字符串 , 比较两个字符串对应的字符编码值
  • 如果有一个操作数是布尔值 , 转换为数值后比较大小
  • 如果是对象 , 调用 valueof( ) 方法 , 然后比较大小 , 如果对象没有 valueof( ) 方法 , 调用 toString( ) 方法 , 然后比较大小
  • NaN 和任何操作数进行比较都会返回 false

相等操作符

  • 相等和不相等 : 先转换再比较
    • 相等操作符由两个等号 ( == ) 号表示 , 如果两个操作数相等 , 返回true
    • 不相等操作符由一个叹号和一个等号 ( != ) 表示 , 如果两个操作数不相等 , 返回 true
    • 这两个操作符都会先转换操作数的数据类型 ( 强制转型 ) , 然后再比较它们的相等性
    • 转换规则 :
      • 如果有一个操作数是布尔值 , 转换为数值型数字 , true 是 1 , false 是 0
      • 如果有一个操作数是字符串 , 另一个操作数是数字 , 将字符串转换为数值
      • 如果一个操作数是对象 , 另一个不是 , 调用对象的 valueOf( ) 方法 , 用得到的基本数据类型进行上述比较
    • null、undefined和NaN的比较规则 :
      • null 和 undefined 是相等但不全等的
      • null 和 undefined 不能转换为任何值
      • 如果有一个操作数是 NaN , 相等操作符返回 false , 不相等操作符返回 true , NaN和任何数都不相等 , 包括 NaN 本身
      • 如果两个操作数都是对象 , 如果两个操作数都指向同一个对象 , 相等操作符返回 true
  • 全等和不全等 : 仅比较不转换
    • 全等操作符由三个等号 ( === ) 表示 , 如果两个操作数相等 , 返回true
    • 不相等操作符由一个叹号和两个等号 ( !== ) 表示 , 如果两个操作数不相等 , 返回 true
    • 这两个操作符会直接比较两个操作数 , 不转换数据类型

条件操作符

条件操作符是 ECMAScript 中最灵活的一种操作符了 , 而且他遵循了与 Java 中的条件操作符相同的语法形式

    var num1,num2...
    function test(){
        var max = (num1 > num2) ? num1 : num2;
        // 判断 num1 是否大于num2 , 返回 true 将 num1 的值赋给 max , 返回 false 将num2 的值赋给 max
    }

赋值操作符

  • 简单地赋值操作符由等于号 ( = ) 表示 , 其作用就是把右侧的值赋给左侧的变量
    function test(){
        var num = 1;
    }
  • 复杂的赋值操作就是在等号前面添加乘性操作符、加性操作符和位操作符
    function test(){
        var num = 1;
        num += 1;       // 等同于 num = num + 1 , 其他复杂赋值操作与之类似 , 只是替换前面的加号
    }
  • 这些复杂操作符的目的是简化赋值操作 , 使用它们不会带来任何性能上的提升

逗号操作符

  • 使用逗号操作符可以在一条语句中执行多个操作 , 多用于声明多个变量
    function test(){
        var num1 = 1, num2 = 2, num3;
    }
  • 逗号操作符可以用于赋值操作 , 在赋值时 , 逗号操作符会将表达式的最后一项返回
    function test(){
        var num = (1,2,3);      // num === 3
    }

语句

语句也被称为流控制语句 , 通常使用一个或多个关键字来完成给定任务

if 语句

    function test(){
        if ( Boolean ){             // 通过括号中的布尔值来控制执行的代码
            // do something...      // 布尔值为 true 时执行的代码
        } else{
            // do something...      // 布尔值为 false 时执行的代码
        }                           // 代码块必不可少 , 就算只有一行代码
    }

do-while 语句

后循环语句 , 条件值为 false 时结束循环 , 不论条件值是什么 , 肯定会执行一次代码

    function test(){
        do {                        // 后测试循环语句
            // do something...      // 先执行代码
        } while( Boolean );         // 再判断条件
    }

while 语句

前循环语句 , 条件值为 false 时结束循环 , 先判断条件再执行代码 , 如果条件值一开始就是 false 直接跳过循环体里面的语句执行下一步操作

    function test(){
        while ( Boolean ){          //先判断条件
            // do something...      //后执行代码
        }
    }

for 语句

for语句也是一种前循环语句 , 它是 while 语句的另外一种表现形式 , 可以看做是把 while 语句的代码集中在了一个位置上

    function test(){
        for (var i = 1; i < 10; i++){
            // do something...
        }
        /* 上面这段代码等同于下面的 while 语句 */
        var i = 1;
        while (i < 10){
            // do something...
            i++;
        }
    }
  • while 语句做不到的 , for 语句同样也做不到
  • 在 ES5 中由于没有块级作用域 , 所以 for 语句中声明的变量 , 在 for 语句外也可以访问到 ( 使用 var 声明的变量是局部变量 , 不使用 var 声明的变量是一个全局变量 )
  • 将 for 循环中的表达式省略掉 , 就可以创建一个无限循环
    function test(){
        for (;;){               // 这是一个无限循环
            // do something...
        }
    }

for-in 语句

for-in 语句是一种精准的迭代语句 , 可以用来枚举对象的属性

    var obj = {
        name : "oswald",
        age : 24
    };
    for (var propName in obj){  // 遍历 obj 中所有的属性
        alert(propName);        // "name" "age"
        alert(obj[propName]);   // "oswald" "24"
    }
  • 当属性值为 null 或 undefined 的时候 , 中断执行报出错误 , 所以在进行 for-in 语句之前最好检测一下是否有属性为 null 和 undefined 的情况
  • 和 for 语句类似 , for-in 语句声明的变量 , 在 for-in 语句外也可以访问
  • ECMAScript 中对象的属性是没有顺序的 , 所以通过 for-in 语句循环输出的属性名的顺序是不可预测的 , 虽然每个属性都会被返回一次 , 但是返回的先后次序可能会因浏览器而已
  • 不建议通过 for-in 语句来迭代数组对象 , 如果这个数组是一种有顺序关系的对象

break 和 continue 语句

break 和 continue 语句用于在循环中精确地控制代码的执行

    function test(){
        var num = 0;
        for (var i = 1; i < 10; i++){
            if(i % 2 === 0){
                // 当 i === 2 时 , 符合条件 , 跳出循环并且不再执行循环体
                break;                  
            }
            num++;
        }
        alert(num);   // 1
    }
    function test2(){
        var num = 0;
        for (var i = 1; i < 10; i++){
            if(i % 2 === 0){
                // 当 i === 2 时 , 符合条件 , 跳过本次循环 , 进入下一次循环
                continue;
            }
            num++;
        }
        alert(num);   // 5
    }

with 语句

with 语句的作用是将代码的作用域设置到一个特定的对象中

  • 严格模式下不允许使用 with 语句 , 将视为语法错误
  • 大量使用 with 语句会导致性能下降 , 也很难维护 , 不建议使用 with 语句

switch 语句

switch 语句和 if 语句的关系最为密切 , 而且也是在其他语言中普遍适用的一种流控制语句

    var i...
    function test(){
        switch(i){
            case 25 :
                alert("25");
                break;  
                // break 用于跳出当前 switch 语句 , 如果省略将会继续执行下一个 case , 如果刻意忽略 break 需要注释说明
            case 35 :
                alert("35");
                break;
            case 45 :
                // 合并两个case
            case 55 :
                alert("55");
                break;
            default :
                alert("other");
        }
    }
  • 可以在 switch 语句中使用任何数据类型 , 无论是字符串 , 还是对象都没有问题
  • 每个 case 的值不一定是常量 , 可以是变量甚至是表达式
  • 每个 case 值都可以返回一个布尔值 , 每个 case 按照顺序被求值 , 直到找到匹配的值或者遇到 default 语句为止
  • switch 语句在比较值的时候使用的是全等操作符

函数

函数可以封装多条任意的语句 , 并且可以在任何地方任何时候调用执行

  • ECMAScript 中的函数使用 function 关键字来声明 , 后面跟一组参数和函数体
  • 函数不必指定是否返回一个值 , 任何函数在任何时候可以通过 return 语句后跟要返回的值来实现返回值
    function test(num1, num2){
        return (num1 + num2);       // 停止执行函数 , 返回 num1 + num2 的值
        alert(num1);                // 不会执行这个操作
    }
  • 函数会在执行 return 语句后停止并立即退出 , 所以 return 语句之后任何代码都不会被执行
  • 一个语句中也可以包含多个 return 语句
    function test(num1, num2){
        if(num1 < num2){
            return (num2 - num1);
        } else{
            return (num1 - num2);
        }
    }
  • return 语句也可以不带任何返回值 , 这样 return 语句会默认返回 undefined

函数中的参数

  • ECMAScript 中的参数是在内部用一个数组来表示的 , 函数接收到的始终是这个数组
  • 我们可以在函数体内通过 arguments 对象来访问这个参数数组 , 从而获取传递给函数的每一个参数
  • arguments 对象只是类似数组 , 它并不是 Array 对象的实例 , 可以使用方括号语法来访问它的每一个元素 , 使用 length 属性来确定传递进来了多少个参数
  • 我们可以通过方括号语法来调用传递进来的参数 , 所以命名参数不是必须使用的
    function sayHi(name, message){
        alert("Hello" + arguments[0] + "," + arguments[1]);
        /* 上面的代码和下面的是一样的 */
        alert("Hello" + name + "," + message);  // 命名参数只提供使用便利 , 并不是必需的
        // arguments 对象的 length 属性可以知道有多少个参数传递给了函数
        alert(arguments.length);                // 2
    }
  • arguments 对象的值永远和命名参数的值保持同步
  • 没有传递值的命名参数将自动被赋予 undefined 值
  • ECMAScript 中的所有参数 , 传递的都是值 , 不会通过引用来传递参数 , 也就是说虽然上面例子中的 name 参数的值和 arguments[0] 的值是一样的 , 但是它们是两个不同的内存空间 , 只是保持值一致而已 , 对象也是如此
  • 由于不存在函数签名的特性 , ECMAScript 函数不能重载 , 但是可以通过检查传入函数中参数的类型和数量并作出不同的反应来模仿方法的重载