数据为什么需要类型?1与’1’,两者都是一为什么要区分呢?

  • 功能不同

    • 数字可以进行加减乘除,字符串不行;
    • 字符串能表示电话号码,数字不行;
  • 存储形式不同

    • JS 中,数字是用64位浮点数的形式存储的;
    • JS 中,字符串是用类似 UTF-8 形式存储的;

如何存储数字

十进制转换二进制即可;

十进制如何转换成二进制

算数比较小的话,可以先找小于并且相邻这个数最近的2的N次方。然后依次。如:

37 = 32 + 4 + 1;
对应:100101 (32 16 8 4 2 1 有的写1,没有则写0)

二进制转换十进制

口诀:每一位乘以2的N次方,然后相加。(从2^0开始)

100011 = 1*2^5 + 0*2^4 + 0*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 35 

由于二进制写起来比较慢,所以用十六进制来代替二进制;

二进制转换为十六进制

举例说明:

011110001011010 转换为 16进制
1. 从右往左,每四位改写一位,四位分割后,如下格式:
  011 1100 0101 1010
2. 分别用8421对应四位数值,忽略0对应的数字,然后把1对应的数字相加;
  011 1100 0101 1010
  421 8421 8421 8421 
   3   12   5    10
3. 大于9的数字改写为ABCDEF,最终得出3C5A

计算器程序员模式:

33

  • HEX 表示16进制,BIN表示2进制,OCT 表示8进制,DEC 表示10进制;

如何存放字符

使用编号表示,编号表如下:

34

  • 0 表示结束字符;
  • 10 表示换行;
  • 13 表示回车;
  • 32 表示空格;
  • 33 到 47表示标点;
  • 48 到 57表示数字符号,分别对应数字0~9;
  • 65 到 90 表示大写字母,分别对应大写字母A~Z;
  • 97 到 122 表示小写字母,分别对应小写字母a~z;
  • 127 表示删除键;

使用 GB2312 表示汉字编号

  • 使用 0000 ~ FFFF 表示汉字 ,一个16进制数是4个0/1位;

  • FFFF 就是4*4=16位,也就是两个字节;

  • 最多收录 2^16 = 65536 个字符;

参考 GB2312 编码表

中国文化博大精深,存在很多生僻字以及繁体字,但是 GB2312 并没有存进去。于是微软推出了国标扩展 GBK;

GBK 国标扩展

  • 包含 21886 个汉字和图形符合;
  • 收录了中日韩使用的几乎所有汉字;
  • 完全兼容 GB2312;
  • 依然使用 16 位(两个字节);

Unicode 万国码

  • 优点

    • 收录了13万字符,全世界通用;
    • 还在继续扩充;
  • 缺点

    • 两个字节不够用,每个字符要使用三个及以上字节;
    • 造成文件扩大;

UTF-8 出现

UTF-8是一种编码规则。

JS中的数据类型

  • 数字 number
  • 字符串 string
  • 布尔 bool
  • undefined
  • null
  • symbol
  • object

数字类型

数字是由64位浮点数组成的。

#### 特殊值

  • +0 -0 0

  • 无穷大 Infinity+Infinity-Infinity, 一般在除数为0时显示;

  • 无法表示的数字 NaN

  • NaN 不等于任何值包括它自己;

数字存储形式

  • JS 数字是由64位浮点数组成的,浮点的意思就是浮动的点,就是小数点会乱动;

  • 由于浮点数不是精确的值,所以涉及小数的比较和运算也会造成不精确的问题;

    0.1 + 0.2 === 0.3 // false
    0.3 / 0.1  // 2.9999999999999996
    (0.3 - 0.2) === (0.2 - 0.1) // false
    
JS 浮点数组成方式:
  • 第1位:符号位, 0 表示正数, 1 表示负数;

  • 第2位到第12位(共11位):指数部分;什么是指数?如:10^2 其中 2 代表10的2次方 那么 2 就是指数;指数可以是正数也可以是负数;范围是 : -1023 ~ 1024;

  • 第13位到第64位(共52位):小数部分(即有效数字,开头的1省略)

