数据类型

原始值

不可改变, 存储在 stack(栈):先进的后出来。

值类型:

  1. Number — 数字
  2. Boolean — 布尔
  3. String — 字符串
  4. undefined — 未定义(未被赋值的变量值输出时会有这个结果)
  5. null — 空(可以用来占位)

引用值

存储在 heap(堆):怎么进的怎么出。

值类型:

  1. Array — 数组
  2. Object — 对象
  3. Function — 函数
  4. RegExp — 正则
  5. Date — 日期

区别

原始值和引用值唯一的不同是赋值形式不同。

原始值以值的拷贝方式赋值,原值是不可变的。操作都在副本上。引用值以引用的拷贝方式赋值,原值是可变的。引用的是地址,操作还是在原来的地方,除非换一个地址(赋新值)。

原始值

一旦赋值,不可更改。无论是原值增删,还是新的赋值,都会直接存放到新的地方,原值不动。在操作上,表现为原始值和对应栈名复制一份到新的地方,同时之前的对应栈名初始化,值不动,增删和新赋值都在副本上进行。如:

  • 在栈内存中声明一个叫 num 的房间,放入值 1
  • 在栈内存中声明一个叫 num1 的房间,拷贝 num 的值 1 放入 num1
  • 将 num 及其值 1 拷贝到一个新的房间,然后修改值为 2,原来的房间名初始化为 1005,原值 1 依然留在该房间,不会发生变化
1
2
3
4
5
var num = 1,
num1 = num;
num = 2;

console.log(num1); // 1

引用值

赋值之后,如果是在原值上增删,会直接修改原值。如果是新的赋值,就会直接存放到新的地方,原值不动。

原值增删:

  • 在栈内存中声明一个叫 arr 的房间,在堆内存中一个房间里放入值 [1, 2],然后 arr 房间内放入这个值的==堆内存地址==heap1001
  • 在栈内存中声明一个叫 arr1 的房间,然后直接拷贝 arr 房间内存放的地址heap1001,获得 arr 的值
  • 此时 arr 与 arr1 指向同一个值的地址heap1001
  • arr 增加新值 3,直接在heap1001存放的值里增加,变为 [1, 2, 3]
  • 此时 arr 与 arr1 共同指向的值变为 [1, 2, 3]
1
2
3
4
5
var arr = [1, 2],
arr1 = arr;
arr.push(3);

document.write(arr1); // [1, 2, 3]

赋新值:

  • 在栈内存中声明一个叫 arr 的房间,在堆内存中一个房间里放入值 [1, 2],然后 arr 房间内放入堆内存地址heap1001
  • 在栈内存中声明一个叫 arr1 的房间,然后直接拷贝 arr 房间内存放的地址,获得 arr 的值
  • 此时 arr 与 arr1 指向同一个值的地址heap1001
  • arr 赋新值,在堆内存中另一个房间里放入新值 [1, 2, 3],然后 arr 房间内删除原来的地址heap1001,放入这个新值的堆内存地址heap1002
  • 此时 arr 指向的值为 [1, 2, 3],arr1 指向的值为 [1, 2]
1
2
3
4
var arr = [1,2],
arr1 = arr;
arr = [1,2,3];
document.write(arr1); // [1, 2]

typeof 操作符

作用:区分数据类型(六种)

  • number
  • string
  • boolean
  • undefined
  • object(泛指引用值,数组 array 和 null 都属于此类)
  • function

原始值:number/string/boolean/undefined/null

引用值:array/object/function

null 最初是作为代替空对象的形式出现(给对象占位),所以它的数据类型是 object

写法:typeof() 或者 typeof 内容

1
2
3
4
5
6
7
8
var num = function() {};
console.log(typeof(num)); // function

var mul = null;
console.log(typeof mul); // object

var arr = [];
console.log(typeof(arr)); // objcet

任何变量未经声明就使用的话,会直接报错。
如果放入 typeof 操作符中,不会报错,会直接返回undefined
这个返回值undefined的类型是字符串。

1
console.log(typeof(a),typeof(typeof(a))); // undefined string

任何情况下,返回的六种类型的值都是字符串类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var str = 'abc';
console.log(typeof(str), typeof(typeof(str))); // string string

