数据类型&转换

很重要的内容,总结一篇

参考链接

数据类型概述
数据类型的转换

数据类型

简介

JavaScript 的数据类型,共有六种。(ES6 又新增了第七种 Symbol 类型的值)

  • 数值(number):整数和小数(比如1和3.14)。
  • 字符串(string):文本(比如Hello World)。
  • 布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)。
  • undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
  • null:表示空值,即此处的值为空。
  • 对象(object):各种值组成的集合。
    • 狭义的对象(object)
    • 数组(array)
    • 函数(function)

JS确定数据类型的方法

  • typeof运算符
  • instanceof运算符
  • Object.prototype.toString方法

typeof运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
typeof运算符可以返回一个值的数据类型。

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"

function f() {}
typeof f
// "function"

typeof undefined
// "undefined"

v
// ReferenceError: v is not defined
利用这一点,typeof可以用来检查一个没有声明的变量,而不报错。
// 这里可以多思考思考。。。🤔
typeof v
// "undefined"

----------实际编程中
// 错误的写法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正确的写法
if (typeof v === "undefined") {🤔🤔🤔
// ...
}

typeof window // "object"
typeof {} // "object"
typeof [] // "object"

可以用instanceof来区分数组和对象
var o = {};
var a = [];
o instanceof Array // false
a instanceof Array // true

1
typeof null // "object"

null的类型是object,这是由于历史原因造成的。1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑null,只把它当作object的一种特殊值。后来null独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。

栈内存和堆内存

参考链接JS栈内存与堆内存
JS中,所有的变量都是保存在栈内存中的。

  • 基本数据类型 - 直接保存在栈内存
  • 引用数据类型 - 堆内存 - 变量保存了对象的内存地址

特点:

  • 栈内存
  • 变量已知大小或有范围上限
  • 存放基本类型
  • 在当前执行环境结束时销毁💥
  • 堆内存
  • 保存无序且唯一的引用类型值
  • 可以用栈中的键名获取
  • 存储大小一般未知 ❔
  • 不随执行环境结束而销毁💥 - 只有当所有引用它的变量不存在时才被垃圾回收机制回收

null,undefined

null

null 专门用来定义一个空对象(例如:let a = null)。
如果想定义一个变量用来保存引用类型,
但是还没想好放什么内容,这个时候,可以在初始化时将其设置为 null。

  • Null 类型的值只有一个,就是 null。比如 let a = null
  • 使用 typeof 检查一个 null 值时,会返回 object。

undefined

  • Undefined 类型的值只有一个,就是 undefind。比如 let a = undefined
  • 使用 typeof 检查一个 undefined 值时,会返回 undefined。

以下是出现undefined的实际情况
总结:

  • 定义未赋值 / 未定义
  • 调用没有返回 / 未传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
### case1:变量已声明,未赋值时
```js
let name;
console.log(name); // 打印结果:undefined
console.log(typeof name); // 打印结果:undefined

### case2:变量未声明(未定义)时
```js
console.log(typeof a); // undefined
console.log(a); // 打印结果:Uncaught ReferenceError: a is not defined

