一、数据类型
1.1 概述
JS中的数据类型
7种(大小写无所谓)
- number 数字
- string 字符串
- bool 布尔
- symbol 符号(用的很少)
- undefined 空
- null 空
- 对象 object
- 总结:四基两空一对象
以下不是数据类型(都是对象)
- 数组
- 函数
- 日期
数据为什么需要类型?
数字和字符串 都是1,为什么要区分数字1和字符串'1'?
功能不同
- 数字可以加减乘除,字符串不行
- 字符串能表示电话号码,数字不行
存储形式不同
- JS中,数字是64位浮点数的形式存储的
- JS中,字符串是用类似UTF8形式存储的
1.2 null undefined 和 布尔值
1.2.1 布尔值
只有两个值,真 和 假
下列运算符会得到bool值
- 两元逻辑运算符: && (And),|| (Or)
- 否定运算 !value
- 相等运算 1==2 ,1! = 2 ,3 ===4,3!==4
- 比较运算 1>2 , 2≤4
如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true。除了false的五个叫做falsy值。
undefinednullfalse0NaN""或''(空字符串)
布尔值往往用于程序流程的控制,经常与if语句配合使用。
if ('') {
console.log('true');
}
// 没有任何输出
上面代码中,if命令后面的判断条件,预期应该是一个布尔值,所以 JavaScript 自动将空字符串,转为布尔值false,导致程序不会进入代码块,所以没有任何输出。
注意,空数组([])和空对象({})对应的布尔值,都是true。
1.2.2 undefined 和 null 两种空类型
没有本质区别,有几个细节
- 细节1:如果一个变量声明了,但是没有赋值,那么默认值就是undefined,而不是null
- 细节2:如果一个函数,没有写return,那么默认return undefined,而不是null
- 细节3:前端程序员习惯上,把非对象的空值写为undefined,把对象的空值写为null,但仅仅是习惯而已,可以不遵守
教程原文:
null表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null,表示未发生错误。
undefined表示“未定义”,下面是返回undefined的典型场景。
// 变量声明了,但没有赋值
var i;
i // undefined
// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
return x;
}
f() // undefined
// 对象没有赋值的属性
var o = new Object();
o.p // undefined
// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined
1.3 数值
1.3.1 整数和浮点数
JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。这就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
1.3.2 数值精度
JavaScript 浮点数的64个二进制位,也就是64位浮点数,从最左边开始,是这样组成的。
- 第1位:符号位,
0表示正数,1表示负数 - 第2位到第12位(共11位):指数部分
- 第13位到第64位(共52位):小数部分(即有效数字)
指数部分一共有11个二进制位,因此大小范围就是0到2047,除以二分给正负,所以是 -1023~1024
指数部分一共有11个二进制位,因此大小范围就是0到2047。IEEE 754 规定,如果指数部分的值在0到2047之间(不含两个端点),那么有效数字的第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字这时总是1.xx...xx的形式,其中xx..xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。
(-1)^符号位 * 1.xx...xx * 2^指数部分
上面公式是正常情况下(指数部分在0到2047之间),一个数在 JavaScript 内部实际的表示形式。
精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-253到253,都可以精确表示。
Math.pow(2, 53)
// 9007199254740992
Math.pow(2, 53) + 1
// 9007199254740992
Math.pow(2, 53) + 2
// 9007199254740994
Math.pow(2, 53) + 3
// 9007199254740996
Math.pow(2, 53) + 4
// 9007199254740996
上面代码中,大于2的53次方以后,整数运算的结果开始出现错误。所以,大于2的53次方的数值,都无法保持精度。由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。
Math.pow(2, 53)
// 9007199254740992
// 多出的三个有效数字,将无法保存
9007199254740992111
// 9007199254740992000
上面示例表明,大于2的53次方以后,多出来的有效数字(最后三位的111)都会无法保存,变成0。
1.3.3 数值范围
根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。
如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity。
Math.pow(2, 1024) // Infinity
如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
Math.pow(2, -1075) // 0
下面是一个实际的例子。
var x = 0.5;
for(var i = 0; i < 25; i++) {
x = x * x;
}
x // 0
上面代码中,对0.5连续做25次平方,由于最后结果太接近0,超出了可表示的范围,JavaScript 就直接将其转为0。
JavaScript 提供Number对象的MAX_VALUE和MIN_VALUE属性,返回可以表示的具体的最大值和最小值。
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
1.3.4 数值的表示法
- 整数 1
- 小数 0.1
- 科学计数法 1.23e4 (e4就是乘以10的4次方)
- 八进制(用得少)0123,00123,0o123
- 十六进制 0x3F 0X3F (用得少)
- 二进制 0b11 或0B11 (用得少)
1.3.5 数值的进制
用字面量(literal)直接表示一个数值时,JavaScript 对整数提供四种进制的表示方法:十进制、十六进制、八进制、二进制。
- 十进制:没有前导0的数值。
- 八进制:有前缀
0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。 - 十六进制:有前缀
0x或0X的数值。 - 二进制:有前缀
0b或0B的数值。
默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。下面是一些例子。
0xff // 255
0o377 // 255
0b11 // 3
如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错。
0xzz // 报错
0o88 // 报错
0b22 // 报错
上面代码中,十六进制出现了字母z、八进制出现数字8、二进制出现数字2,因此报错。
通常来说,有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制。
0888 // 888
0777 // 511
前导0表示八进制,处理时很容易造成混乱。ES5 的严格模式和 ES6,已经废除了这种表示法,但是浏览器为了兼容以前的代码,目前还继续支持这种表示法。
十进制转二进制方法:
- 31转成二进制,经过一番尝试发现:31= 02的5次方 + 12的四次方 + 12的3次方 + 12的平方 + 12 + 12的0次方
- 所以31(十进制) = 01111(二进制)
二进制转十进制
- 100011变成十进制,每一位乘以2的n次方,然后加起来
- 100011 = 2的五次方 + 2的1次方 +2的0次方=35
二进制转十六进制
用程序员计算器,或者自己算
1.3.6 特殊数值
- 正0和负0,都等于0,但是是三个数(1除以-0等于负无穷)
- 无穷大:Infiniti,+Infiniti,-Infiniti
- 无法表示的数字:NaN(Not a Number),但他是一个数字 。(比如0除以0,返回NaN) NaN不等于任何值,包括NaN。
1.4 字符串
1.4.1 定义
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。(以及反引号)
'abc'
"abc"
`abc`
如果想在字符串里回车,那么可以直接用反引号
let s = `这样是
可以的
用反引号很容易做到`
1.4.2 转义
反斜杠(\)在字符串内有特殊含义,用来表示一些特殊字符,所以又称为转义符。
需要用反斜杠转义的特殊字符,主要有下面这些。
\0:null(\u0000)\b:后退键(\u0008)\f:换页符(\u000C)\n:换行符(\u000A)\r:回车键(\u000D)\t:tab制表符(\u0009)\v:垂直制表符(\u000B)\':单引号(\u0027)\":双引号(\u0022)\\:反斜杠(\u005C)\xHH:\x后面紧跟两个十六进制数(00到FF),代表一个字符。HH对应该字符的 Unicode 码点,比如\xA9表示版权符号。这种方法也只能输出256种字符。\uXXXX:\u后面紧跟四个十六进制数(0000到FFFF),代表一个字符。XXXX对应该字符的 Unicode 码点,比如\u00A9表示版权符号。
上面这些字符前面加上反斜杠,都表示特殊含义。
1.4.3 字符串与数组
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。
var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"
// 直接对字符串使用方括号运算符
'hello'[1] // "e"
如果方括号中的数字超过字符串的长度,或者方括号中根本不是数字,则返回undefined。
'abc'[3] // undefined
'abc'[-1] // undefined
'abc'['x'] // undefined
但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。
var s = 'hello';
delete s[0];
s // "hello"
s[1] = 'a';
s // "hello"
s[5] = '!';
s // "hello"
上面代码表示,字符串内部的单个字符无法改变和增删,这些操作会默默地失败。
1.4.4 length属性
length属性返回字符串的长度,该属性也是无法改变的。
var s = 'hello';
s.length // 5
'\n\r\t'.length //3
''.length// 0
' '.length // 1
上面代码表示字符串的length属性无法改变,但是不会报错。
为什么字符串有属性?学完对象可以解答。
1.4.5 字符集
如何存字符?
用0-127表示所有符号,然后记录下用户点击了哪些符号
中国人开始用电脑了,怎么办?(之前不包含生僻字、繁体、日语、汉语)
中国国家标准局 —— 国标2312
生僻字怎么办?
微软出了GBK
网页里出现了藏文、泰文,怎么办?
万国码Unicode
优点
- 已收录13万字符(大于16位),全世界通用
- 以后还会继续扩充
缺点
- 两个字节不够用,每个字符要三个及以上字节
- 所有文件都扩大50%,不划算
UTF-8应运而生
UTF-8 是 Unicode 一种存储规则,也叫字符编码规则。
这就是如何存字符的
那就是记录编号,然后存编号
二、变量声明
三种声明方式
- var a =1 过时,不要再用
- let a =1 新的
- const a =1 声明时必须赋值,且不能再改
- a =1 这种声明方式是错的
let 声明
- 遵循块作用域,适用范围不能超过{}
- 不能重复声明
- 可以赋值,也可以不赋值
- 必须先声明再使用
- 全局声明的let变量,不会变成window属性
- for循环配合let 有奇效
const 声明
- 跟let规则一样
- 只有一条不同,声明时就要赋值,赋值后不能改
声明变量的同时,也指定了类型,但是值和类型都可以随时变化
类型转换
number变为string 👇
- String(n)
- n + ''
string变为number 👇
- Number(s)
- parseInt(s) / parseFloat(s)
- s - 0
x变为bool 👇
- VBoolean(x)
- !!X
x变为string 👇
- String(x)
- x.toString()