类型、值和变量
数据类型
-
原始类型和对象类型
- 原始类型:数字、字符串和布尔值
- 特殊原始值:null和undefined,分别代表各自特殊类型的唯一成员
- 对象类型:属性的集合,每个属性由键值对构成
- 特殊对象:数组,表示带编号的值的有序集合
- 特殊对象:函数,表示具有与之相关联的可执行代码的对象
- 原始类型:数字、字符串和布尔值
-
可以拥有方法的类型和不能拥有方法的类型
-
可变类型和不可变类型(值能否修改)
- 可变:对象、数组
- 不可变:数字、布尔值、null和undefined
值与变量
-
数字:js不区分整数值与浮点数值,所有数字均用浮点数值表示,采用IEEE 754标准定义的64位浮点格式表示,能表示的整数范围为-253~253
-
整型直接量:支持十进制、十六进制,八进制某些实现下支持(ES6严格模式明令禁止)
-
浮点型直接量:
-
算术运算:溢出、下溢或被零整除时不会报错
- 溢出:超出数字上下限,返回正无穷大(Infinity)或负无穷大(-Infinity)
- 下溢:无限接近于零且比能表示的最小值还小,返回0(正数)或“负零”(负数)
- 被零整除:简单返回无穷大或负无穷大,但零除以零时返回NaN
- 无穷大除以无穷大、负数开方或算术运算符与不是数字或无法转换为数字的操作数一起使用时,都将返回NaN
-
Infinity和NaN为两个已经定义好的只读全局变量
- NaN和任何值都不相等,包括自身,判断变量x是否为NaN可用x!=x或函数isNaN()(参数为NaN或非数字值时返回true)
- Infinity也可以用函数isFinite()判定,在参数不是NaN、Infinity或-Infinity时返回true
-
负零值:与正零值几乎相等,仅当作为除数时会不相等
-
浮点数:采用IEEE-754浮点数表示法,但不能精确表示,会出现四舍五入差异,因此建议使用整数进行重要的计算
-
日期时间:用Date()构造函数创建表示日期和时间的对象,并提供简单API
-
-
文本(字符串):由16位值组成的不可变有序序列,每个字符来源于Unicode字符集,字符串长度为所含16位值个数,索引从0开始,无表示单个字符的“字符型”
- 字符串直接量:由单引号或双引号直接括起,ES3中必须写在一行,ES5写成多行必须用“\”作为结束
- 转义字符:支持转义字符,如果“\”位于无转义的字符前,会被自动忽略
- 字符串使用:可用“+”连接字符串,用length属性获得字符串长度,以及各种方法
- 模式匹配:采用Perl中的正则表达式语法,利用RegExp()构造函数创建表示文本匹配的对象,可以用两条斜线之间的文本表示一个正则表达式直接量
-
布尔值:保留字true和false,包含toString()方法,
- if( o !== null ) 仅当o不为null时执行,if( o ) 仅当o不为false或任何假值时才会执行。
- 三个布尔运算符:&&、||和!
-
null和undefined
- null
- 用于表示空值
- typeof结果为object,即为一个特殊的对象值,含义为“非对象”
- 可表示数字、字符串或对象是“无值”的
- undefined
- 用于表示值的空缺,表明变量没有初始化
- 查询值时返回undefined表示这个属性或元素不存在
- 函数没有返回值则返回undefined
- 引用没有提供实参的函数形参的值也会得到undefined
- 是预定义的全局变量,ES5中为只读,typeof结果为undefined
- “==”判断二者为相等的,“===”可以区分它们
- 都是假值,在希望值是布尔类型的地方和false类似
- 不包含任何属性和方法,使用“.”和“[]”都会产生一个类型错误
- 通常undefined用于表示系统级的、出乎意料的或类似错误的值的空缺;null表示程序级的、正常的或意料之中的值的空缺。赋值、传参最好使用null
- null
-
全局对象
- js程序可直接使用全局对象的属性
- js解释器启动时,将自动创建一个全局对象,并给它一组定义的初始属性
- 全局属性:如undefined、Infinity和NaN
- 全局函数:如isNaN()、parseInt()和eval()
- 构造函数:如Date()、RegExp()、String()、Object()和Array()
- 全局对象:如Math和JSON
- 可在代码最顶级,即不在任何函数内的js代码中,用this指代全局对象
- 客户端js中,Window对象充当了全局对象,可代替this来引用全局对象
-
包装对象:存取字符串、数字或布尔值属性时创建的临时对象
- 只是偶尔用来区分值与对象
- 可通过String()、Number()或Boolean()显示创建,且创建后的包装对象与原值在“==”下视为相等,在“===”下视为不等
-
不可变的原始值与可变的对象引用
- 原始值不可更改,任何方法都无法更改一个原始值
- 原始值的比较是值的比较,对字符串来说当且仅当它们长度相等且每个索引字符都相等时才相等
- 对象是可变的,它们的值可修改
- 对象的比较并非值的比较,两个包含同样属性与相同值的对象是不相等的,各索引元素完全相等的两个数组也不相等
- 对象常称为引用类型,其比较为引用的比较,当且仅当引用同一个基对象时才相等
- 将对象赋值给一个变量时,仅仅赋予引用值。如果想得到一个对象或数组的副本,必须显式复制每个属性或元素
-
类型转换
- 显式类型转换:使用Boolean()、Number()、String()或Object(),或toString()方法
- 试图将null或undefined转换为对象会抛出一个类型错误,但Object()仅仅只返回一个新创建的空对象
- 某些运算符会做隐式类型转换,如“+”转换为字符串,一元“+”转换为数字,一元“!”转换为布尔等
- Number类定义的toString()方法可接收作为转换基数的参数(2~36之间),默认基于十进制转换
- toFixed()方法根据小数点后的指定位数将数字转换为字符串
- toExponential()方法使用指数计数法,小数点后位数由参数指定
- toPrecision()方法根据指定的有效数字位数转换为字符串,若少于整数部分位数则转换成指数形式
- parseInt()只解析整数,可传入第二个参数指定数字转换基数;parseFloat()可解析整数和浮点数。
□ 二者都会跳过任意数量空格,解析尽可能多的数字字符,并忽略后面的内容。
□ 若第一个非空格字符为非法数字直接量,会返回NaN
- 对象转换原始值:
- 对象到布尔值:所有对象均转换为true
- 所有对象都继承有toString()函数与valueOf()函数,前者根据不同类有不同的特定版本,后者默认返回原始值或对象本身
- 对象到字符串转换步骤:
□ 若对象具有toString()方法,则调用该方法;若它返回一个原始值,则将值转换成字符串并返回
□ 若对象不具有toString()方法,或该方法不返回一个原始值,则调用valueOf()方法。此时若对象具有valueOf()方法则调用,若返回值为原始值,则转换为字符串再返回
□ 若对象不具有toString()和valueOf()方法且无法从中获得一个原始值,则抛出一个错误异常 - 对象到数字转换步骤:
□ 若对象具有valueOf()方法且返回一个原始值,则转换为数字并返回
□ 否则,若对象具有toString()方法且返回一个原始值,则转换为数字并返回
□ 否则,抛出一个类型错误异常 - “+”运算符操作时,若其中一个为对象,则会将对象转换为原始值(而非数字)
- “==”等关系运算符操作时,若为一个对象和一个原始值操作,也会将对象转换为原始值
- 对于非日期对象,对象到原始值的转换基本是对象到数字的转换
- 对于日期对象,则会使用对象到字符串的转换模式,且此转换模式会直接使用valueOf()或toString()返回的原始值,并不会转换成数字或字符串
- 显式类型转换:使用Boolean()、Number()、String()或Object(),或toString()方法
-
变量声明:使用关键字var
- 重复声明变量是合法无害的,若带有初始化器则将直接被看成简单的赋值语句
- 读取未声明变量值时会报错
- 在ES5严格模式中,给一个没有声明的变量赋值也会报错。而在非严格模式下,js会给全局对象创建一个同名属性
-
变量作用域
- 全局变量具有全局作用于,在js代码中任何地方都有效
- 函数内声明变量只在函数体内有定义,为局部变量,作用域也是局部性的,函数参数也是局部变量
- 在函数体内,局部变量优先级高于同名全局变量,会对同名全局变量进行覆盖
- 声明局部变量必须用var,否则会创建或修改全局变量的值
- 函数定义和局部作用域都是可嵌套的
- 声明提前:js函数里声明的所有变量(但不涉及赋值)都会被“提前”至函数体顶部
- 属性变量:使用var声明一个变量时,创建的属性是不可配置的,即不可通过delete运算符删除该变量;但在非严格模式下自动创建的全局变量是全局对象的正常可配置属性,可以进行删除
- js可以使用this引用全局对象,但没有方法可以引用局部变量中存放的对象
- 作用域链
- 每一段js代码都有一个与之相关联的作用域链,是一个对象列表或链表,这组对象定义了这段代码作用域中的变量。js查找变量x的值时,会依次在链中每一个对象上查找属性,直到最后抛出一个引用错误异常
- js顶层代码中,作用域链由一个全局对象构成;在不包含嵌套的函数体内,作用域链由定义函数参数和局部变量的对象与全局对象组成;在嵌套函数体内,作用域链上至少有3个对象
- 定义一个函数时,它会保存一个作用域链。当调用它时,它会创建一个新的对象存储它的局部变量,并添加到保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的链
- 对于嵌套函数来说,每次调用外部函数时,内部函数都会重新定义一遍,因为每次调用时作用域链都是不同的