var bool = true;
console.log(typeof(bool), typeof(typeof(bool))); // boolean string

var num = 7;
console.log(typeof(num), typeof(typeof(num))); // number string

var obj = {};
console.log(typeof obj, typeof(typeof obj)); // object string

var fn = function() {};
console.log(typeof fn, typeof(typeof fn)); // function string

console.log(typeof undefined, typeof(typeof undefined)); // undefined string

类型转换

显示

Number( ):将括号里的内容转换成数字/数。

  • undefined、字符串(除了字符串类型的数字)、NaN-> NaN
  • true -> 1
  • false、""、null -> 0
  • "123" -> 123(字符串类型的数字直接转换类型,数值不变)
1
2
3
4
5
6
7
8
9
10
11
var num = Number(true); // 布尔类型

console.log(typeof(num),num); // number 1

var num = Number('true'); // 字符串类型

console.log(typeof(num),num); // number NaN

console.log(Number('123abc')); // NaN

console.log(Number(null)); // 0

parseInt (string, radix):(integer:整数)

  • 第一个作用:string 参数,转换成整值(如果前面是数字,从数字位开始看,直到非数字位截止,返回数字位)
  • 第二个作用:radix 进制,以此进制为基底,将值转换为十进制,取值:2~36,选填。划重点:你填的多少,进制就是多少。从你填的转为十进制。目标进制(你填写的进制) <==> 十进制
  • 常见转换:
    • "123.7"-> 123
    • "123abc" -> 123(首位是数字的话,从数字位开始看,在非数字位截断)
    • 其他 -> NaN
1
2
3
4
5
6
7
8
9
10
11
12
13
var num = parseInt(true);
console.log(typeof(num) + ': ' + num); // number: NaN

console.log(parseInt('123.9')); // 123

console.log(parseInt('123abc')); // 123

var num = parseInt('abc123');
console.log(typeof(num) + ': ' + num); // number: NaN

var num = parseInt('a',16); // a 目前为十六进制数,要转化为十进制数

console.log(typeof(num) + ': ' + num); // number: 10

parseFloat(string):类似 parseInt 方法,转换成浮点数(正常的小数)。

1
2
3
4
5
6
7
8
var num = parseFloat('123.45');
console.log(typeof(num) + ': ' + num); // number: 123.45

var num = parseFloat('123.45abc');
console.log(typeof(num) + ': ' + num); // number: 123.45

var num = parseFloat('abc123.45');
console.log(typeof(num) + ': ' + num); // number : NaN

参数.toString(radix):将参数转换成字符串

  • radix 进制,以十进制为基底,转换成填写的进制,选填。
    十进制<==>目标进制(你填写的进制)划重点:你填的多少,就是想要多少。从十进制转为你填的。
  • undefined 和 null 不能用该方法,使用会直接报错(因为它俩没有原型,而其他原始值经过包装类后成为原始值对象,都有原型)
1
2
3
4
5
6
7
8
9
var demo = 123;
var num = demo.toString();

console.log(typeof(num) + ': ' + num); // string: 123

var demo = 10;
var num = demo.toString(16);// 10 目前为十进制数,要转化为十六进制

console.log(typeof(num) + ': ' + num); // string: a

如果直接使用123.toString()是不可以的,会直接报错。因为系统会首先将这个语句识别为浮点型,数学计算的点.优先级最高,所以识别成浮点数,小数点后是字母是肯定报错的。

1
2
3
var num = 123.toString();

console.log(num); // 报错,Uncaught SyntaxError: Invalid or unexpected token

String( ):将括号里的内容转换成字符串

1
2
3
4
5
6
7
var num = String(123);

console.log(typeof(num) + ': ' + num); // string: 123

var num = String(true);

console.log(typeof(num)+': '+num); // string: true

Boolean( ):转换成布尔值

  • undefined / null / NaN / “” / 0 / false -> false
1
2
3
4
5
6
7
8
9
10
11
var num = Boolean('');

console.log(typeof(num) + ': ' + num); // boolean: false

var num = Boolean(0);

console.log(typeof(num) + ': ' + num); // boolean: false

