JS笔记《数据类型》

126 阅读8分钟

数据类型

  • 为什么需要数据类型?在计算机中,不同的数据所占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。
  • 变量的数据类型:JS是一种弱类型或者说解释型语言,意味着不用提前声明变量的类型,在程序运行过程中类型会被自动确定。
  • 数据的存储单位:bit < byte < kb < mb < gb < tb < ...
存储单位换算
bit(位)最小单位,存储1或0
b(字节)1b = 8bit
kb(千字节)1kb = 1024b
mb(兆字节)1mb = 1024kb
gb(G字节)1gb = 1024mb
......

JS数据类型

  • 简单数据类型:Number、String、Boolean、Null、Undefined(Symbol、BigInt为ES6新增)。
  • 复杂数据类型: Object(array、Object、function、date…)。
  • 简单数据类型又叫做原始值,存在栈(stack)内存中,也叫做不可改变的原始值。
  • 理解原始值的存放方式:
var a = 10;     // 在栈中申请一个内存空间 a,值为10
var b = a;      // 再申请一个内存空间 b,将 a 的值拷贝一份放到 b 中,相当于副本。互相不影响
a = 30;         // a不再指向之前的内存空间,而是在栈中重新申请一个空间 a,值为30。之前的内存空间失去了指向(无法访问),但数据依然存在,等待着接下来其他变量申请空间被覆盖。
  • 复杂数据类型也叫做引用值,存在堆(heap)内存中,包括Array、Object、Function、Date、RegExp……
  • 理解引用值的存放方式:
var arr = [1, 2];     // 将数组的值存放到堆中,同时栈也申请内存空间 arr,存放指向堆里的值的地址
var arr1 = arr;      // 申请一个栈内存空间 arr1, 将 arr 栈中存放的地址拷贝一份放到 arr1 中(拷贝的是地址),两者栈中的值相同,都指向堆中的同一个数据 
arr.push(3);        // 根据 arr 栈中的地址找到堆数据,修改为[1, 2, 3] 此时修改 arr 就相当于修改了 arr1 ,因为二者都指向同一个堆中的数据   

// arr = [3, 4];    在堆中又重新申请了新的空间存放[3, 4],然后 arr 在栈中重新申请空间存放指向这个新空间的地址。 此时 arr1 还是[1, 2], 因为 arr 重新指向了一个新的地址,而 arr1 的指向却没变

null 和 undefined

  • 都表示“没有”,区别是在JS中一般使用 null 表示一个空对象;使用 undefined 表示一个未定义的原始值。

boolean

  • 只有 truefalse,表示真和假。
  • 以下运算符会返回布尔值: !、===、==、!==、!=、>、<、>=、<=
  • 除了""、NaN、0、null、undefined、false以外任何值转为boolean都为true

number

  • JS内部所有的数字都是以64位浮点数形式储存,也就是说JS底层根本没有整数,所有数字都是64位浮点数的小数。
console.log(1 === 1.0);   // true
  • 由于浮点数不是精确的值,所以尽量避免涉及到小数的比较和运算。
console.log(0.1 + 0.2 === 0.3);   // false
cosnole.log(0.3 / 0.1);           // 2.9999999999999996

特殊数值

  • +0-0:几乎相等,除了当作除数时。
console.log(-0 === +0); // true
console.log(0 === -0);  // true
console.log(0 === +0);  // true

console.log((1 / +0) === (1 / -0));  // false 因为 1 / +0 等于 Infinity; 1 / -0 等于 -Infinity
    ```
* `NaN`:表示非数,依然是`number`类型。
```javascript
console.log(5 - 'a');  // NaN
console.log(0 / 0);    // NaN
console.log(typeof(NaN)); // 'number'

NaN与任何数运算得到的都是NaNNaN不等于任何值,包括它自己。

  1. Infinity-Infinity:表示正负无穷。
console.log(1 / 0);  // Infinity
console.log(1 / -0); // -Infinity

Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。

全局方法

parseInt(string, radix)
  • 用于将字符串转换成整数(小数位直接去掉),数字类型的值也可用。只能转换以数字开头的数值或字符串,其余一律 NaN。
  • radix表示以radix进制数为基底,将string转化为10进制的数,取值范围 2~36之间。省略则表示10进制。
console.log(parseInt("123"));       // 123
console.log(parseInt("123.43"));    // 123
console.log(parseInt("123px"));     // 123  
console.log(parseInt("1a23"));      // 1
console.log(parseInt('    1'));     // 1  空格会被自动去除

// parseInt只能转换以数字开头的数值或字符串,其余一律 NaN
//(前提radix不是16进制,因为十六进制允许以a~f开头)
console.log(parseInt("a123"));      // NaN
console.log(parseInt(''));          // NaN
console.log(parseInt(true));        // NaN
console.log(parseInt(false));       // NaN
console.log(parseInt(null));        // NaN
console.log(parseInt(undefined));   // NaN

console.log(parseInt("a1", 16));     // 161  以十六进制基底,将 a1 转化为10进制的数
console.log(parseInt("0x1"));        // 1  虽未填写 radix,但以"0x"开头则同样表示以十六进制为基底,将 "0x1"转化为10进制的数
parseFloat(string)
  • 用于将字符串转换成浮点数(保留小数位),数字类型的值也可用。
console.log(parseFloat(100.2));     // 100.2
console.log(parseFloat(100));       // 100
// 如果非纯数字的字符串,则只保留至非数字位(不包括 .)前的数字。要是以非数字(不包括 .)开头则返回 NaN
console.log(parseFloat("100.2"));   // 100.2
console.log(parseFloat("100"));     // 100
console.log(parseFloat("100.2a"));  // 100.2
console.log(parseFloat("12.a0"));   // 12
console.log(parseFloat(".3"));      // 0.3
console.log(parseFloat('  1.56'));  // 1.56

