JS之数据类型

一、变量数据类型

为什么需要数据类型

在计算机中,不同的数据所需占用的存储空间不同,为了充分利用存储空间,于是定义了不同的数据类型。而且,不同的数据类型,寓意也不同。

我们都知道,无论这个变量是字符串类型,还是数字类型,我们都可以直接用 `var` 去定义它。比如:

```javascript
var a = 'hello word';

var b = 123;
```

为什么可以这样做呢?这是因为:JavaScript 是一种「弱类型语言」,或者说是一种「动态语言」,这意味着不需要提前声明变量的类型,在程序运行过程中,类型会自动被确定。

**JS 的变量数据类型,是在程序运行的过程中,根据等号右边的值来确定的**。而且,变量的数据类型是可以变化的。比如说:

```javascript
var name = 'qianguyihao';

name = 123; // 强制将变量 name 修改为 数字类型
```

JS中一共有六种数据类型

- **基本数据类型(值类型)**:String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。

- **引用数据类型(引用类型)**:Object 对象。引用数据类型只有一种

基本和引用数据类型之间的区别**:

- 基本数据类型:参数赋值的时候,传数值。

- 引用数据类型:参数赋值的时候,传地址(修改的同一片内存空间)。

注意:内置对象 Function、Array、Date、RegExp、Error等都是属于 Object 类型。也就是说,除了那五种基本数据类型之外,其他的,都称之为 Object类型。

注意以下两个例子

**基本数据类型举例**:

```javascript
var a = 23;
var b = a;

a++;

console.log(a); // 打印结果:24
console.log(b); // 打印结果:23
```

上面的代码中:a 和 b 都是基本数据类型,让 b 等于 a,然后**改变 a 的值之后,发现 b 的值并没有被改变**。

**引用数据类型举例**:

```javascript
var obj1 = new Object();
obj1.name = 'smyh';

// 让 obj2 等于 obj1
var obj2 = obj1;

// 修改 obj1 的 name 属性
obj1.name = 'vae';

console.log(obj1.name); // 打印结果:vae
console.log(obj2.name); // 打印结果:vae
```

 

从上面的例子中,可以反映出,基本数据类型和引用数据类型是有区别的。

栈内存和堆内存

JS中,所有的**变量**都是保存在**栈内存**中的。

**基本数据类型**:

基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。

**引用数据类型**:

对象是保存到**堆内存**中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间;而**变量保存了对象的内存地址**(对象的引用),保存在栈内存当中。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。

二、基础数据类型

1、String 字符串

字符串型可以是引号中的任意文本,其语法为:双引号 `""` 或者单引号 `''`。

```javascript
var a = "abcde";
var b = "千古壹号";
var c = "123123";
var d = '哈哈哈哈哈';
var e = ""; //空字符串

var f = haha; // 没使用引号,到这里会直接报错。因为会被认为是js代码,但是之前并没有定义 haha。

console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);

```

控制台输出如下:

```
string
string
string
string
string
```

注意:

1、单引号和双引号不能混用。比如下面这样写是不可以的:

```javascript
var str = 'hello"; // 报错:Uncaught SyntaxError: Invalid or unexpected token
```

2、同类引号不能嵌套:双引号里不能再放双引号,单引号里不能再放单引号。

3、单引号里可以嵌套双引号;双引号里可以嵌套单引号。

 

转义字符

在字符串中我们可以使用`\`作为转义字符,当表示一些特殊符号时可以使用`\`进行转义。

- `\"` 表示 `"`

- `\'` 表示 `'`

- `\\` 表示`\`

- `\r` 表示回车

- `\n` 表示换行。n 的意思是 newline。

- `\t` 表示缩进。t 的意思是 tab。

- `\b` 表示空格。b 的意思是 blank。

获取字符串的长度

字符串是由若干个字符组成的,这些字符的数量就是字符串的长度。我们可以通过字符串的 length 属性可以获取整个字符串的长度。

```javascript
var str1 = '张三';
var str2 = '张三和李四';

var str3 = 'qianguyihao';
var str4 = 'qianguyihao, keep moving!';

console.log(str1.length); // 4
console.log(str2.length); // 5
console.log(str3.length); // 11
console.log(str4.length); // 25
```

由此可见,字符串的 length 属性,在判断字符串的长度时,会认为:

- 一个中文算一个字符,一个英文算一个字符

- 一个标点符号(包括中文标点、英文标点)算一个字符

- 一个空格算一个字符

字符串拼接

多个字符串之间可以使用加号 `+` 进行拼接。

**拼接语法**:

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

**拼接规则**:拼接前,会把与字符串相加的这个数据类型转成字符串,然后再拼接成一个新的字符串。

**代码举例**:(字符串与六大数据类型相加)

```javascript
var str1 = '张三' + '永不止步';
var str2 = '张三' + 666;
var str3 = '张三' + true;
var str4 = '张三' + null;
var str5 = '张三' + undefined;