var num = Boolean('0');

console.log(typeof(num) + ': ' + num); // boolean: true

隐式

内部原理:调用显示类型转换。原理:调用 Number( ) 方法转为数字,然后和 NaN 比对。

isNaN() :判断参数是不是 NaN,返回结果为 boolean 类型。

  • 常用转换:NaN / undefined / 字符串(除了字符串类型的数字) -> NaN
1
2
3
4
5
6
7
8
9
10
11
console.log(isNaN(NaN)); // true

console.log(isNaN(123)); // false

console.log(isNaN('123')); // false

console.log(isNaN('aa')); // true

console.log(isNaN(undefined)); // true

console.log(isNaN(null)); // false

++/--+/-(一元正负):转换为 number 类型。

  • 原理:调用 Number( )。
  • 一元正负,只有一边有参数,如”+ a” / “- b”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = 'abc';
a++;
console.log(typeof(a), a);// number NaN

var b = '123';
b++;
console.log(typeof(b), b);// number 124

var c = null;
c--;
console.log(typeof(c), c);// number -1

var d = +'abc';
console.log(typeof(d), d);//number NaN

+ (加号):

  • 若加号两边存在一个字符串,将另一个也转为字符串,转为 string 类型。调用 String 方法。
1
2
var a = 1 +'abc';
console.log(typeof(a), a);// string 1abc
  • 其他情况下(number / undefined / null / boolean),转为 number 类型。调用 Number 方法。
1
2
var a = false + 1;
console.log(typeof(a), a);// number 1

-、*、/、%:转为 number 类型。原理:调用 Number 方法

1
2
3
4
5
6
7
8
var a = '1' * 1;
console.log(typeof(a), a);// number 1

var b = null / 1;
console.log(typeof(b), b);// number 0

var c = 'abc' - 1;
console.log(typeof(c), c);// number NaN

&&、||:过程中转为 boolean 类型进行比较,结果返回表达式的值(值本身是什么类型就返回什么类型)。

!:结果返回 boolean 类型。

1
2
3
4
5
6
7
8
9
10
11
var num = 'abc' && 2; 
console.log(typeof(num), num);// number 2

var num = 'abc' && 'def';
console.log(typeof(num), num);// string def

var num = null && 4;
console.log(typeof(num), num);// object null

var num = !!'a';
console.log(typeof(num), num);// boolean true

<、>、<=、>=

  • 两边都是字符串时,比较 asc 码,返回 boolean 类型。
  • 其他情况下,调用 Number( ),先转换为数字进行比较,结果返回 boolean 类型。
  • undefined 和 null 除外,见特殊情况。

==、!= :若两边均为对象,对比它们的引用是否相同,返回 boolean 类型。其他情况下,调用 Number 方法,两边转为数字进行比较,结果返回 boolean 类型。

1
2
3
4
5
6
7
8
// 引用值,两个不同的地址引用(不同房间):
console.log({} == {}); // false

// 同一个地址引用:
var obj = {};
var obj1 = obj;

console.log(obj == obj1); // true

特殊情况:

  • undefined 和 null 既不大于 0,也不小于 0,更不等于 0。
  • undefined == null
  • NaN !== NaN
1
2
3
4
5
6
7
8
9
10
console.log(undefined > 0); // false
console.log(undefined < 0); // false
console.log(undefined == 0); // false

console.log(null > 0); // false
console.log(null < 0); // false
console.log(null == 0); // false

console.log(undefined == null);// true
console.log(NaN == NaN);// false

例:

1
2
3
4
5
6
7
8
// false == 0, true == 1, 0 > 1 -> false
console.log(false > true); // false

// 先判断 1 > 10 -> false, false == 0, 0 > 0 -> false
console.log(1 > 10 > 0); // false

// 2 > 3 -> false, false == 0, 0 < 1 -> true
console.log(2 > 3 < 1); // true

不发生类型转换:

  • ===
  • !==

常用转换汇总

Boolean():undefined、null、NaN、””、0、false -> false

Number():(千方百计变成数字)

  • undefined / 字符串(除了字符串类型的数字)/ NaN -> NaN
  • true -> 1
  • false / “” / null -> 0
  • “123” -> 123 (字符串类型的数字直接转换类型,数值不变)

