Js的数据类型
number 数字 string 字符串 boolean 布尔 symbol 符号 null 空 undefined 空 object 对象 bigint 表示任意大的整数
number
特殊值
- 正0 和负0 都等于0,但是负0又不一样
- 无穷大
Infinity、+Infinity、-Infinity - 无法表示的数字
NAN(not a number)
64位浮点数
JS数字的存储形式
- 浮点就是浮动的点,意思就是小数点会乱动
114.514
- 可以表示为
1.14514e2 - 也可以表示为
11451.4e-2
符号占1位 指数占11 位(-1023~1024) 有效数字占52位(开头的1省略)
范围和精度
范围(忽略符号位)
-
指数拉满、有效数字拉满,得到最大二进制数字
Number.MAX_VALUE:1.7976931348623157e+308
-
指数负方向拉满、有效数字最小1,得到最小值
-
Number.MIN_VALUE: 5e-324
精度(有效数字)
- 最多只能到52+1个二进制位表示有效数字
- 2^53 对应的十进制是9后面15个零
- 所以15位有效数字都能精确表示
- 16位有效数字如果小于90开头,也能精确表示9110000000000001就存不下来
String
写法
- 单引号
'你好'
- 双引号
"你好" - 反引号 ``
注意 引号不属于字符串的一部分
转义
用另一种写法表示你想要的东西'表示'
\”表示"\n表示换行\r表示回车\t表示tab 制表\表示 \\uFFFF表示对应的Unicode字符\xFF表示前256个Unicode字符
多行字符串
如果你想要在字符串里回车
用反引号
let s =`这样是
可以的
用反引号很容易做到`
字符串的长度
string.length
'123'.length // 3
‘\n\r\t’.length // 3字节
''.length // 0
' '.length // 1
通过下标读取字符
string[index]let s = 'hello';
s[0]// "h"
index 从0开始 s[0]是第一个字符
超过这个字符的则会显示undefined
let s = 'hello' ;
s[5] // undefined,居然不报错
s[4]// 'o'
base64转码
window.btoa
正常字符串转为Base64 编码的字符串
window .atob
Base64 编码的字符串转为原来的字符串
—般用来隐藏招聘启事里的简历邮箱
基本上也用来自欺欺人 所谓的「加密」,也就能骗过一部分外行
Boolean
只有true 和 false
下列运算符会得到bool值
否定运算
- ! value
相等运算
- 1 == 2 (false)
- 3 === 4(false)
- 3 !== 4(true)
比较运算
- 1 >2
- 1 >= 2
- 3 <4
- 3 <= 4
五个falsy 值
falsy 就是相当于false 但又不是false的值 分别是
- undefined
- null
- NaN
- ''
- 0
ps:''和' '是不一样的,前者为空字符串,后者为空格
undefined 和 null的区别
区别 没有本质区别
细节一
- 如果一个变量声明了,但没有赋值,那么默认值就是
undefined,而不是null
细节二
- 如果一个函数,没有写return,那么默认return
undefined,而不是null
细节三
- 前端程序员习惯上,把非对象的空值写为
undefined,把对象的空值写为null但仅仅是习惯上而已
symbol
symbol 是一种基本数据类型。Symbol() 函数会返回 symbol 类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的 symbol 注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。
bigint
BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。
变量声明
三种声明方式
var a = 1
let a = 1
const a = 1
区别
- var 是过时的、不好用的方式
- let是新的,更合理的方式
- const是声明时必须赋值,且不能再改的方式最后这种方式是错误的,不准这样声明
var声明
let 声明
规则
- 遵循块作用域,即使用范围不能超出{ }不能重复申明
- 可以赋值,也可以不赋值、必须先声明再使用,否则报错
- 全局声明的let变量,不会变成 window 的属性
- for 循环配合let有奇效
const 声明
规则
前三条一样
- 遵循块作用域,即使用范围不能超出{ }不能重复申明
- 可以赋值,也可以不赋值、必须先声明再使用,否则报错
- 全局声明的let变量,不会变成 window 的属性
- 声明时就要赋值,赋值后不能改,如果是数组就可以添加数据后面在解释
指定值
var a = 1
同时也指定了类型
var a = 1
但是值和类型都可以随意变化
a = 2
a = '字符串'
类型转换
number =>string
- String(n)
- n+ 'i
string =>number
- Number(s)
- parseInt(s)/ parseFloat(s)
- s - 0
x=>bool
- Boolean (x)
- !!
x=>string
- String(x)
- x.toString()
Object
定义
- 无序的数据集合
- 键值对的集合
写法
let obj = { 'name': 'mike', 'age': 32 }
let obj = new Object({'name': 'mike','age': 32})
细节
- 键名是字符串,不是标识符,可以包含任意字符
- 引号可省略,省略之后就只能写标识符
- 就算引号省略了,键名也还是字符串(大声!)
let obj = { key: value}
每个 key 都是对象的属性名(property)
每个 value 都是对象的属性值
- 所有属性名会自动变成字符串
let obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
234: true,
0xFF: true
};
Object.keys(obj)
=> ["1", "100", "255", "3.2", "0.01", "0.234"]
Object.keys(obj) 可以得到 obj 的所有 key
- 除了自己写定的值作为属性名,变量也可以作为属性名
let ac = 'age'
let obj = { ac : '25'} //这样写,属性名为 'ac'
let obj = { [ac] : '18' } //这样写,属性名为 'age'
let obj = { [ac] : '18' } ====> let obj = { age : '18' } //当然,age也是字符串
对比
- 不加 [ ] 的属性名会自动变成字符串
- 加了 [ ] 则会当做变量求值
- 值如果不是字符串,则会自动变成字符串
对象的隐藏属性
隐藏属性
- JS 中每一个对象都有一个隐藏属性
- 这个隐藏属性储存着其共有属性组成的对象的地址
- 这个共有属性组成的对象叫做原型
- 也就是说,隐藏属性储存着原型的地址
代码示例
var obj = {}
obj.toString() // 居然不报错
因为 obj 的隐藏属性对应的对象上有 toString()
原型
每个对象都有原型
- 原型里存着对象的共有属性
- 比如 obj 的原型就是一个对象
obj.__proto__存着这个对象的地址- 这个对象里有
toString/constructor/valueOf等属性
对象的原型也是对象
- 所以对象的原型也有原型
obj = {}的原型即为所有对象的原型- 这个原型包含所有对象的共有属性,是对象的根
- 这个原型也有原型,是
null
对象的增删改查
删除属性
使用delete obj.xxx 或 delete obj['xxx']
即可删除 obj 的 xxx 属性
有一个问题是需要区分属性值为 undefined和不含属性名
- 不含属性名
'xxx' in obj === false
- 含有属性名,但是值为 undefined
'xxx' in obj && obj.xxx === undefined
- 注意
obj.xxx === undefined不能断定 'xxx' 是否为 obj 的属性
- 举个例子
你有没有安装360?
A: 没有 // 不含属性名
B: 有,但是没有装(下载了安装包) // 含有属性名,但是值为 undefined
一定要分清楚,没有与undefined的区别
查看所有属性
- 查看自身所有属性
Object.keys(obj)
- 查看自身+共有属性
console.dir(obj)
或者自己依次用 Object.keys 打印出 obj.__proto__
判断一个属性是自身的还是共有的
obj.hasOwnProperty('toString')
ps:
'xxx' in obj表示这个属性是否在obj里面,也包含了原型中方法。obj.hasOwnProperty('xxx')判断一个属性是自身的还是共有的,如果是自己的就会返回true,否则返回false(自己的原型上的方法或者原型链上的方法
两种方法查看属性
- 中括号语法:
obj['key']
- 点语法:
obj.key
- 坑新人语法:
obj[key]变量 key 值一般不为 'key'
请优先使用中括号语法
- 点语法会误导你,让你以为 key 不是字符串
- 等你确定不会弄混两种语法,再改用点语法
和之前都一样obj[name]不等于obj['name']
- 第一个
name是一个变量,取决于当前作用域的name对应的值(说不定还没有name的值呢) - 第二个
name是obj本身的name
修改或增加属性
直接赋值
let obj = {name: 'mike'} // name 是字符串
obj.name = 'mike' // name 是字符串
obj['name'] = 'mike'
obj[name] = 'mike' // 错,因 name 值不确定
obj['a'+'ge'] = 114
let key = 'name'; obj[key] = 'mike'
let key = 'name'; obj.key = 'mike' // 错
因为 obj.key 等价于 obj['key']
批量赋值
Object.assign(obj, {age: 18, gender: 'man'})
修改或增加共有属性
- 无法通过自身修改或增加共有属性
let obj = {}, obj2 = {} // 共有 toString
obj.toString = 'xxx' //只会在改 obj 自身属性
obj2.toString //还是在原型上
- 我偏要修改或增加原型上的属性
obj.__proto__.toString = 'xxx' // 不推荐用 __proto__
Object.prototype.toString = 'xxx' 一般来说,不要修改原型,会引起很多问题
修改隐藏属性
不推荐使用 __proto__
let obj = {name:'frank'}
let obj2 = {name: 'jack'}
let common = {kind: 'human'}
obj.__proto__ = common
obj2.__proto__ = common
推荐使用 Object.create
let obj = Object.create(common)
obj.name = 'frank'
let obj2 = Object.create(common)
obj2.name = 'jack'
最好不要改,如果要改,就一开始就改,别后来再改