var obj = { name: '张三', age: 28 };
var str6 = '张三' + obj;

console.log(str1);
console.log(str2);
console.log(str3);
console.log(str4);
console.log(str5);
console.log(str6);
```

打印结果:

```
张三永不止步

张三666

张三true

张三null

张三undefined

张三[object Object]
```

2、数值型:Number

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

```javascript
var a = 100; // 定义一个变量 a,并且赋值整数100
console.log(typeof a); // 输出变量 a 的类型

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

上方代码的输出结果为:

```
number

number
```

再次补充:在 JS 中,只要是数,就是 Number 数值型的。无论整浮、浮点数(即小数)、无论大小、无论正负,都是 Number 类型的。

数值范围

由于内存的限制,ECMAScript 并不能保存世界上所有的数值。

- 最大值:`Number.MAX_VALUE`,这个值为: 1.7976931348623157e+308

- 最小值:`Number.MIN_VALUE`,这个值为: 5e-324

如果使用 Number 表示的变量超过了最大值,则会返回Infinity。

- 无穷大(正无穷):Infinity

- 无穷小(负无穷):-Infinity

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


NaN

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

```javascript
console.log("abc" / 18); //结果是NaN

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

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

Undefined和任何数值计算的结果为 NaN。NaN 与任何值都不相等,包括 NaN 本身。

浮点数的运算

在JS中,整数的运算**基本**可以保证精确;但是**小数的运算,可能会得到一个不精确的结果**。所以,千万不要使用JS进行对精确度要求比较高的运算。

如下:

```javascript
var a = 0.1 + 0.2;
console.log(a); //打印结果:0.30000000000000004
```

上方代码中,打印结果并不是0.3,而是0.30000000000000004。

我们知道,所有的运算都要转换成二进制去计算,然而,二进制是无法精确表示1/10的。因此存在小数的计算不精确的问题。

连字符和加号的区别

键盘上的`+`可能是连字符,也可能是数字的加号。如下:

```
console.log("我" + "爱" + "你"); //连字符,把三个独立的汉字,连接在一起了
console.log("我+爱+你"); //原样输出
console.log(1+2+3); //输出6
```

输出:

```
我爱你
我+爱+你
6
```

**总结**:如果加号两边**都是**数值,此时是加。否则,就是连字符(用来连接字符串)。


隐式转换

我们知道,`"2"+1`得到的结果其实是字符串,但是`"2"-1`得到的结果却是数值1,这是因为计算机自动帮我们进行了“**隐式转换**”。

也就是说,`-`、`*`、`/`、`%`这几个符号会自动进行隐式转换。例如:

```javascript
var a = "4" + 3 - 6;
console.log(a);
```

输出结果:

```javascript
37
```

虽然程序可以对`-`、`*`、`/`、`%``这几个符号自动进行“隐式转换”;但作为程序员,我们最好自己完成转换,方便程序的可读性。

 

3、布尔值:Boolean

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

布尔值直接使用就可以了,千万不要加上引号。

代码:

```javascript
var a = true;
console.log(typeof a);
```

控制台输出结果:

```
boolean
```

布尔型和数字型相加时, true 按 1 来算 ,false 按 0 来算。


Null 和 Undefined

null:空值

专门用来表示一个为空的**对象**(例如:`var a = null`)。注意,专门用来表示**空对象**。

- Null类型的值只有一个,就是null。比如 `var a = null`。

- 使用 typeof 检查一个null值时,会返回object。

如果你想定义一个变量,以后打算存储为对象,但是还没想好放什么内容,这个时候,可以给 null。

比如:

```js
var myObj = null;
cosole.log(typeof myObj); // 打印结果:object
```


`undefined`:未定义

**声明**了一个变量,但是没有**赋值**(例如:`var a;`),此时它的值就是 `undefined`。

- Undefined类型的值只有一个,就是undefind。比如

- 使用 type of 检查一个undefined时,会返回undefined。

null和undefined有很大的相似性。看看null == undefined的结果(true)也就更加能说明这点。

但是null === undefined的结果(false)。它们虽然相似,但还是有区别的,其中一个区别是:和数字运算时,10 + null结果为:10;10 + undefined结果为:NaN。

- 任何数据类型和undefined运算都是NaN;

- 任何值和null运算,null可看做0运算。

## 变量值的传递(赋值)

语句:

```
a = b;
```

把b的值赋给a,b不变。

将等号右边的值,赋给左边的变量;等号右边的变量,值不变。

来做几个题目。

