类型和语法
类型
内置类型
JS有七种内置类型空值(null)
、未定义(undefined)
、布尔值(boolean)
、数字(Number)
、字符串(String)
、对象(Object)
、符号(Symbol)
typeof
检测null会得到”object”, 使用(!a && typeof a === 'object')
即可得到正确的结果
typeof
检测函数会得到”function” ,但是函数是object
的子类型,具体来说函数是“可调用对象”。
typeof
检测数组会得到”object”,数组也是object
的子类型。
值和类型
JS的变量是没有类型的,只有值才有,变量可以随时持有任何类型的值
对于未定义变量的检测
typeof
检测对于未定义变量也返回undefined
,这个机制可以帮助我们检测一个全局变量是否存在
if (a) {
... // ReferenceError: a is not defined
}
if (typeof a !== undefined) {
... // OK
}
值
数组
创建的”稀疏数组”中的空白单元会表现为undefined
但是和实际上赋值为undefined
仍有区别
字符串键值如果能被强制转化为数字,则会被转化成数字索引
为字符串键值赋值,数组总长度不会变化,即
var a = []
a["1"] = 1
a["dd"] = '阿巴阿巴阿巴'
a.length === 2 // true
字符串
字符串和数组很相似,都拥有indexOf
、concat
等方法,但是实际上并不相同
字符串值不可变,成员函数会返回一个新的字符串
a = ['f', 'o' ,'o']
b = 'foo'
a[1] = 'O'
b[1] = 'O'
a // ['f', 'O', 'o']
b // foo
字符串可以借用很多数组的方法,譬如join
、map
,不过对于字符串反转来讲,由于字符串不可变所以不可以直接用reverse
,替代方法是
var a = 'abc'
var b = a
// 将a的值转化为字符数组
.split("")
// 将数组中的值进行倒转
.reverse()
// 将数组中的值拼回字符串
.join("")
b // "cba"
注意:以上方法只适用于简单的字符串,对于复杂字符(UniCode、星号、多字节字符等)的字符串并不适用,去网上找库去
数字
js中只有一种数字,包括整数和带小数的十进制数,整数即是没有小数的十进制数。所以42.0等于“整数”42
js使用的是“双精度”格式,即64位二进制
数字的语法
不要直接在字面量数字后边调用方法,.
操作符会被认为是数字的小数点
// 无效语法:
42.toFixed( 3 ); // SyntaxError
// 下面的语法都有效:
(42).toFixed( 3 ); // "42.000"
0.42.toFixed( 3 ); // "0.420"
42..toFixed( 3 ); // "42.000" 请注意多出来的点
42 .toFixed( 3 ); // "42.000" 请注意空格
可以用指数形式来表示比较大的数字,特别大和特别小的数字默认用指数格式显示,与 toExponential()
函数的输出结果相同
var a = 5E10;
a; // 50000000000
a.toExponential(); // "5e+10"
var b = a * a;
b; // 2.5e+21
var c = 1 / a;
c; // 2e-11
整数的安全范围
能够被“安全”呈现的最大整数是 2^53 - 1,即 9007199254740991
,在 ES6 中被定义为Number.MAX_SAFE_INTEGER。
最小整数是 -9007199254740991
,在 ES6 中被定义为 Number.MIN_SAFE_INTEGER。
void 运算符
我们可以使用void 0
来获得undefined
,void ___
都会返回undefined
void加在表达式之前可以让表达式返回undefined
return void doSomething();
// -> 等同于
doSomething();
return;
特殊的数字
NaN
意指“不是一个数字”,typeof检测仍返回”number”,不过它不和任何东西相等,即使是==
,可以使用Number.isNaN()
来进行判断
不要使用全局
isNaN()
,它有BUG!
isNaN的polyfill
if (!Number.isNaN) {
Number.isNaN = function(n) {
return (
typeof n === 'number' &&
window.isNaN(n)
)
}
}
// 或者利用其与自己不相等
if (!Number.isNaN) {
Number.isNaN = function(n) {
return n !== n
}
}
js使用有限数字表示法,所以一旦计算结果溢出为“无穷数”,就无法再得到“有穷数”
js中存在-0
值,是因为在一些应用中,符号位可能会代表其他信息,譬如方向,如果一个值为0的变量失去了它的符号位,那么方向信息可能就会丢失,日常代码中几乎不会遇见
ES6中新加入了一个工具方法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
能使用
==
或者===
就不要使用Object.is()
,因为前者效率更高
值和引用
简单值,即标量基本类型值,总是通过值复制的方式来赋值和传递,包括null、undefined、字符串、数字、布尔值和符号
复合值,对象和函数总是用过引用复制的方式来进行赋值和传递
由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向
function foo(x) {
x.push(4);
x; // [1,2,3,4]
// 然后
x = [4,5,6]
x.push(7)
x; // [4,5,6,7]
}
var a = [1,2,3]
foo(a);
a;
// 是[1,2,3,4]而不是[4,5,6,7]
原生函数
常见的原生函数有
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()
实际上他们就是内建函数
原生函数可以被当作构造函数来使用
var a = new String('abc')
typeof a // 是object 不是string
a instanceof String // true
Object.prototype.toString.call(a) // '[object String]'
new String('abc')
创建的是字符串“abc”的封装对象,而非基本类型值”abc”
内部属性
所有typeof返回值为object的对象都包含一个内部属性[[class]],我们可以把它看作一个内部的分类,而非传统的面向对象意义上的类,这个属性无法直接访问,一般通过Object。prototype.toString()
来查看
Object.prototype.toString.call([1,2,3])
// '[object Array]'
js会对变量自动封装对象,尽可能让引擎决定什么时候封装对象,书写代码的时候尽量不要手动封装对象
new Boolean(false) => true
拆封
如果想要得到封装对象中的基本类型值,可以使用valueOf()
函数
在需要用到封装对象中的基本类型值的地方会发生隐式拆封
var a = new String("abc")
var b = a + ""
typeof a // "object"
typeof b // "string"
原生函数作为构造函数
Array()
当只有一个数字参数的时候,该参数会作为数组的预设长度,而非作为数组的一个元素
我们将包含至少一个空单元的数组称为稀疏数组
有空单元的数组在使用map的时候会无从遍历而返回undefined,但是join不会,因为它假定数组不为空,然后使用length进行遍历
我们可以通过下述方式创建包含undefined单元(而非空单元)的数组
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!