35

数字的范围和精度

范围

64位浮点数的指数部分的长度是11个二进制位,意味着指数部分是最大值是2047(2的11次方-1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为2的-1023次到2的1024次,超出这个范围的数无法表示。

举例1:

Math.pow(2, 1024); // Infinity

如果一个数大于2的1024次方,那么就会发生“正向溢出”,也就是说 JS 表示不了,就会返回 Infinity

举例2:

Math.pow(2, -1075); // 0

如果一个数小于等于2的-1075次方(指数部分最小值-1023,加上小数部分52位),那么就会发生为 “负向溢出”,JS 无法表示这么小的数,这时就会直接返回0。

JS 中可以使用 Number.MAX_VALUENumber.MIN_VALUE 返回可以表示的具体最大的值与最小的值。

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
精度
  • 最多只能得到53个二进制位表示有效数字;
  • 2^53对应的十进制是9后面15个零;
  • 15位有效数字都能精确表示,16位有效数字如果小于 90 开头,也能精确表示;反之则不能精确表示;如下图:

36

字符串

字符串有如下写法:

  • 单引号 ‘Hello’ 注意是英文的单引号;
  • 双引号 “Hello” 注意是英文的双引号;
  • 反引号 `Hello`

注意:JS 中需要输出单引号和双引号时,必须遵循 单引号套双引号或者双引号套单引号,优先使用反引号。如果需要在单引号或者双引号中必须使用单引号则可以使用转义符的形式。

约定俗成:由于 HTML 语言的属性值使用双引号,所以我们在写 JS 时字符串用的是单引号。一定要做到的是坚持使用一种风格,而不是风格交叉使用。

转义符

  • \' 表示 '
  • \" 表示 ";
  • \n 表示换行;
  • \r 表示回车;
  • \t 表示tab;
  • \\ 表示 \
  • \uFFFF 表示对应的是 Unicode 字符;
  • \xFF 表示前256个 Unicode 字符;

字符串与数组

字符串可以视为字符数组。只是相似仅此而已。

let s = 'hello';
s[0] // "h"
s[1] // "2"
s[4] // "o"
// 直接对字符串使用方括号运算符
'world'[1] // "o"

注意:如果方括号中的数字超过字符串的长度,或者方括号中根本不是数字,则返回 undefined

'abcd'[4] // undefined
'abcd'[-1] // undefined
'abc'['x'] // undefined

字符串无法改变单个字符。

var s = 'hello';
delete s[0];
s // "hello"

s[1] = 'a';
s // "hello"

s[5] = 'a';
s // "hello"

// 字符串内部无法改变和删除。

注意:字符串 length 属性也是无法改变,如果做出改变的话,会什么也不操作,也不会报错!

var s = 'hello';
s.length // 5

s.length = 3;
s.length // 5

s.length = 7;
s.length // 5

Base64 转码

所谓 Base64 就是一种编码方法,可以将任意值转成 0~9、A~Z、a-z、+/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。

JS 原生提供两个 Base64 编码方法:

  1. btoa() 任意值转换为 Base64 编码;
  2. atob() Base64 编码转换为原来的值;

    window.btoa('hello') // "aGVsbG8="
    window.atob('aGVsbG8=') // "hello"
    window.btoa('您好') // 报错
    

如果需要将非 ASCII码字符转为 Base64 编码,必须中间插入一个转码环节。

function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}

function b64Decode(str) {
  return decodeURIComponent(atob(str));
}

b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

布尔

布尔值代表“真”和“假”两个状态。”真”用关键字 true 表示, “假”用关键字false表示。布尔值只有这两个值。

运算符可以返回布尔值:

  • !
  • 相等运算符 =====!=!==
  • 比较运算符 ><>=<=

if 搭配布尔:

if (value) {...} else {...}

五个 falsy 值:(falsy 相当于 false 但又不是 false 的值)

undefined null 0 NaN '' 注意:是 “ 字符串而不是’ ‘空格字符串;

