# 原始数据类型
原始数据类型有六种:Undefined、Null、Boolean、Number、String 和 Symbol。
# Undefined
这个类型值有一个值 undefined 。
使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了undefined值。
let a
var b
console.log(a) // undefined
console.log(b) // undefined
注意:使用 const 声明变量如果没有赋初始值会报错。
const a // Uncaught SyntaxError: Missing initializer in const declaration
对未声明或未初始化的变量调用 typeof 的时候,返回都是 undefined。
var a
console.log(typeof a) // undefined
console.log(typeof b) // undefined
console.log(a) // undefined
console.log(b) // Uncaught ReferenceError: b is not defined
# Null
这个类型只有一个值 null 。
用等于操作符(==)比较null和undefined始终返回true。
null == undefined // true
用 === 操作符比较 null 和 undefined 返回false。
null === undefined // false
# Boolean
这个类型有两个值 true 和 false 。
调用 Boolean 函数可以将其他值转换为布尔类型。具体转换规则如下:
| 数据类型 | 转换为true的值 | 转换为false的值 |
|---|---|---|
| Boolean | true | false |
| String | 非空字符串 | ""(空字符串) |
| Number | 非零数值(包括无穷值) | 0、NaN(参见后面的相关内容) |
| Object | 任意对象 | null |
| Undefined | N/A(不存在) | undefined |
# Number
十进制这里我们不做特殊说明,这里我们简单列举下八进制和十六进制在 JS 中的表示方法。
let octalNum1 = 070; // 八进制的56
let octalNum2 = 079; // 无效的八进制值,当成79处理
let octalNum3 = 08; // 无效的八进制值,当成8处理
TIP
ECMAScript 2015或ES6中的八进制值通过前缀0o来表示;严格模式下,前缀0会被视为语法错误,如果要表示八进制值,应该使用前缀0o。——译者注
let hexNum1 = 0xA; // 十六进制10
let hexNum2 = 0x1f; // 十六进制31
0.1加0.2得到的不是0.3,而是0.300 000 000 000 000 04。
TIP
之所以存在这种舍入错误,是因为使用了IEEE 754数值,这种错误并非ECMAScript所独有。其他使用相同格式的语言也有这个问题。
ECMAScript可以表示的最小数值保存在Number.MIN_VALUE中,这个值在多数浏览器中是5e-324;可以表示的最大数值保存在Number.MAX_VALUE中,这个值在多数浏览器中是1.797 693 134 862 315 7e+308。
任何无法表示的负数以-Infinity(负无穷大)表示,任何无法表示的正数以Infinity(正无穷大)表示。
isFinite()函数可以用来确定某个值是不是有限大。
console.log(0/0); // NaN
console.log(-0/+0); // NaN
// 分子是非0值,分母是有符号0或无符号0,则会返回Infinity或-Infinity
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
NaN不等于包括NaN在内的任何值。
console.log(NaN == NaN); // false
isNaN() 可以是任意数据类型,然后判断这个参数是否“不是数值”。把一个值传给isNaN()后,该函数会尝试把它转换为数值。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10是数值
console.log(isNaN("10")); // false,可以转换为数值10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值1
# String
ECMAScript中的字符串是不可变的,要修改的话,只能销毁重新创建。
我们可以使用 toString() 方法和 String() 构造函数,将其他类型转换为字符串类型。注意!null 和 undefined 没有 toString() 方法,不能调用。toString() 可以传入一个底数参数,来指定以什么为底数输出字符。
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
String()函数遵循如下规则。
- 如果值有toString()方法,则调用该方法(不传参数)并返回结果。
- 如果值是null,返回"null"。
- 如果值是undefined,返回"undefined"。
# Symbol
Symbol(符号)是ECMAScript 6新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
let sym = Symbol();
console.log(typeof sym); // symbol
这块使用比较少,有需要的可以去 MDN 上查询。
# 对象类型
ECMAScript中的对象其实就是一组数据和功能的集合。
# 创建对象的方式
第一种,使用字面量的方式
var p = {name: 'f'}
第二种,使用构造函数
var p1 = new Object({name: 'f'})
function P() {
this.name = 'f'
}
var p2 = new P()
第三种,使用Object.create,Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
var p1 = {name: 'f'}
var p2 = Object.create(p1)
console.log(p2.__proto__ === p1) // true
上面列举了三种创建对象的方法。这里重点介绍下通过 new 这种方式创建对象。
const num = new Number(1) // Number {1}
const str = new String('hello') // String {"hello"}
const bool = new Boolean(true) // Boolean {true}
// 构造函数 构造函数也是函数,一个函数通过 new 调用,就可以被称为构造函数。
function Person(name, age) {
this.name = name;
this.age = age;
}
const person = new Person('f', 18) // Person {name: "f", age: 18}
# new关键字
上面展示了通过 new 方法创建的几个实例对象,你是不是会好奇 new 是干嘛的?它做了什么?下面我们来探究下,new 实际做了如下操作:
- 一个新对象被创建,它继承自构造函数的原型对象。
- 构造函数被执行,并传入相应的参数。同时this会被指向这个新对象。
- 如果构造函数返回了一个对象,那么这个对象会取代new出来的结果。如果构造函数没有返回对象,那么new出来的结果为第一步创建的对象。
模拟new运算符
function new1(func) {
// 创建一个对象,绑定原型
const o = Object.create(func.prototype)
// 绑定this
const res = func.call(this)
// 如果构造函数返回了一个对象,那么这个对象会取代new出来的结果。如果构造函数没有返回对象,那么new出来的结果为第一步创建的对象。
return typeof res === 'object' ? res : o
}
验证我们写的 new 方法
function new1(func) {
const o = Object.create(func.prototype)
const res = func.call(this)
return typeof res === 'object' ? res : o
}
function Fn() {}
const fn = new1(Fn)
console.log(fn instanceof Fn) // true
console.log(fn instanceof Object) // true
console.log(fn.__proto__.constructor === Fn) // true
这里我们列举几个使用对象时有可能会使用到的方法和属性:
- constructor:用于创建当前对象的函数
- hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属性
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。
# typeof
我们可以通过 typeof 来检测数据类型。
typeof undefined // undefined
typeof null // object
typeof 1 // number
typeof true // boolean
typeof 'hello' // string
typeof Symbol() // symbol
typeof {} // object
typeof function(){} // function
typeof null返回的是"object"。这是因为特殊值null被认为是一个对空对象的引用。
函数在 ECMAScript 中被认为是对象,并不代表一种数据类型。可是,函数也有自己特殊的属性。为此,就有必要通过typeof操作符来区分函数和其他对象。
← 严格模式/非严格模式 类型转换 →