数据类型
- 简单数据类型(原始类型)
Undefined、Null、Boolean、Number、String、Symbol(符号)
- 复杂数据类型(对象)
Object(无序名值对的集合)
Undefined
- 使用 var let const 声明了变量但是没有初始化赋值时,就相当于给变量赋值了undefined
let message
console.log(message == undefined) // true
- 正常情况下不用显著的给变量设置undefined,undefined只是用来初始化变量,在ECMA-262第三版之前是不存在的,增加undefined与null本质的区别,null是明确确定空对象指针
undefined == null // true 会转换操作数
Null
- 定义变量是对象,但是当时又没有哪个对象可保存,可以用null来填充,既能保持null是空对象指针的语义,又能与undefined区分开,又能检查变量是否被重新赋予了对象的引用
- null 是假值
Boolean
- 字面量:true、false
- 区分大小写
- 转型函数 Boolean()
- Boolean 类型
- 转换为true
Boolean(true)
- 转换为false
Boolean(false)
- String
- 转换为true
Boolean('dd') // 非空字符串
- 转换为false
Boolean('') // 空字符串
- Number
- 转换为true
Boolean(1) // 非0数值 无穷大也是 true Infinity
Boolean(Infinity) // true
Boolean(-Infinity) // true
- 转换为false
Boolean(0) 0 和NaN
- Object
- 转换为true
Boolean({}) 任意对象
Boolean(function() {})
- 转换为false
Boolean(null) 空指针
- Undefined
- 转换为true
没有
- 转换为false
Boolean(undefined)
- 流程控制语句会自动执行其他类型值转换Boolean值的转换
Number
- 0 === -0 ﹢0永远 === -0
- 整数和浮点数
- 浮点数 科学计数法
- let floatNum = 3.125e7; // 等于31250000
- 规则:数值后面跟一个小写的e字母,加上乘以10的多少次幂
- 值的范围
- infinity 无穷大, -infinity负无穷大,不能在进行任何计算
- isFinite() 判断是不是最大值函数
- Number.MAX_VALUE 保存最大的值 1.797 693 134 862 315 7e+308
- Number.MIN_VALUE 保存最小的值 5e-324
- Number.NEGATIVE_INFINITY 捕获 -Infinity
- Number.POSITIVE_INFINITY 获取 Infinity
- NaN
- 表示不是数值,返回数值操作失败,不会抛出错误
- 不合法的转换数值操作都会返回NaN, 0/0
- 分母是0时,返回 Infinity 分母是-0,返回-Infinity
- 任何涉及与NaN操作都会返回NaN
- NaN 不等于 包含NaN在内的任何值 NaN == NaN // false
- isNaN() 参数是任何数据类型,判断参数是否不是数值
- 能直接转数值的 返回 false
- 不能直接转数值的 返回 true
- 转换过程 先调用对象的valueOf(),能转换,直接返回,不能,在调用toString(),并测试转换值
- 数值转换
- 转换函数 Number()
- parseInt()
- parseInt(value, 转换进制) // 2、8、10、16 避免系统出错,应该传第二个参数
- 专注字符串转数值
- 最前面的空格会被忽略,从第一个非空字符串开始转换
- 第一个字符不是数值字符,加号+,减号-,返回NaN // parseInt(' i1ddd1') // Nan
- 第一个字符是数值字符串,或者以加号+或者减号-,则会继续检测每个字段,直到结束,如果遇到非数值字符换转是数值的那些值 // parseInt(' 1dfdfd+0ddd1') // 1
- 遇到小数点也会忽略 parseInt(' 1.34') // 1
- 例子
- let num1 = parseInt("1234blue") // 1234
- let num2 = parseInt("") // NaN
- let num3 = parseInt("0xA") // 10,解释为十六进制整数
- let num4 = parseInt(22.5) // 22
- let num5 = parseInt("70") // 70,解释为十进制值
- let num6 = parseInt("0xf")// 15,解释为十六进制整数
- let num1 = parseInt("10", 2) // 2,按二进制解析
- let num2 = parseInt("10", 8) // 8,按八进制解析
- let num3 = parseInt("10", 10) // 10,按十进制解析
- let num4 = parseInt("10", 16) // 16,按十六进制解析
- parseFloat()
String
- 声明 单引号'', 双引号"", 反引号``, 以什么引号开头就要以什么引号结束
- let firstName = "John"
- let firstName = 'John'
- let firstName =
John
- 字符字面量
- 用来表示非打印字符或其他用途字符,可以在字符串的任意位置
- 常见字面量
- \n 换行
- \t 制表
- \b 退格
- \r 回车
- \f 换页
- \ 反斜杠(\)
- ' 单引号(')
- " 双引号(")
- ` 反引号(`)
- \xnn 以十六进制编码nn表示的字符(n表示十六进制数字0~F),'\x42' 表示 'A'
- \unnnn 以十六进制编码nnnn表示Unicode字符(n表示十六进制数字0~F)'\u03a3' 表示希腊字符 'Σ'
- length 属性
- 字符串特点
- 声明的字符串是不可变的,修改变量值过程是先销毁原始字符串,在将新的字符串赋值该变量
- 早期浏览器拼接字符串非常慢,现已针对性优化
- 转为字符串
- 模板字面量
- `` 反引号,可以保留换行符,可以跨行定义字符
- 定义模板方便
- 字符串插值
- 可以在一个连续定义中插入一个或者多个值
- 是一种特殊的语法表达式,求值后得到的是字符串
- 写法
${} 插入的值都会使用toString()强制转型为字符串
- 插值内可以调用函数和方法
- 模板字面量标签函数
- 通过标签函数可以自定义插值行为
- 标签函数接受被插值记号分割后的模板和表达式求值的结果
- 标签函数本身是一个常规函数,通过前缀到模板字面量来应用自定义行为
- 标签函数接受参数为原始字符串数组和每个表达式的求值结果
- 原始字符串数组
第一个参数总是接收这个插值左右两边的字符,并存入数组
- 每个表达式的求值结果
有多少个插值就有多少个参数可以用剩余参数
let a = 6; let b = 9;
function simpleTag(strings, aValExpression, bValExpression, sumExpression) {
console.log(strings);
console.log(aValExpression);
console.log(bValExpression);
console.log(sumExpression);
return 'foobar';
}
let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
- 标签函数返回值是自定义模板字面量后字符串
- 例子
function format(strings,...values){
return strings.reduce((s,v,idx)=>{
if(idx>0){
const prev=values[idx-1]
if(typeof prev==='number'){
s+=`$${prev.toFixed(2)}`
}else{
s+=prev
}
}
return s+v
},'')
}
const item='orange'
const price=3.5554
const text=format`the ${item}'s price is ${price}`
console.log(text)
Symbol
- es6 新增基本数据类型,符合是原始值,符合实例是唯一、不可变的。符合用途确保对象属性使用唯一标识符,且不会发生属性冲突
- symbol基本使用
- 使用Symbol()函数初始化,typeof会返回symbol类型
- 调用时可以传入一个字符串参数作为描述,以方便将来通过这个字符串调用代码
- symbol没有字面量,只要创建symbol实例作为object的新属性,就可以保证不会覆盖已经有的对象
- symbol函数不能用new关键字作为构造函数使用,let mySymbol = new Symbol() // TypeError: Symbol is not a constructor
- 使用symbol包装对象
- let mySymbol = Symbol() let myWrappedSymbol = Object(mySymbol)
- 例子
- let sym = Symbol() console.log(typeof sym) // symbol
- let genericSymbol = Symbol()
let otherGenericSymbol = Symbol()
let fooSymbol = Symbol('foo')
let otherFooSymbol = Symbol('foo')
console.log(genericSymbol == otherGenericSymbol) // false
console.log(fooSymbol == otherFooSymbol) // false
- 使用全局符合注册表
- 使用符号作为属性
- 凡是可以用字符串和数值作为属性的地方。也可以使用符合
- 对象字面量属性和Object.defineProperty()和Object.defineProperties()定义属性
- Object.defineProperty()
- 添加、修改对象属性,通过属性特征描述符可以控制属性的可配置性,可枚举性,可修改性
- Object.defineProperty(obj, props, descriptor),返回修改的目标对象
obj:要定义或者修改的对象
props: 属性名
descriptor: 属性描述
descriptor: {
configurable: false
enumerable: false
writable: true
value: ''
get() {
},
set() {
}
}
方式二与方式一不能同时出现
3. 例子
let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux')
let o = {
[s1]: 'foo val'
}
let a = Object.defineProperty(o, s2, {value: 'bar val'})
console.log(o) // {Symbol(foo): 'foo val', Symbol(bar): 'bar val'}
console.log(a) // {Symbol(foo): 'foo val', Symbol(bar): 'bar val'}
- Object.defineProperties()
- 一次性定义多个属性
- Object.defineProperty(obj, descriptor),返回修改的目标对象,两个参数
obj:要定义或者修改的对象
descriptor:属性集合对象
descriptor:{
name: {
value: 'key',
configurable: false // 可配置性
enumerable: false // 可枚举性
writable: true // 可修改性
}
}
// 例子
let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux');
let o = {
[s1]: 'foo val'
};
let b = Object.defineProperties(o, {
[s3]: {value: 'baz val'},
[s4]: {value: 'qux val'}
})
console.log(o) // {Symbol(foo): 'foo val', Symbol(baz): 'baz val', Symbol(qux): 'qux val'}
console.log(b) // {Symbol(foo): 'foo val', Symbol(baz): 'baz val', Symbol(qux): 'qux val'}
- Object.getOwnPropertyNames()
- 返回对象实例的常规属性数组
- Object.getOwnPropertySymbols()
- 返回对象实例的符号属性数组
- Object.getOwnPropertyDescriptors()
- 返回同时包含常规和符号属性描述符的对象
- Reflect.ownKeys()
- 返回两种类型的键
- 例子
let s1 = Symbol('foo'),
s2 = Symbol('bar');
let o = {
[s1]: 'foo val',
[s2]: 'bar val',
baz: 'baz val',
qux: 'qux val'
};
console.log(Object.getOwnPropertySymbols(o));
// [Symbol(foo), Symbol(bar)]
console.log(Object.getOwnPropertyNames(o));
// ["baz", "qux"]
console.log(Object.getOwnPropertyDescriptors(o));
// {baz: {...}, qux: {...}, Symbol(foo): {...}, Symbol(bar): {...}}
// {baz: {configurable: true, enumerable: true, value: "baz val", writable: true}}
console.log(Reflect.ownKeys(o));
// ["baz", "qux", Symbol(foo), Symbol(bar)]
- 查找没有显示保存属性的引用值时,要循环去寻找
let o = {
[Symbol('foo')]: 'foo val',
[Symbol('bar')]: 'bar val'
};
console.log(o);
let barSymbol = Object.getOwnPropertySymbols(o)
.find((symbol) => symbol.toString().match(/bar/));
console.log(barSymbol);
- 常用内置符号
- es6引入了常用的内置符号,暴露语言内部行为,可以让开发者直接访问、重新或者模拟这些行为
- 都是一symbol工厂函数字符串属性的形式存在
- 用途之一重新定义,改变原生结构
- 是全局函数Symbol的普通字符串属性,指向一个符号的实例
- 内置符号属性都是不可写、不可枚举、不可配置的
- 引用符号的前缀是@@ @@iterator 指的就是Symbol.iterator
- symbol.asyncIterator
- Symbol.hasInstance
- instanceof 确认一个对象实例的原型链上是否有原型
- ES6中 instanceof 操作符使用 Symbol.hasInstance函数确认关系
- 以Symbol.hasInstance为key的函数也会执行,区别是操作数对调
- 例子
function Foo() {}
let f = new Foo();
console.log(Foo[Symbol.hasInstance](f));
- 属性定义在Function原型上,因此默认所有的函数和类上都能调用。
- instanceof会在原型上寻找这个属性定义,可以在继承的类上通过静态方法重新定义
- 例子
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
let b = new Baz();
console.log(Bar[Symbol.hasInstance](b));
console.log(b instanceof Bar);
console.log(Baz[Symbol.hasInstance](b));
console.log(b instanceof Baz);
- Symbol.isConcatSpreadable
- 通过Symbol.isConcatSpreadable的值(false、true)修改ES6concat()方法
- 为false、假值的时候整个对象被加到数组末尾
let initial = ['foo'];
let array = ['bar'];
console.log(initial.concat(array)); // ['foo', 'bar']
console.log(array[Symbol.isConcatSpreadable]) // undefined
array[Symbol.isConcatSpreadable] = false
console.log(initial.concat(array)); // ['foo', Array(1)]
- 为true、真值把这个类数组对象打平到数组实例
let say = function () {
console.log(arguments) // 类数组对象 不能用数组的方法,但是可以用索引来访问。存在length
}
say(1, 2)
// 结构为
0: 1
1: 2
length: 2
{0: 1, 1: 2, length: 2}
如果一个普通的对象加上一个 length 属性就可以变成一个类数组对象。
{length: 1, value: 1, 0: 3}
let say = function () {
console.log(Array.from(arguments))
}
say(1, 2)
let initial = ['foo']
let arrayLikeObject = { length: 1, 0: 'baz' }
console.log(initial.concat(arrayLikeObject))
console.log(arrayLikeObject[Symbol.isConcatSpreadable])
arrayLikeObject[Symbol.isConcatSpreadable] = true
console.log(initial.concat(arrayLikeObject))
- 不是类数组对象的在设置为true时会被忽略
let initial = ['foo'];
let otherObject = new Set().add('qux');
console.log(initial.concat(otherObject));
console.log(otherObject[Symbol.isConcatSpreadable]);
otherObject[Symbol.isConcatSpreadable] = true;
console.log(initial.concat(otherObject));
- Symbol.iterator
- Symbol.match
- 表示一个正则表达式方法,用正则表达式去匹配字符串
- 由String.prototype.macth()调用
- 参数是一个正则表达式,若不是正则,会转换成正则对象
- 可以自定义Symbol.match函数
- 例子
class FooMatcher {
static [Symbol.match](target) {
return target.includes('foo');
}
}
console.log('foobar'.match(FooMatcher));
console.log('barbaz'.match(FooMatcher));
class StringMatcher {
constructor(str) {
this.str = str;
}
[Symbol.match](target) {
return target.includes(this.str);
}
}
console.log('foobar'.match(new StringMatcher('foo')));
console.log('barbaz'.match(new StringMatcher('qux')));
- Symbol.replace
- 替换一个字符串中匹配的子串
- 由String.prototype.replace()调用
- 参数是一个正则表达式,若不是正则,会转换成正则对象
- 可以自定义Symbol.replace函数
class FooReplacer {
static [Symbol.replace](target, replacement) {
return target.split('foo').join(replacement);
}
}
console.log('barfoobaz'.replace(FooReplacer, 'qux'));
class StringReplacer {
constructor(str) {
this.str = str;
}
[Symbol.replace](target, replacement) {
return target.split(this.str).join(replacement);
}
}
console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux'));
- Symbol.search
- 返回匹配字符串中子串的下标
- 由String.prototype.search()调用
- 参数是一个正则表达式,若不是正则,会转换成正则对象
- 可以自定义Symbol.search函数
class FooSearcher {
static [Symbol.search](target) {
return target.indexOf('foo');
}
}
console.log('foobar'.search(FooSearcher));
console.log('barfoo'.search(FooSearcher));
console.log('barbaz'.search(FooSearcher));
class StringSearcher {
constructor(str) {
this.str = str;
}
[Symbol.search](target) {
return target.indexOf(this.str);
}
}
console.log('foobar'.search(new StringSearcher('foo')));
console.log('barfoo'.search(new StringSearcher('foo')));
console.log('barbaz'.search(new StringSearcher('qux')));
- Symbol.species
- 是一个函数值的属性,被构造函数用以创建派生对象
- 用Symbol.species 定义静态的获取器(getter)方法, 可以修改子类覆盖对象的默认构造函数
class Bar extends Array {}
let bar = new Bar();
console.log(bar instanceof Array);
console.log(bar instanceof Bar);
bar = bar.concat('bar');
console.log(bar instanceof Array);
console.log(bar instanceof Bar);
class Baz extends Array {
static get [Symbol.species]() {
return Array;
}
}
let baz = new Baz();
console.log(baz instanceof Array);
console.log(baz instanceof Baz);
baz = baz.concat('baz');
console.log(baz instanceof Array);
console.log(baz instanceof Baz);
- Symbol.split
- 在匹配正则表达式的索引位置拆分字符串
- String.prototype.split()方法使用
- 参数是一个正则表达式,若不是正则,会转换成正则对象
- 可以自定义Symbol.split函数
class FooSplitter {
static [Symbol.split](target) {
return target.split('foo');
}
}
console.log('barfoobaz'.split(FooSplitter));
class StringSplitter {
constructor(str) {
this.str = str;
}
[Symbol.split](target) {
return target.split(this.str);
}
}
console.log('barfoobaz'.split(new StringSplitter('foo')));
- Symbol.toPrimitive
- 是一个方法,将对象转换为相应的原始值
- 由ToPrimitive 抽象操作使用
- 自定义的对象,实例可以通过Symbol.toPrimitive,定义一个函数改变默认行为
class Foo {}
let foo = new Foo();
console.log(3 + foo);
console.log(3 - foo);
console.log(String(foo));
class Bar {
constructor() {
this[Symbol.toPrimitive] = function(hint) {
switch (hint) {
case 'number':
return 3;
case 'string':
return 'string bar';
case 'default':
default:
return 'default bar';
}
}
}
}
let bar = new Bar()
console.log(3 + bar);
console.log(3 - bar);
console.log(3 - bar);
- Symbol.toStringTag
- 通常作为对象的属性key使用
- 对应的数值应该为string类型,用来表示该对象的自定义类型标签
- 通常由内置的 Object.prototype.toString() 调用,把它包含在自己的返回值
- Object.prototype.toString() 调用时,会寻找symbol.toStringTag指定的实例标识符。默认为Object
- 自定义类实例需要明确定义
let s = new Set()
console.log(s)
console.log(s.toString())
console.log(s[Symbol.toStringTag])
class Foo = {}
let foo= new Foo()
console.log(foo);
console.log(foo.toString());
console.log(foo[Symbol.toStringTag])
class Bar {
constructor() {
this[Symbol.toSrtingTag] = 'Bar'
}
}
let bar = new Bar()
console.log(bar);
console.log(bar.toString());
console.log(bar[Symbol.toStringTag])
- Symbol.unscopables
- 指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称
- 表示一个对象所有的以及集成的属性,从关联对象的with环境绑定中排除
- 不推荐使用
let o = { foo: 'bar'}
with(o) {
console.log(foo)
}
o[Symbol.unscopables] = {
foo: true
}
with(o) {
console.log(foo)
}
Object
- 一组数据和功能的集合
- 通过创建object类型的实例来创建自己的对象
let o = new Object()
- 每个object的实例都有下面的属性和方法
- constructor
class Bar {
constructor() {
this.name = 'bar'
}
}
const bar = new Bar()
console.log(bar.name)
- hasOwnProperty
- 判断当前对象实例(不是原型)上,是否存在给定的属性
- 参数必须是string或者symbol
const foo = {}
foo.name = 'foo'
console.log(foo.hasOwnProperty(name))
console,log(foo.hasOwnProperty(sex))
- isPrototypeOf
function Foo() {}
function Bar() {}
Bar.prototype = Object.create(Foo.prototype)
const bar = new Bar()
Bar.prototype.isPrototypeOf(bar)
Foo.prototype.isPrototypeOf(bar)
- propertyIsEnumerable
const o = {}
const a = []
o.name = 'object'
a[0] = 'array'
console.log(a.propertyIsEnumerable(0))
console.log(o.propertyIsEnumerable('name'))
console.log(a.propertyIsEnumerable('length))
console.log(o.isPrototypeOf('isPrototypeOf'))
- toLocaleString
- 返回对象的字符串表示,反应对象所在的本地化执行环境
- 主要用于将数组 Number对象或Date对象转换为本地格式的字符串
- toString
- 返回对象的字符串表示
- 与toLocaleString区别
const a = 123
console.log(a.toString()) //
console.log(a.toLocaleString())
const b = 1234567
console.log(b.toString()) //
console.log(b.toLocaleString())
const time = new Date()
console.log(time.toString()) // Wed Dec 29 2021 12:59:04 GMT+0800 (中国标准时间)
console.log(time.toLocaleString()) // 2021/12/29 下午12:59:04
- valueOf
const num = 123456
console.log(num.valueOf())
const array = ["ABC", true, 12, -5]
console.log(array.valueOf() === array)
const date = new Date(2021, 12, 29, 13, 11, 59, 230)
console.log(date.valueOf())