类型
七个内置类型
- 空值 (null)
 - 未定义 (undefined)
 - 布尔值 (boolean)
 - 数字 (number)
 - 字符串 (string)
 - 对象 (object)
 - 符号 (symbol)
 
检测各个类型
1  | typeof undefined === "undefined" // true  | 
本身null对象里面代表空值,所以其为object也是合理。但应该typeof null 返回是 null才符合常理。由于这个bug在许多代码中已经这样做了,所以重新修回会导致更严重的bug。因此被修回的可能性很小。
因此,对null应该采用复合查询语句
1  | var a = null;  | 
而对于typeof function(){} === “function” 而言,因为本身function是object的一个子类型,具体的说,函数是一个可调用对象。
且typeof [0,1] === “object”,因为数组也是object的一个子类型
ps:由于所有的typeof都会返回一个string,所以 typeof typeof 42会是”string”,因为typeof 42首先会变成一个“number”,是一个string类型,所以typeof “number”是一个string
undefined && undeclared && typeof undeclared
1  | var a;  | 
从上述可以看出,undefined 和 undeclared 是两码事。undefined意思是定义但未赋值,或者赋值为undefined,而undeclared是未定义。因此两者不能画等号
typeof undeclared
1  | typeof a // "undefined"  | 
出现这种原因因为typeof有一个特殊的安全防范机制,因为多个脚本文件会在共享的全局变量命名空间中加载变量。如果typeof一个未命名的报错,会导致整段程序停止运行。对于typeof来检查undeclared变量,有时是一个不错的办法。
值
数组
js的数组可以容纳任何的值,甚至可以是另一个数组,因此多维数组就是这种方式来实现的。
由于数组本身就是一个特殊的对象,所以数组也可以包含字符串键值和属性,但是这并不计算在数组长度内。
1  | var a = [];  | 
为什么会这样呢?由于本身数组就是一个对象的子集合,因此在[]中,使用十进制字符串数字会直接强制类型转化成数字。a[“13”]就变成了a[13],因此在数组内会直接将其长度变化成14。同理,在属性给foobar加到a数组中,因为数组的界定是有数字来确定下标位置,而length是最后一个下标数字+1,因而加入的非数字就不在长度里面了。
类数组
对于es5而言,可以用slice,concat来实现类数组转数组,对于es6而言,可以用Array.from()来实现从类数组转换成数组。
字符串
字符串的一些方法indexOf(),concat(),toUpperCase(),reverse()等等。
字符串的一些方法:
|方法|描述|
|—|—|
|charAt() | 返回指定索引位置的字符|
|charCodeAt() | 返回指定索引位置字符的 Unicode 值|
|concat() | 连接两个或多个字符串,返回连接后的字符串|
|fromCharCode() | 将 Unicode 转换为字符串|
|indexOf() | 返回字符串中检索指定字符第一次出现的位置|
|lastIndexOf() | 返回字符串中检索指定字符最后一次出现的位置|
|localeCompare() | 用本地特定的顺序来比较两个字符串|
|match() | 找到一个或多个正则表达式的匹配|
|replace() | 替换与正则表达式匹配的子串|
|search() | 检索与正则表达式相匹配的值|
|slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分|
|split() | 把字符串分割为子字符串数组|
|substr() | 从起始索引号提取字符串中指定数目的字符|
|substring() | 提取字符串中两个指定的索引号之间的字符|
|toLocaleLowerCase() | 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射|
|toLocaleUpperCase() | 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射|
|toLowerCase() | 把字符串转换为小写|
|toString() | 返回字符串对象值|
|toUpperCase() | 把字符串转换为大写|
|trim() | 移除字符串首尾空白|
|valueOf() | 返回某个字符串对象的原始值|
如果需要经常一字符数组的方式来处理字符串的话,倒不如直接用数组。这样就不用在字符串和数组之间来回折腾。可以在有需要的时候使用join(“”)来将字符串数组转换为字符串
数字
和大部分编程语言一样,js中的数字是基于IEE754标准来实现的。该标准通常也被称为“浮点数”。而js使用的是双精度单位(64位)格式。所以也会有iee754标准的通病,即浮点数之间相加会有奇妙的现象。
数字的一些方法:
toExponential()
1  | var a = 5E10 // 可以通过这种方式赋值  | 
因为.被视为常量42.的一部分。所以没有.属性访问运算符来调用toFixed()
toPrecision() // 执行有效位数的显示位数
1  | var a = 42.59  | 
EPSILON // 最小精度
1  | if(((0.1 + 0.2) - 0.3)<Number.EPSILON){  | 
MAX_VALUE
MAX_SAFE_INTEGER
1  | Number.MAX_VALUE // 1.7976931348623157e+308  | 
isInteger
1  | Number.isInteger(1) // true  | 
特殊数值
undefined
1  | var undefined = 2  | 
ps:永远不要重新定义undefined
void 运算符
在不需要返回值的时候,可以void掉
1  | if(ready){  | 
这样做可以将setTimeout返回的id给void掉
NaN
NaN是一个数值型。意思指的是不是一个数值,并且NaN != NaN。可以使用isNaN来判断是否是NaN
1  | Number.isNaN(NaN) // true  | 
0值
加法和减法运算永远不会有-0
使用toString和JSON.stringify()会将-0变成0
1  | 0/-1 // -0  | 
特殊等式
Object.is
Object.is 可以判断是+0还是-0,而且可以判断是否为NaN
1  | Object.is(+0, -0) // false  | 
值和引用
null,undefined,字符串,数字,布尔,symbol都是简单值
对象,函数都是复杂值
1  | function foo(x) {  | 
ps:我们无法自行决定使用值赋值还是引用赋值,一切由值的类型决定
1  | function foo(warpper){  | 
原生函数
- String
 - Number
 - Boolean
 - Array
 - Object
 - Function
 - RegExp
 - Date
 - Error
 - Symbol
 
内部属性[[Class]]
所有typeof返回值为“Object”的对象(如数组)都包含一个内部属性[[Class]],这个属性通常无法直接访问,一般通过Object.prototype.toString查看
1  | Object.prototype.toString.call([123]) // "[object Array]"  | 
虽然Null和undefined这样的原声构造函数不存在,但是内部Class属性值仍然是Null和Undefined。基本类型值被各自的封装对象自动包装,所以他们的内部[[Class]]属性值为Boolean。
封装对象包装
1  | var a = "abc";  | 
只是创建字面量基本值的时候,并没有其他的方法。当在使用其对象方法时,需要通过封装对象才能访问,此时js会自动为基本类型值包装(box或者wrap)一个封装对象。
但是为经常用到的.length方法直接new一个对象也不是一个好办法,因为浏览器对.length这样的常见情况做了优化,直接使用封装对象来“提前优化”反而会降低执行效率。
封装对象的释疑
例如:
1  | var a = new Boolean(false);  | 
因为建立一个a之后,这个对象得到的是真值,得到的结果和使用false相反
自行封装可以使用Object
1  | var a = "abc"  | 
一般不直接使用封装对象,但是他们偶尔也会派上用场
拆封
如果想得到封装对象里面的值,可以使用valueOf函数,隐式拆封也是调用了valueOf函数:
1  | var a = new String("abc")  | 
原生函数作为构造函数
四种方式创建应该尽量避免构造函数,除非十分必要
- array 数组
 - object 对象
 - function 函数
 - RegExp 正则表达式
ARRAY(..)
调用Array构造函数时,可以不需要加上new,效果一致。)且Array构造函数纸袋一个数字作为参数的时候,这个参数会当作数组的预设长度,而不是充当其中的一个元素1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 效果一致
var a = new Array(1,2,3);
a // [1,2,3]
var b = Array(1,2,3)
b // [1,2,3]
var c = [1,2,3]
c // [1,2,3]
// 不同方式创建出来空数组效果不一致
var d = new Array(3);
console.log(d) // chrome上: (3) [empty × 3]
d.length // 3
var e = [undefined,undefined,undefined];
console.log(e) // (3) [undefined, undefined, undefined]
var f = []
f.length = 3;
console.log(f); // chrome上: (3) [empty × 3]
// 直接以,创建。虽然长度是3令人费解,但是可以更好的复制粘贴
var g = [,,,]
console.log(g) // chrome上: (3) [empty × 3] 
由于创建方式不同,导致在chrome下不一致的显示,但是更难过的是,他们有时相同,有时呵呵
1  | var a = new Array(3)  | 
a.map之所以执行失败,是因为a中是没有元素的,而b里面有undefied。
而join首先假定数组不为空,然后通过length属性值来便利其中的元素,而map并不做这种假定
可以通过这种方式来创建包含undefined单元的数组
1  | var a = Array.apply(null, {length:3});  | 
PS:永远不要创建和使用空单元数组
OBJECT、FUNCTION、REGEXP
除非玩不得已,尽量不要使用他们
1  | var c = new Object();  | 
javascript对常量形式的代码会对他们进行预编译和缓存!
DATE、ERROR
相较于其他原生构造函数,Date、Error的用处比其他的更多,因为没有其他对用的常量形式来作为他们的替代
引入生成当前时间戳,使用
1  | Date.now()  | 
错误对象通常与throw一起使用
1  | function foo(x){  | 
SYMBOL
Symbol可作为私有属性是一种简单标量基本类型
强制类型转换
抽象值操作
如果对象有自己的toString()方法,字符串化就会调用该方法并使用其返回值。
数组的默认toString方法经过了重新定义
1  | var a = [1,2,3]  | 
JSON 字符串化
JSON.stringify(42) // “42”
JSON.stringify(“42”) // “”42””
JSON.stringify(null) // “null”
JSON.stringify(true) // “true”
JSON.stringify()在对象中遇到undefined、function和symbol时会自动将其忽略,在数组中则会返回null
1  | JSON.stringify(undefined) // undefined  | 
循环引用会出错
1  | var o = {};  | 