举例1:

```js
//a b c
var a = 1; //1
var b = 2; //1 2
var c = 3; //1 2 3
a = b + c; //5 2 3
b = c - a; //5 -2 3
c = a * b; //5 -2 -10
console.log(a);
console.log(b);
console.log(c);
```

输出:

```
5
-2
-10
```

举例2:

```js
//a b c
var a = 1;
var b = 2;
var c = 3; //1 2 3
a = a + b; //3 2 3
b = b + a; //3 5 3
c = c + b; //3 5 8
console.log(a); //3
console.log(b); //5
console.log(c); //8
```

输出:

```
3
5
8
```

举例3:

```js
//a b
var a = "1";
var b = 2; //"1" 2
a = a + b; //"12" 2
b = b + a; //"12" "212"
console.log(a); //输出12
console.log(b); //输出212
```

输出:

```
12
212
```

举例4:

```js
//a b
var a = "1";
var b = 2;
a = b + a; //"21" 2
b = b + a; //"21" "221"
console.log(a); //21
console.log(b) //221
```


效果:

```
21
221
```

举例5:(这个例子比较特殊,字符串减去数字)

```js
var a = "3";
var b = 2;
console.log(a-b);
```


效果:(注意,字符串 - 数值 = 数值)

```
1
```

 三、数据类型的转换

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

- 转换为字符串类型

- 转换为数字型

- 转换为布尔型

1、typeof 运算符

typeof()`表示“**获取变量的数据类型**”,返回的是小写,语法为:(两种写法都可以)

```javascript
// 写法1
typeof 变量;

// 写法2
typeof(变量);
```

typeof 这个运算符的返回结果就是变量的类型。那返回结果的类型是什么呢?是字符串。

备注 1:为啥 `typeof null`的返回值也是 object 呢?因为 null 代表的是**空对象**。

备注 2:`typeof NaN`的返回值是 number,上一篇文章中讲过,NaN 是一个特殊的数字。

console.log(type []); // 空数组的打印结果:object

console.log(type {}); // 空对象的打印结果:object

代码解释:这里的空数组`[]`、空对象`{}` ,为啥他们在使用 typeof 时,返回值也是 `object`呢?因为这里的返回结果`object`指的是**引用数据类型**。空数组、空对象都是**引用数据类型 Object**。

2、变量的类型转换的分类

显示类型转换

- toString()

- String()

- Number()

- parseInt(string)

- parseFloat(string)

- Boolean()

隐式类型转换

- isNaN ()

- 自增/自减运算符:`++`、`—-`

- 正号/负号:`+a`、`-a`

- 加号:`+`

- 运算符:`-`、`*`、`/`

隐式类型转换(特殊)

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

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

 

三、常用类型转换举例

1、字符串

方法一(隐式类型转换):字符串拼接

格式:变量+"" 或者 变量+"abc"

举例:

var a = 123; // Number 类型
console.log(a + ''); // 转换成 String 类型
console.log(a + 'haha'); // 转换成 String 类型

上面的例子中,打印的结果,都是字符串类型的数据。实际上内部是调用的 String() 函数。也就是说,`c = c + ""` 等价于 `c = String(c)`。

方法二:调用 toString()方法

 

变量.toString()

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

注意:null 和 undefined 这两个值没有 toString()方法,所以它们不能用方法二。如果调用,会报错。

另外,Number 类型的变量,在调用 toString()时,可以在方法中传递一个整数作为参数。此时它将会把数字转换为指定的进制,如果不指定则默认转换为 10 进制。例如:

```javascript
var a = 255;

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

console.log(a); // 11111111
console.log(typeof a); // string

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

语法:

```javascript
String(变量)
```

使用 String()函数做强制类型转换时:

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

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

prompt():用户的输入

prompt()就是专门用来弹出能够让用户输入的对话框。重要的是:用户不管输入什么,都当字符串处理。

2、number

使用 Number() 函数

**情况一:字符串 --> 数字**

- 1.如果字符串中是纯数字,则直接将其转换为数字。

- 2.只要字符串中包含了非数字的内容(`小数点`按数字来算),则转换为 NaN。

- 3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为 0。

**情况二:布尔 --> 数字**

- true 转成 1

- false 转成 0

**情况三:null --> 数字**

- 结果为:0

**情况四:undefined --> 数字**

- 结果为:NaN

补充:怎么理解这里的 **NaN** 呢?可以这样理解,使用 Number() 函数之后,**如果无法转换为数字,就会转换为 NaN**。

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

**parseInt()的作用是将字符串中的有效的整数内容转为数字**。parse 表示“转换”,Int 表示“整数”(注意`Int`的拼写)。例如:

parseInt("5");