parseInt (string, radix):(只要整数,不管其他)

  • “123.7” -> 123
  • “123abc” -> 123(首位是数字的话,从数字位开始看,在非数字位截断)
  • 其他 -> NaN

例 1:关于 parseInt() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
console.log(typeof parseInt('123abc'), parseInt('123abc')); // number 123
console.log(parseInt('123.7')); // 123

console.log(typeof parseInt(undefined), parseInt(undefined)); // number NaN

console.log(parseInt(null)); // NaN

console.log(parseInt(NaN)); // NaN

console.log(parseInt('abc123')); // NaN
console.log(parseInt('')); // NaN

console.log(parseInt(true)); // NaN
console.log(parseInt(false)); // NaN

例 2:

1
2
3
4
5
6
7
8
9
10
var str = false + 1; 
// 0 + 1
console.log(str); // 1

var demo = false == 1;
// 0 !== 1 -> false
console.log(demo); // false

console.log(11 + '11' * 2 == 33);// true
// 11 + 22

例 3:

1
2
3
4
5
6
7
8
9
10
11
12
console.log(typeof(a) && -true + (+undefined) + ''); // 'NaN'
// 左边:typeof(a) -> 'undefined'
// && 优先级低于算术运算符,放在最后处理
// 右边:-true + (+undefined) + '' -> -1 + NaN + '' -> NaN + '' -> 'NaN'
// 'undefined' && 'NaN'
// 一真返二
// 'NaN'

if(typeof(a) && -true + (+undefined) + ''){
console.log('是否能输出');
}
// 条件内返回的是字符串的'NaN',为 true,可以执行

例 4:

1
2
3
!!' ' + !!'' - !!false || console.log('能吗?');
// 左边:true + false - false -> 1 + 0 - 0 = 1
// 1 为真,会直接返回 1,|| 后面的语句不会执行

进制

特点

进制也就是进位计数制,是人为定义的带进位的计数方法。对于任何一种进制—— X 进制,就表示每一位置上的数运算时都是逢 X 进一位。

十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,X 进制就是逢 X 进位。

比如十六进制:1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f。如果 f + 1,那么按照逢十六进一的规则,个位数变为 0,然后向前进一位,十位数变为 1。那么:f + 1 = 10,这里的 10(一零),就代表十进制里的 16。

比如二进制:0, 1。如果 1 + 1,按照逢二进一的规则,个位数变为 0 ,十位数变为 1,1 + 1 = 10,这里的 10(一零),代表十进制里的 2。

转换

十进制 -> X 进制:除。数除以 X,得商,接着用商除 X,直到商为 0,余数倒过来写。
X 进制 -> 十进制:乘。从数的个位开始,依次乘以 X 的 0 次方,1 次方……,最后加起来。

十进制 -> 十六进制

1
2
3
4
5
6
10 进制数:33

33 / 16 = 2 ...... 1
2 / 16 = 0 ...... 2

转换成 16 进制数:21

十六进制 -> 十进制

1
2
3
4
5
16 进制数:21

1 * 16⁰ + 2 * 16¹ = 33

转换成 10 进制数:33

十进制 -> 八进制

1
2
3
4
5
6
10 进制数:19

19 / 8 = 2 ...... 3
2 / 8 = 0 ...... 2

转换成 8 进制数:23

八进制 -> 十进制

1
2
3
4
5
8 进制数:23

3 * 8⁰ + 2 * 8¹ = 19

转换成 10 进制数:19

十进制 -> 二进制

1
2
3
4
5
6
7
8
9
10
10 进制数:46

46 / 2 = 23 ...... 0
23 / 2 = 11 ...... 1
11 / 2 = 5 ...... 1
5 / 2 = 2 ...... 1
2 / 2 = 1 ...... 0
1 / 2 = 0 ...... 1

转换成 2 进制数:101110

二进制 -> 十进制

1
2
3
4
5
2 进制数:101110

0 * 2⁰ + 1 * 2¹ + 1 * 2² + 1 * 2³ + 0 * 2⁴ + 1 * 2⁵ = 46

转换成 10 进制数:46