console.log(parseFloat('12a23ads')); // 12
console.log(parseFloat('12e23ads')); // 1.2e+24  数字后面跟着的字母 e是特殊值

转为NaN的规则同parseInt

isNaN(obj)
  • 用来判断一个值是否为NaN。只对数值有效,如果传入其他值,会被先转成数值。
console.log(isNaN(123));    // false
console.log(isNaN("123"));  // false Number("123") ==> 123 
console.log(isNaN(true));   // false Number(true) ==> 1
console.log(isNaN(null));   // false Number(null) ==> 0 

console.log(isNaN(NaN));        // true
console.log(isNaN(undefined));  // true Number(undefined) ==> NaN 
console.log(isNaN("abc"));      // true Number("abc") ==> NaN
console.log(isNaN({}));          // true Number({}) ==> NaN

// 数组比较特殊
console.log(isNaN([]));      // false Number([]) == > 0
console.log(isNaN([1]));     // false Number([1]) == > 1
console.log(isNaN([1,2]));   // true Number([1,2]) == > NaN
console.log(isNaN(['aaa'])); // true Number(['aaa']) == > NaN

内部实现相当于调用 Number(obj)。

isFinite(obj)
  • 返回一个布尔值,表示某个值是否为正常的数值。
console.log(isFinite(Infinity));    // false
console.log(isFinite(-Infinity));   // false
console.log(isFinite(NaN));         // false
console.log(isFinite(undefined));   // false

console.log(isFinite(null));        // true
console.log(isFinite(true));        // true
console.log(isFinite(0));           // true
console.log(isFinite("123"))        // true

内部实现相当于调用 Number(obj)。

string

  • Unicode字符集: 也叫统一码、万国码,字符集表示多个字符的集合。它将世界各种语言里的每一个字符都定义了一个唯一的编码,这意味着世界上所有的语言都可以使用它,而不会出现冲突。

  • Unicode字符集的编码范围是0x0000 - 0x10FFFF,可以容纳一百多万个字符,每个字符都有独一无二的编码,即每个字符都有一个二进制数值对应,也叫码点

  • 字符编码:字符集的一种实现方式,把字符集中的字符映射为特定的字节或字节序列,它是一种规则。UTF-8、UTF-16、UTF-32都是字符编码规则。

  • UTF-16有两种长度,对于码点在U+0000U+FFFF之间的字符,长度为16位,也就是2个字节;对于码点在U+10000U+10FFFF之间的字符,长度为32位,也就是4个字节。所以UTF-16的编码长度可以是2个字节或4个字节,这取决于每个字符的码点值。

  • JS内所有字符都是使用Unicode字符集表示,每个字符在JS中都是以16位(2个字节)的UTF-16格式存储,即使码点值是4个字节。这也就导致了字符串的length属性识别4个字节的字符会当成2个字符。

// 𝌆 对应码点为 U+1D306,在U+10000 到 U+10FFFF码点区间内,所以是4个字节
console.log('𝌆'.length);  // 2 被当成了2个字符
  • 字符串可以被视为字符数组,可以使用数组的方括号获取对应下标的值,但无法根据下标修改其中的单个字符。
var s = 'hello';
console.log(s[0]); // 'h'
s[0] = 'a';
console.log(s);    // 'hello'

length属性

  • 字符串的length属性返回字符串的长度,该属性只能查询,无法修改。
var s = 'hello';
console.log(s.length); // 5
s.length = 4;
console.log(s.length); // 5

Base64

  • base64是一种编码方法,可以将任意值转为0~9、a-z、A-Z、+、/这64个字符组成的可打印字符。主要目的不是为了加密,而是为了不出现特殊字符。
  • btoa():任意值转为Base64编码。
  • atob():Base64编码转为原来的值。
var str = 'Hello World!';
console.log(btoa(str));                // 'SGVsbG8gV29ybGQh'
console.log(atob('SGVsbG8gV29ybGQh')); // 'Hello World!'

console.log(btoa('你好'));    // 报错
// 以上2个方法不适合非ASCII码的字符,会报错。如需要处理非ASCII码中间需插入一个转码环节

/**
 * base64编码
 */
function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}

/**
 * base64解码
 */
function b64Decode(str) {
  return decodeURIComponent(atob(str));
}

console.log(b64Encode('你好'));        // 'JUU0JUJEJUEwJUU1JUE1JUJE'
console.log(b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE'));  // '你好'

typeof 运算符

  • 用来获取检测变量的数据类型,返回字符串类型的值
  • js共有3种方法用于检测一个变量到底是什么类型:
    1. typeof
    2. instanceof
    3. Object.prototype.toString()
console.log(typeof 123);     // "number"
console.log(typeof "123");   // "string"
console.log(typeof true);    // "boolean"

console.log(typeof {});      // "object"
console.log(typeof []);      // "object"
console.log(typeof null);    // "object"
console.log(typeof(new Number(1))); // "object" 包装类对象也会返回 object

function Person(name) {
    this.name = name;
}
var stu = new Person();
console.log(typeof stu);     // "object"
console.log(typeof Person);  // "function"

var a;
var arr = [1, 2];
var obj = {};
console.log(typeof a);         // "undefined" 只声明未赋值
console.log(typeof aaa);       // "undefined" 未声明的变量,只有在 typeof中才不会报错,否则在其他任何地方都会报错
console.log(typeof arr[2]);    // "undefined" 数组中没有第 3个元素或第 3个元素未赋值
console.log(typeof obj.uname); // "undefined" 对象中没有 uname属性

typeof 返回的 6种数据类型为:number、string、boolean、undefined、object、function