类型和语法

类型

内置类型

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

字符串

字符串和数组很相似,都拥有indexOfconcat等方法,但是实际上并不相同

字符串值不可变,成员函数会返回一个新的字符串

a = ['f', 'o' ,'o']
b = 'foo'
a[1] = 'O'
b[1] = 'O'

a // ['f', 'O', 'o']
b // foo

字符串可以借用很多数组的方法,譬如joinmap,不过对于字符串反转来讲,由于字符串不可变所以不可以直接用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来获得undefinedvoid ___都会返回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单元(而非空单元)的数组



语言   js      js 基础

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!