### case3:函数无返回值时
```js
function foo() {}
console.log(foo()); // 打印结果:undefined

### case4:调用函数时,未传参
function foo(name) {
console.log(name);
}
foo(); // 调用函数时,未传参。执行函数后的打印结果:undefined

实际开发案例

1
2
3
4
5
6
7
8
9
如果调用函数时没有传参,我们可以给形参设置一个默认值:
function foo(name) {
name = name || 'qianguyihao';
}
foo();

es6
function foo(name = 'qianguyihao') {}
foo();

null和undefined的区别

比较 / 运算

  • null == undefined 的结果为 true
  • null === undefined 的结果是 false
  • 10 + null 结果为 10。
  • 10 + undefined 结果为 NaN。
  • 任何数据类型和 undefined 运算都是 NaN;
  • 任何值和 null 运算,null 可看做 0 运算。

数值

在JS中所有的数值都是 Number 类型,包括整数和浮点数(小数)。

1
2
3
4
5
6
7
8
9
var a = 100; // 定义一个变量 a,并且赋值整数100
console.log(typeof a); // 输出变量 a 的类型

var b = 12.3; // 定义一个变量 b,并且赋值浮点数 12.3
console.log(typeof a);

上方代码的输出结果为:
number
number

数值范围

  • 最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
  • 最小值:Number.MIN_VALUE,这个值为: 5e-324
  • 如果使用 Number 表示的变量超过了最大值,则会返回Infinity。
  • 无穷大(正无穷):Infinity
  • 无穷小(负无穷):-Infinity
  • 注意:typeof Infinity的返回结果是number。

NaN

NaN:是一个特殊的数字,表示Not a Number,非数值。比如:

1
2
3
4
5
6
7
8
9
  console.log("abc" / 18);  //结果是NaN
//按理说,字符串相乘是没有结果的,但如果你非要让JS去算,它就一定会给你一个结果。结果是NaN
console.log("abc" * "abcd");

注意:`typeof NaN`的返回结果是 number。

Undefined和任何数值**计算**的结果为 NaN

NaN 与**任何值**都不相等,包括 NaN 本身。❌

隐式转换

-*/%这几个符号会自动进行隐式转换。

1
2
3
4
var a = "4" + 3 - 6;
console.log(a);

37

浮点数运算

1
2
3
4
5
6
7
8
9
千万不要使用JS进行对精确度要求比较高的运算。
var a = 0.1 + 0.2;
console.log(a); //打印结果:0.30000000000000004

这是因为,计算机在做运算时,所有的运算都要转换成二进制去计算。
然而,有些数字转换成二进制之后,无法精确表示。
比如说,0.10.2转换成二进制之后,是无穷的,
因此存在浮点数的计算不精确的问题。

布尔值

布尔型有两个值:true 和 false。
主要用来做逻辑判断: true 表示真,false 表示假。

以下运算会返回布尔值

  • 两元逻辑运算符: && (And),|| (Or)
  • 前置逻辑运算符: ! (Not)
  • 相等运算符:===,!==,==,!=
  • 比较运算符:>,>=,<,<=

以下值会被转化为false 🌪
UNN0F空

  • undefined
  • null
  • false
  • 0
  • NaN
  • “”或’’(空字符串)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if ('') {
console.log('true');
}
// 没有任何输出

注意,空数组([])和空对象({})对应的布尔值,都是true。
if ([]) {
console.log('true');
}
// true

if ({}) {
console.log('true');
}
// true

字符串

单引号&双引号

  • 单引号和双引号都可以表示字符串类型
  • 但是不能混用 - 一个单一个双
  • 如果嵌套使用,一对单外面一对双

转义字符
表示一些特殊符号时,可用\进行转义

  • \" 表示 " 双引号
  • \' 表示 ' 单引号
  • \\ 表示\
  • \r 表示回车
  • \n 表示换行。n 的意思是 newline。
  • \t 表示缩进。t 的意思是 tab。
  • \b 表示空格。b 的意思是 blank。

字符串的长度

  • 一个中文算一个字符,一个英文算一个字符
  • 一个标点符号(包括中文标点、英文标点)算一个字符
  • 一个空格算一个字符

字符串拼接

1
字符串 + 任意数据类型 = 拼接之后的新字符串;

字符串不可变性

字符串里面的值不可被改变。虽然看上去可以改变内容
,但其实是地址变了,内存中新开辟了一个内存空间。

字符串重复赋值、字符串拼接都会引用新的地址空间来存放,增加内存消耗。

1
2
3
4
5
var str = 'hello';
str = 'qianguyihao';

比如上面的代码,当重新给变量 str 赋值时,常量`hello`不会被修改,
依然保存在内存中;str 会改为指向`qianguyihao`

模板字符串

ES6中引入了模板字符串,省去了字符串拼接的烦恼。🤗🤗🤗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var name = 'qianguyihao';
var age = '26';
console.log(`我是${name},age:${age}`); //ES6 写法。注意语法格式
`${变量名}`

const a = 5;
const b = 10;
// 下面这行代码,故意做了换行。
console.log(`this is ${a + b} and
not ${2 * a + b}.`);

this is 15 and
not 20.

// 模板中可以调用函数
function getName() {
return 'qianguyihao';
}
console.log(`www.${getName()}.com`); // 打印结果:www.qianguyihao.com

// 模板字符串支持嵌套使用
// 创建 ul 标签 - 给innerHTML
// 可以封装函数使用
const nameList = ['千古壹号', '许嵩', '解忧少帅'];
function myTemplate() {
// join('') 的意思是,把数组里的内容合并成一个字符串
return `<ul>
${nameList
.map((item) => `<li>${item}</li>`)
.join('')}
</ul>`;
}
document.body.innerHTML = myTemplate();

对象

对象概念

在 JavaScript 中,对象是一组无序的相关属性和方法的集合。

对象的作用是:封装信息。比如Student类里可以封装学生的姓名、年龄、成绩等。

对象具有特征(属性)和行为(方法)。

1
2
3
4
5
6
var person = {};

person.name = '王二';
person.age = 35;
person.sex = '男';
person.height = '180';

由此可见,对象里面的属性均是键值对: - 遍历 for in

  • 键:相当于属性名。
  • 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)。
  • 补充1:对象的属性值可以是任何的数据类型,也可以是个函数:(也称之为方法)
  • 补充2:对象中的属性值,也可以是一个对象
1
2
3
4
5
6
7
8
9
var obj = new Object();
obj.sayName = function () {
console.log('smyhvae');
};

console.log(obj.sayName); //没加括号,就是获取方法
console.log('-----------');
console.log(obj.sayName()); //加了括号,就是调用方法。即:执行函数内容,并执行函数体的内容

对象和数据类型的关系

  • 只要不是那五种基本数据类型,就全都是对象。
  • 基本数据类型的值直接保存在栈内存中,值与值之间是独立存在,修改一个变量不会影响其他的变量。
  • 如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj1 = new Object();
obj1.name = "孙悟空";

var obj2 = obj1; // 将 obj1 的地址赋值给 obj2。从此, obj1 和 obj2 指向了同一个堆内存空间

//修改obj2的name属性
obj2.name = "猪八戒";

//obj1 的 name 属性也会被修改。


//把引用类型 A 的值赋值给 B,让A和B相互不受影响的话,可以通过 Object.assign() 来复制对象。
var obj1 = {name: '孙悟空'};
// 复制对象:把 obj1 赋值给 obj3。两者之间互不影响
var obj3 = Object.assign({}, obj1);

对象的分类

  1. 内置对象
    • 比如:Object、Math、Date、String、Array、Number、Boolean、Function等。
  2. 宿主对象
    • 比如 BOM DOM。比如consoledocument
  3. 自定义对象
    • 通过 new 关键字创建出来的对象实例,都是属于对象类型,比如Object、Array、Date等。

对象内容挺多的,再写一篇!!!🐝🐝🐝

函数

数组

数据类型转换

通常有三种形式的类型转换:

  • 转换为字符串类型
  • 转换为数字型
  • 转换为布尔型

typeof()表示“获取变量的数据类型

typeof 的代码写法 返回结果
typeof 数字 number
typeof 字符串 string
typeof 布尔型 boolean
typeof 对象 object
typeof 方法 function
typeof null object
typeof undefined undefined
这里要用instance区分
1
2
3
4
5
console.log(typeof []); // 空数组的打印结果:object
console.log(typeof {}); // 空对象的打印结果:object

console.log([] instanceof Array); // 打印结果:true
console.log({} instanceof Array); // 打印结果:false

显式转换

  • toString()
  • String()
  • Number()
  • parseInt(string)
  • parseFloat(string)
  • Boolean()

其他类型 ->String

方法一(隐式类型转换):字符串拼接
格式:变量+”” 或者 变量+”abc”

方法二:调用 toString()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
变量.toString()

【重要】该方法**不会影响到原变量**,它会将转换的结果返回。
当然我们还可以直接写成`a = a.toString()`,这样的话,就是直接修改原变量。

注意:nullundefined 这两个值没有 toString()方法
如果调用,会报错。

var a = 255;
//对于Number调用toString()时可以在方法中传递一个整数作为参数
//此时它将会把数字转换为指定的进制,如果不指定则默认转换为10进制
a = a.toString(2); // 转换为二进制

方法三(强制转换):使用 String()函数

1
2
3
4
5
6
7
String(变量)

- 对于 NumberBoolean 而言,本质上就是调用 toString()方法。

- 但是对于 nullundefined,则不会调用 toString()方法。它会将 null 直接转换为 "null"
- 将 undefined 直接转换为 "undefined"

其他类型 -> Number

使用 Number() 函数

情况一:字符串 –> 数字

  • 1.如果字符串中是纯数字,则直接将其转换为数字。
  • 2.如果字符串是一个空串或者是一个全是空格的字符串,则转换为 0。
  • 3.只要字符串中包含了其他非数字 的内容(小数点按数字来算),则转换为 NaN。

情况二:布尔 –> 数字

  • true 转成 1
  • false 转成 0

情况三:null –> 数字

  • 结果为:0

情况四:undefined –> 数字

  • 结果为:NaN

使用 parseInt()函数:字符串 -> 整数

情况一:字符串 –> 数字

  • 1.只保留字符串最开头的数字,后面的中文自动消失。
  • 2.如果字符串不是以数字开头,则转换为 NaN。
  • 3.如果字符串是一个空串或者是一个全是空格的字符串,转换时会报错

情况二:Boolean –> 数字

  • 结果为:NaN

情况三:Null –> 数字

  • 结果为:NaN

情况四:Undefined –> 数字

  • 结果为:NaN

Number()🌹 函数和 parseInt()🐠 函数的区别:

就拿Number(true)parseInt(true)/parseFloat(true)来举例,二者在使用时,是有区别的:

  • Number(true) :千方百计地想转换为数字。🌹🌹🌹
  • parseInt(true)/parseFloat(true) :先转为字符串,再提取出最前面的数字部分;🐠没提取出来,那就返回 NaN。

parseInt() 函数特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
(1)**只保留字符串最开头的数字**,后面的中文自动消失。例如:
console.log(parseInt("2017写了6篇文章")); //打印结果:2017
console.log(parseInt("2017.01写了6篇文章")); //打印结果仍是:2017 (说明只会取整数)
console.log(parseInt("aaa2017.01写了6篇文章")); //打印结果:NaN (因为不是以数字开头)

(2)如果对**非 String**使用 parseInt()或 parseFloat(),它会**先将其转换为 String** 然后再操作。【重要】
var a = 168.23;
console.log(parseInt(a)); //打印结果:168 (因为是先将 a 转为字符串"168.23",然后然后再操作)

var b = true;🐠🐠🐠
console.log(parseInt(b)); //打印结果:NaN (因为是先将 b 转为字符串"true",然后然后再操作)

var c = null;🐠🐠🐠
console.log(parseInt(c)); //打印结果:NaN (因为是先将 c 转为字符串"null",然后然后再操作)

var d = undefined;
console.log(parseInt(d)); //打印结果:NaN (因为是先将 d 转为字符串"undefined",然后然后再操作)

(3)自动带有截断小数的功能:**取整,不四舍五入🐠🐠🐠**。

var a = parseInt(5.8) + parseInt(4.7);
console.log(a); // 9

var a = parseInt(5.8 + 4.7);
console.log(a); // 10

(4)带两个参数时,表示在转换时,包含了进制转换。

var a = '110';
var num = parseInt(a, 16); // 【重要】将 a 当成 十六进制 来看待,转换成 十进制 的 num
console.log(num); // 272
无论 parseInt() 里面的进制参数是多少,最终的转换结果是十进制。

var a = '5';
var num = parseInt(a, 2); // 将 a 当成 二进制 来看待,转换成 十进制 的 num
console.log(num); // 打印结果:NaN。因为 二进制中没有 5 这个数,转换失败。

parseFloat()函数:字符串 –> 浮点数(小数)

parseFloat()和 parseInt()的作用类似,不同的是,parseFloat()可以获得有效的小数部分。

1
2
var a = '123.456.789px';
console.log(parseFloat(a)); // 打印结果:123.456🐠

其他类型 -> Boolean

  • 情况一:数字 –> 布尔。除了 0 和 NaN,其余的都是 true。也就是说,Boolean(NaN)的结果是 false。
  • 情况二:字符串 —> 布尔。除了空串,其余的都是 true。全是空格的字符串,转换结果也是 true。字符串'0'的转换结果也是 true。
  • 情况三:null 和 undefined 都会转换为 false。
  • 情况四:引用数据类型会转换为 true。注意,空数组[]和空对象{}转换结果也是 true,这一点,很多人都不知道。

总结:其他类型转为Boolean为false的情况🐸🐸🐸

  • 0
  • NaN
  • ‘’
  • ‘全是空格’
  • null,undefined

Boolean隐式转换

1
2
3
4
5
6
7
8
当**非 Boolean 类型的数值**和 Boolean类型的数值做**比较**时
会先把前者进行隐式转换为 Boolean类型,
const a = 1;

console.log(a == true); // 打印结果:true
console.log(typeof a); // 打印结果:number。可见,上面一行代码里,a 做了隐式类型转换,但是 a 的数据类型并没有发生变化,仍然是 Number 类型

console.log(0 == true); // 打印结果:false

Boolean显式转换
方法1:使用 !!可以显式转换为 Boolean 类型。比如 !!3的结果是true。
方法2:使用 Boolean()函数可以显式转换为 Boolean 类型。

Boolean的实际案例

1
2
3
4
5
6
7
8
9
10
11
12
13
const result1 = '';
const result2 = {a:'data1', b: 'data2'};

if (result1) {
console.log('因为 result1的内容为空,所以代码进不了这里');
}

if (result2 && result2.a) {
// 接口返回了 result2,且 result2.a 里面有值,前端才做进一步的事情
console.log('代码能进来,前端继续在这里干活儿');
}

> 这里再次强调一下,空数组`[]`和空对象`{}`转换为 Boolean 值时,转换结果为 true。

隐式转换

  • isNaN ()
  • 自增/自减运算符:++—-
  • 正号/负号:+a-a
  • 加号:+
  • 运算符:-*/%

isNaN()

任何不能被转换为数值的参数,都会让这个函数返回 true

执行过程

  • (1)先调用Number(参数)🌹🌹🌹函数;
  • (2)然后将Number(参数)🌹🌹🌹的返回结果和NaN进行比较。
1
2
3
4
5
6
7
8
9
console.log(isNaN('123')); // 返回结果:false。

console.log(isNaN('abc')); // 返回结果:true。因为 Number('abc') 的返回结果是 NaN

console.log(isNaN(null)); // 返回结果:false

console.log(isNaN(undefined)); // 返回结果:true

console.log(isNaN(NaN)); // 返回结果:true

++ –

被++ 或 – 后就转换成 Number类型了

1
2
3
4
5
6
7
8
9
10
11
12

var a = "666";
a++;

console.log(typeof a); // 打印结果: **number**
console.log(a); // 打印结果:667


var a = 'abc';
a++;
console.log(typeof a); // 打印结果:**number**
console.log(a); // 打印结果:NaN。因为 Number('abc')的结果为 NaN,再自增后,结果依然是 NaN

正号/负号:+a-a

1
2
3
4
5
6
7
8
var a = '666';
var b = +a;

console.log(typeof a); // 打印结果:string。说明 a 的数据类型保持不变。
console.log(a); // 打印结果:666

console.log(typeof b); // 打印结果:number。说明 b 的数据类型发生了变化。
console.log(b); // 打印结果:666

加号 +

情况一:字符串 + 数字

  • 当加号的两边,只要有一个是字符串的时候,就会调用 String() 函数将数字转为字符串,
  • 然后再计算。导致最终的运算结果是字符串。

情况二:Boolean + 数字

  • Boolean 型和数字型相加时, true 按 1 来算 ,false 按 0 来算。
  • 这里其实是先调 Number() 函数,将 Boolean 类型转换为 Number类型,然后再和 数字相加。

情况三: null + 数字

  • 等价于:0 + 数字

情况四: undefined + 数字

  • 计算结果:NaN
1
2
3
4
5
6
7
8
9
10
11
12
 result1 = true + 1;  // 2 = 1+ 1 --------

result2 = true + false; // 1 = 1+ 0 -----------

result3 = 1 + null; // 1 = 1+ 0

result4 = 100 - '1' // 99

result1 = 1 + 2 + '3' // 33 ------------

result2 = '1' + 2 + 3; // 123

隐式转换-特殊

未解
逻辑运算符:&&|| 。非布尔值进行与或运算时,会先将其转换为布尔值,
然后再运算,但运算结果是原值

关系运算符:<> <= >=等。关系运算符,得到的运算结果都是布尔值:
要么是true,要么是false。