1.内置类型
1.1 JavaScript有7种内置类型
序号 | 类型 | 含义 | typeof返回值 |
---|---|---|---|
1 | null | 空值 | object |
2 | undefined | 未定义 | undefined |
3 | boolean | 布尔值 | boolean |
4 | number | 数字 | number |
5 | string | 字符串 | string |
6 | object | 对象 | object |
7 | symbol | 符号 | symbol |
1.2 注意点
1.2.1 null值检测
由于null值返回object,需要通过复合条件检测null值
var a = null
if(!a && typeof a === 'object') {
console.log('a is null')
}
1.2.2 typeof function(){}
对函数使用typeof运算符会返回’function’
1.2.3 typeof的安全防范机制及应用
对于undeclared(或者not defined)变量,typeof照样返回undefined,虽然变量未声明,但typeof并没有报错,这是因为typeof有一个特殊的安全防范级制。
该安全防范机制对在浏览器中运行的JavaScript代码很有帮助,因为多个脚本文件会在共享的全局命名空间中加载变量,通过typeof的安全防范级制(阻止报错)来检查哪些是未声明的变量。
2. 值
数组,字符串,数字
2.1 数组
2.1.1 delete
使用delete运算符可以将单元从数组中删除,但是单元删除后,数组的length属性不会改变
2.1.2 数组索引
数组通过数字进行索引,但他们也是对象,所以也可以包含字符串键值和属性,如果字符串键值能被强制类型转换为十进制数字的话,它就被当作数字索引来处理。
2.1.3 类数组转换为数组
详情参考数组和类数组及arguments
2.1.4 数组检测
- Array.isArray 推荐用法
- instanceof Array 如果存在多个全局环境(多个框架),从而存在多个不同版本的Array构造函数,检测会不准确
- Object.prototype.toString.call 判断如果返回值是[object Array],说明是数组
2.1.5 数组API
修改原数组的API有:
splice/reverse/fill/copyWithin/sort/push/pop/unshift/shift
不修改原数组的API有:
slice/map/forEach/every/filter/reduce/entries/find
2.1.6 转换方法
- toString():返回由数组中每个值的字符串形式拼接而成的以逗号分隔的字符串。
- valueOf():返回数组本身
- join():使用传入的分隔符构建字符串,如果不给join方法传入任何值,或者给它传入undefined,则使用逗号作为分隔符
2.1.7 栈方法
栈是一种LIFO(last-in-first-out)的数据结构,push和pop可以模拟类似栈的行为。
- push():接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
- pop():从数组末尾移除最后一项,然后返回移除的项
2.1.8 队列方法
队列是一种先进FIFO(先进先出)的数据结构,结合使用shift和push可以模拟队列的行为,另外同时使用unshift和pop可以从相反的方向来模拟队列。
方向从右向左
- shift():移除数组的第一项
- push():接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
方向从左向右
- unshift():数组前端添加任意项并返回数组的长度。
- pop():从数组末尾移除最后一项,然后返回移除的项
2.1.9 操作方法
定义 | 参数 | 说明 |
---|---|---|
操作方法 | ||
concat(value1[, value2[, …[, valueN]]]) | 数组和/或值,将被合并到一个新的数组中。如果省略了所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝 | 基于当前数组的所有项创建一个新数组,不会更改现有数组。如果传递的参数是一个数组,则会将这些数组中的每一项都添加到结果数组中,如果传递的不是数组,这些值会被简单的添加到结果数组末尾 |
slice([begin[, end]]) | begin:如果是负数,则从倒数第几个元素开始取,如果大于数组length,则返回空数组。 end:如果为负数,则它表示在原数组中的倒数第几个元素结束抽取,如果被省略,取到数组结尾,如果大于数组长度,也取到数组结尾 |
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。 |
splice(start[, deleteCount[, item1[, item2[, …]]]]) | start:指定修改的开始位置,如果超出数组长度,从末尾开始添加元素,如果是负值,则表示从数组末位开始的第几位,如果负数的绝对值大于数组长度,则开始位置为0 item1, item2, … 可选要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。 |
|
位置方法 | ||
indexOf(searchElement[, fromIndex]) | searchElement:要查找的项 fromIndex:开始查找的位置 |
|
lastIndexOf(searchElement[, fromIndex]) | (searchElement[, fromIndex]) | |
迭代方法 | ||
map | 返回每次函数调用的结果组成的数组 | |
fliter | 对数组每一项运行给定函数,返回该函数返回true的项构成的数组 | |
forEach | 对数组中每一项运行给定函数,无返回值 | |
every | 对数组中的每一项运行给定函数,如果都返回true则返回true | |
some | 对数组中的每一项运行给定函数,如果函数对任一项返回true,则返回true | |
并归方法 | ||
reduce | 从左向右遍历 | |
reduceRight | 从右向左遍历 |
注:reduce方法回调函数第一次执行时,accumulator
和currentValue
的取值有两种情况:如果调用reduce()
时提供了initialValue
,accumulator
取值为initialValue
,currentValue
取数组中的第一个值;如果没有提供 initialValue
,那么accumulator
取数组中的第一个值,currentValue
取数组中的第二个值。
要累加对象数组中包含的值,必须提供初始值,以便各个item正确通过你的函数。如下所示:
let initialValue = 0
let sum = [{ x: 1 }, { x: 2 }, { x: 3 }].reduce((acc,curr,index,arr) => { return acc + curr.x }, initialValue)
2.2 字符串
2.2.1 字符串转义序列
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 进制 |
\\ | 斜杠 |
\‘ | 单引号,在用单引号表示的字符串中使用 |
\“ | 双引号,在用双引号表示的字符串中使用 |
\xnn | 以16进制代码nn表示的一个字符(其中n为0~F) |
\unnn | 以16进制代码nnnn表示的一个Unicode字符(其中n为0~F) |
2.2.2 字符串的特点
ECMAScript中的字符串是不可变的,字符串一旦创建,它们的值就不能改变,要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新知的字符串填充该变量。
2.2.3 通过数组函数处理字符串
需要数组函数处理字符串很方便,可以通过call apply间接调用,示例如下:
var a = 'foo'
var b = Array.prototype.join.call(a,'-')
var c = Array.prototype.map.call(a, ch => ch.toUpperCase() + ".")
注意:字符串反转不能直接使用Array.prototype.reverse.call(),而应该使用变通的方式,如下所示:
var a = "abcdef"
var b = a.split('').reverse().join('')
2.2.4 字符串方法
定义 | 参数 | 说明 |
---|---|---|
字符方法 | ||
charAt(index) | index一个介于0 和字符串长度减1之间的整数。 (0~length-1)如果没有提供索引,charAt() 将使用0。 | 已单字符字符串形式返回给定位置的字符 |
charCodeAt(index) | index一个介于0 和字符串长度减1之间的整数。 (0~length-1)如果没有提供索引,charAt() 将使用0。 | 已字符编码形式返回给定位置的字符 |
字符串操作 | ||
concat() | ||
slice() | ||
substring() | ||
substr() | ||
trim() | 创建一个字符串副本,删除前置及后缀的所有空格 | |
String.fromCharCode() | 接受一个或多个字符编码,将其转换为一个字符串 | |
位置方法 | ||
indexOf(element[,startIndex]) | ||
lastIndexOf(element[,startIndex]) | ||
大小写转换 | ||
toUpperCase() toLocalUpperCase() | ||
toLowerCase() toLocalLowerCase() |
利用indexOf匹配所有子字符串位置示例代码:
var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit"
var positions = []
var pos = stringValue.indexOf("e")
while(pos > -1){
positions.push(pos)
pos = stringValue.indexOf("e",pos+1)
}
return positions
2.3 数字
JavaScript中的数字类型是基于IEEE 754标准来实现的,该标准也被称为浮点数,JavaScript使用的是”双精度”格式(即64位二进制)
2.3.1 数字的语法
toFixed():指定小数部分的显示位数,如果指定的小数部分的显示位数多于实际位数就用0补齐。
toPrecision():指定有效数位的显示位数。包括整数部分。
注意:42.toFixed(3)是无效语法,因为.被视为常量42.的一部分,可以使用(42).toFixed(3)
_
2.3.2 二进制浮点数误差
二进制浮点数最大的问题是会出现如下情况:
0.1 + 0.2 === 0.3 //false
二进制浮点数中的0.1和0.2并不是十分精确,它们相加的结果并非刚好等于0.3而是一个比较接近的数字,所以判断条件为false。最常见的方法是设置一个误差范围值,通常称为”机器精度”,对于JavaScript来说这个值通常是 2^-52(Math.pow(2,-52)),该值定义在Number.EPSILON中。
function numberCloseEnoughToEqual(n1,n2) {
return Math.abs(n1 - n2) < Number.EPSILON
}
2.3.3 整数的安全范围及最大 最小浮点数
最大浮点数:Number.MAX_VALUE
最小浮点数:Number.MIN_VALUE
能够被安全呈现的最大整数: Number.MAX_SAFE_INTERGER (2^53 - 1)
能够被安全呈现的最小整数:Number.MIN_SAFE_INTEGER
超出JavaScript数值范围的值,会被自动转换成特殊的Infinity值,如果这个值是负数则会转换为-Infinity,确定一个值是不是有穷可以使用isFinite()函数
2.3.4 整数检测
检测一个值是否是整数,使用ES6的Number.isInteger()方法。
Number.isInteger('123') //false
Number.isInteger(123) //true
Number.isInteger(123.3) //false
Number.isInteger(-0) //true
针对ES6之前版本的polyfill方法
if(!Number.isInteger) {
Number.isInteger = function(num) {
return typeof num === 'number' && num % 1 === 0
}
}
检测一个值是否是安全的整数,使用ES6的Number.isSafeInteger()方法.
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) //true
Number.isSafeInteger(Math.pow(2,53)) //false
Number.isSafeInteger(Math.pow(2,53) - 1) //true
针对ES6之前版本的polyfill代码
if(!Number.isSafeInteger) {
Number.isSafeInteger = function(num) {
return Number.isInteger(num) &&
Math.abs(num) <= Math.pow(2,53) -1
}
}
2.3.5 NaN
数学运算的操作数不是数字类型,就无法返回一个有效的数字,这种情况下返回值为NaN.意指”不是一个数字”(not a number)。其实更准确的意思应该是”无效数值” “失败数值”。任何涉及NaN的操作都会返回NaN,NaN仍然是数字类型。
typeof NaN === 'number' //true
检测变量的值是否为NaN,不能和NaN直接比较判断,NaN是一个特殊值,它和自身不相等,是唯一一个非自反的值(NaN != NaN 为true).标准的检测方法为Number.isNaN(),针对ES6之前版本的polyfill代码如下:
//版本1
if(!Number.isNaN) {
Number.isNaN = function(num) {
return typeof num === 'number' &&
window.isNaN(num)
}
}
//版本2 利用NaN非自反的特点直接判断传入参数是否和自身相等
if(!Number.isNaN) {
NUmber.isNaN = function(num) {
return num !== num
}
}
2.3.6 零值
JavaScript有一个常规的0和一个-0.
var a = 0/-3 //-0
var b = 0*-3 //-0
//////////////////////////////
var c = 0
a == c //true
-0 == 0 //true
a === c //true
-0 === 0 //true
要区分-0和0,需要做一些特殊逻辑处理,如下代码所示:
function isNegZero(n) {
n = Number(n)
return (n === 0) && (1 / n === -Infinity)
}
2.3.7 特殊等式
针对以上特殊情况的等式判断,ES6新加入了一个工具方法。Object.is(),来判断两个值是否绝对相等
注意:能够使用 ==和===时尽量不要使用Object.is(),因为前者的效率更高,Object.is()主要用于处理特殊情况
var a = 2 / 'foo'
var b = -3 * 0
Object.is(a,NaN) //true
Object.is(b,-0) //true
Object.is(b,0) //false
3. 复制变量值
3.1 基本类型
如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,这两个值可以参与任何操作而不会互相影响。
3.2 引用类型
当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到新变量分配的空间,不同的是,这个值实际上是一个指针,这个指针指向存储在堆中的一个对象,复制操作结束后,两个变量实际将引用同一个对象。
4. 检测类型
typeof运算符常用于检测基本类型值,检测引用类型值时,通常会使用instanceof操作符