所以,value 中除五个falsy 值外都是 true;

null 与 undefined

nullundefined 都表示“没有” 、“空”的意思。如果将一个变量赋值为 undefinednull 语法效果几乎没有区别。

细节

  • 如果一个变量声明了,但没有赋值,那么默认值就是 undefined, 而不是 null
  • 如果一个函数,没有写 return 那么默认 return undefined ,而不是 null
  • 在习惯上,把非对象的空值写为 undefined,把对象的空值写为 null

JS 数据类型转换

JS 在定义变量时,既定义了变量的值也定义了变量的类型,并且值和类型都是可以随意变化的。

JS 又可以分为 自动类型转换强制类型转换

强制类型转换

强制转换主要是指使用 Number()String()Boolean() 三个函数,手动将各种类型的值,分别转换为数字、字符串和布尔值。

Number

使用 Number 函数,可以将任意类型的值转换为数值(肯定包含NaN)。

// 数值:转换还是原来的值
Number(123); // 123

// 字符串:如果可以被解析为数值,则转换为相应的数值,否则解析为NaN
Number('456'); // 456 
Number('324abc'); // NaN

// 空字符串转换为 0
Number(''); // 0

// 布尔值: true 转换为1, false转换为0
Number(false); // 0
Number(true); // 1

// undefined: 转换为NaN
Number(undefined); // NaN

// null: 转换为0
Number(null) // 0

注意:字符串转换为数字时,还可使用 parseInt函数,但是 Number函数将字符串转换为数值时,要比 parseInt 函数严格的多的。只要有一个字符无法转换成数值,则整个字符串都会被转换为 NaN

parseIntNumber 函数都会自动过滤一个字符串前后空格。

parseInt('\n\r\t12.31\n'); // 12
Number('\n\r\t12.31\n'); // 12.31

String

String 函数可以将任意类型的值转化为字符串,有如下转换规则:

  • 数值:转为相应的字符串。
  • 字符串:转换后还是原来的值。
  • 布尔值true 转换为字符串 "true", false 转换为字符串 "false"
  • undefined: 转换为字符串 "undefined"
  • null: 转换为字符串 "null"

    String(123); // "123"
    String('abc'); // "abc"
    String(false); // "false"
    String(undefined); // "undefined"
    String(null); // "null"
    

Boolean

Boolean 函数可以将任意类型的值转换为布尔值。

转换规则:除五个falsy 外,都会转换为 true

Boolean(undefined); // false
Boolean(null); // false
Boolean(0); // false
Boolean(''); // false
Boolean(NaN); // false
Boolean('0'); // true

自动类型转换

自动类型转换是以强制类型转换为基础的。

以下三种情况,JS 会进行自动类型转换,即转换是自动完成的,用户不可见。

  • 不同类型之间的数据互相转换

    123 + abc  // "123abc"
    123 * '1' // 123
    
  • 对于非布尔值的类型数据求布尔值

    if (abc) {
    console.log('hi');
    }
    // if 判断条件会自动转换布尔值
    
  • 对于非数值类型的值使用一元运算符(+-

    +'abc' // NaN
    +'123' // 123
    -'123' // -123
    

自动转换规则:预期什么类型的值,就该调用该类型的转换函数。比如,预期为字符串就调用String 函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认就会转为数值。

转换为布尔值示例

if ( !undefined
  && !null
  && !0
  && !NaN
  && !''
) {
  console.log('true');
} // true
// 还可以用 !!
!!0 // false
!!1 // true
!!'' // false
!!undefined // false

转换为字符串示例

5 + '1' // "51"
'5' + false // "5false"
'5' + true // "5true"
'5' + undefined // "5undeined"
'5' + null // "5null"

转换为数值示例

'5' - '2' // 3
'2' * '5' // 10
true - 1 // 0
false - 2 // -2
'1' - 1 // 0
false / '5' // 0
'abc' - 1 // NaN
null + 2 // 2
undefined + 2 // NaN

运算符两侧都被转换为数值。

参考资料