得到的结果是数字 5。

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)**只保留字符串最开头的数字**,后面的中文自动消失。例如:

```javascript
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** 然后再操作。【重要】

比如:

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

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

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

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

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

例 1:

```javascript
var a = parseInt(5.8) + parseInt(4.7);
console.log(a);
```

打印结果:

```
9
```

例 2:

```javascript
var a = parseInt(5.8 + 4.7);
console.log(a);
```

打印结果:

```javascript
10;
```

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

代码举例:

```javascript
var a = '110';

var num = parseInt(a, 16); // 【重要】将 a 当成 十六进制 来看待,转换成 十进制 的 num

console.log(num);
```

打印结果:

```
272
```

如果你对打印结果感到震惊,请仔细看上面的代码注释。就是说,无论 parseInt() 里面的进制参数是多少,最终的转换结果是十进制。

我们继续来看下面的代码,打印结果是多少。

```javascript
var a = '5';

var num = parseInt(a, 2); // 将 a 当成 二进制 来看待,转换成 十进制 的 num

console.log(num); // 打印结果:NaN。因为 二进制中没有 5 这个数,转换失败。
```

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

parseFloat()的作用是:将字符串转换为**浮点数**。

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

代码举例:

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

parseFloat() 的几个特性,可以参照 parseInt()。

3、转换为 Boolean

将其他的数据类型转换为 Boolean,可以使用 Boolean()函数。情况如下:

- 情况一:数字 --> 布尔。除了 0 和 NaN,其余的都是 true。也就是说,`Boolean(NaN)`的结果是 false。

- 情况二:字符串 ---> 布尔。除了空串,其余的都是 true。全是空格的字符串,转换结果也是 true。字符串`'0'`的转换结果也是 true。

- 情况三:null 和 undefined 都会转换为 false。

- 情况四:引用数据类型会转换为 true。注意,空数组`[]`和空对象`{}`,转换结果也是 true


PS:转换为 Boolean 的这几种情况,**很重要**,开发中会经常用到。

4、其他进制的数字

- 16 进制的数字,以`0x`开头

- 8 进制的数字,以`0`开头

- 2 进制的数字,`0b`开头(不是所有的浏览器都支持:chrome 和火狐支持,IE 不支持)

比如`070`这个字符串,如果我调用 parseInt()转成数字时,有些浏览器会当成 8 进制解析,有些会当成 10 进制解析。

所以,比较建议的做法是:可以在 parseInt()中传递第二个参数,来指定当前数字的进制。例如:

```javascript
var a = "070";

a = parseInt(a, 8); //将 070 当成八进制来看待,转换结果为十进制。
console.log(a); // 打印结果:56。这个地方要好好理解。
```

四、隐式类型转换

隐式类型转换,内部调用的都是显式类型的方法

1、isNaN() 函数

isNaN(参数);

解释:判断指定的参数是否为 NaN(非数字类型),返回结果为 Boolean 类型。也就是说:**任何不能被转换为数值的参数,都会让这个函数返回 true**。

**执行过程**:

(1)先调用`Number(参数)`函数;

(2)然后将`Number(参数)`的返回结果和`NaN`进行比较。

代码举例:

```javascript
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
```

2、自增/自减运算符:`++`、`—-`

**举例 1**:

```javascript
var a = "666";
a++;

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

执行过程:

(1)先调用`Number(参数)`函数;

(2)然后将`Number(参数)`的返回结果进行 加 1 操作。

**举例 2**:

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

3、正号/负号:`+a`、`-a`

> 注意,这里说的是正号/负号,不是加号/减号。

任何值做`+a`、`-a`、`/a`运算时,运算结果都会自动转换为 Number 类型。 内部调用的是 Number() 函数。

**举例**:

```javascript
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
```

4、加号:`+`

**情况一**:字符串 + 数字

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

**情况二**:Boolean + 数字

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

**情况三**: null + 数字

- 等价于:0 + 数字

**情况四**: undefined + 数字

- 计算结果:NaN

5、运算符:`-`、`*`、`/`

1、任何非 Number 类型的值做`-`、`*`、`/`运算时,会将这些值转换为Number然后再运算(内部调用的是 Number() 函数),运算结果是 Number 类型。(注:`任何值 + 字符串`是特例,运算结果是字符串)

比如:

```javascript
result1 = true + 1; // 2 = 1+ 1

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

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

result4 = 100 - '1' // 99
```

2、任何的值和字符串做加法运算,都会先转换为字符串,然后再做拼串操作。

比如:

```javascript
result1 = 1 + 2 + '3' // 33

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


3、任何值和NaN做运算的结果都是NaN。

 

posted @ 2020-06-11 09:34  才华充电中  阅读(218)  评论(0编辑  收藏  举报