ES6知识点总结
ES6和ES5的区别
新增的块级作用域
新增了解构赋值
新增了class类
新增了symbol
新增了promise
新增了迭代器,生成器
新增了严格模式
let ,const
let:声明变量,const:声明常量
通常和块级作用域一起使用
const声明常量时声明赋值必须同时完成,并且不能修改常量的值
有自己的作用域,会产生临时性死区
严格模式
在混杂模式下,arguments和函数的形参存在映射关系,给函数加上默认参数,则自动为严格模式
class 类
<script>
class Person {
// 构造器:用来构造实例的属性
constructor(age, name) {
this.name = name
this.age = age
}
// 构造器外为原型,用来定义方法
say() {
}
// 存储器属性(getter,setter) 两个方法必须同时使用
get age() {
console.log('取值时走进get方法');
// 这里必须要有返回值,不然age的值为undefined
return this._age
}
set age(age) { //传入的参数就是在实例化时传入的age数据
// 在实例化时传入的age为12,此时相当设置了值,所以会走进set函数
console.log('设置值的时候必须走进');
// 可以对age进行限制
if (!typeof age === 'number') {
throw new Error('age需要为数字')
}
if (age < 0) {
age = 0
} else if (age > 200) {
age = 200
}
// 用_age来替换age
this._age = age
}
}
let a = new Person(12, 'zs')
// 在这里打印age,相当于取值操作,所以会走进get方法
console.log(a.age);
// 1类的声明不会被提升,和let,const一样,有临时性死区
// 2类的所有代码都是在严格模式下执行
// 3所用方法不可枚举
// 4类的所用方法不能当做构造函数使用
// 5类的构造器必须使用new调用(内部封装了new.target)
// 静态成员:属于自己所有,不能被实例化出来,不管有没有实例化都会占用内存空间
class Person1 {
constructor(name, age) {
this.name = name
this.age = age
}
static say() {
console.log("静态成员");
}
}
// 实例化出来的对象没有say方法
let p1 = new Person1('ls', 15)
Person1.say()
// 对象的继承
// 原来的继承方式 call+prototype
function Fa(uname, uage) {
this.uname = uname
this.uage = uage
}
Fa.prototype.say = function() {
console.log('父类');
}
function Son(uname, uage) {
Fa.call(this, uname, uage)
}
Son.prototype = Fa.prototype
let s1 = new Son('li', 44)
// 类的继承
class Fa2 {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
console.log('class继承');
}
}
// super:当成函数使用时表示父类的构造(fa2中的constructor)
class son2 extends Fa2 {
// 如果定义了构造器,在第一行必须调用父类的构造函数,也就是super的函数形式
// 如果子类没有定义构造器,则会默认调用父类的构造器
constructor(name, age) {
super(name, age)
}
// 如果方法重名则优先使用自己的方法
say() {
console.log(111);
// super当作对象使用时,代表父类的原型
super.say()
}
}
let s2 = new son2('li', 22)
</script>
箭头函数
箭头函数的this指向定义的位置的外层
箭头函数中没有this,arguments,new.target,如果强行使用就去找外层
箭头函数没有原型,不能当构造函数使用
新增对象的api
1,Object.is()方法,和=基本相同不过NaN和+0,-0的判断刚好相反,is(Nan,nan) 返回true is(+0,-0) 返回false,nan=nan 返回false,+0===-0 返回true
2.Object.assign():用来浅克隆
3.Object.assign({},obj1,obj2) 返回克隆的对象
4.Object.hasOwnpropertyNames():获取对象的所有对象的属性名,并返回一个数组
5.setPrototyOf():设置对象的原型对象
存储器属性(getter,setter)
getter:取值时必定走进
setter:设置值时必须走进
继承比较
// 原来的继承方式 call+prototype
function Fa(uname, uage) {
this.uname = uname
this.uage = uage
}
Fa.prototype.say = function() {
console.log('父类');
}
function Son(uname, uage) {
Fa.call(this, uname, uage)
}
Son.prototype = Fa.prototype
let s1 = new Son('li', 44)
// 类的继承
class Fa2 {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
console.log('class继承');
}
}
// super:当成函数使用时表示父类的构造(fa2中的constructor)
class son2 extends Fa2 {
// 如果定义了构造器,在第一行必须调用父类的构造函数,也就是super的函数形式
// 如果子类没有定义构造器,则会默认调用父类的构造器
constructor(name, age) {
super(name, age)
}
// 如果方法重名则优先使用自己的方法
say() {
console.log(111);
// super当作对象使用时,代表父类的原型
super.say()
}
}
let s2 = new son2('li', 22)
symbol
<script>
// symbol:是为了给对象添加私有属性的(只能在内部使用,不能访问)
// 和静态成员的区别:静态成员可以通过类去访问,但是私有属性不能通过常规手段在外部访问
let sym1 = Symbol()
console.log(typeof sym1);
// 每次调用symbol生成的符号永远不相等
// 符号可以当中对象的属性名使用,叫做符号属性
const obj = {
[sym1]: 1,
a: 2,
b: 3
}
console.log(obj);
// 使用symbol作为属性名,不会被一些常规方法访问到,所以可以通过这种方法来添加私有属性
// 通过for in,forof objecct.keys(),Object.getOwnPropertyNames(obj)遍历访问对象:不能访问symbol属性
for (const key in obj) {
console.log(key);
}
// 可以直接拿
console.log(obj[sym1]);
console.log(Object.getOwnPropertyNames(obj));
// 访问符号属性的方法:返回一个数组
console.log(Object.getOwnPropertySymbols(obj));
// 获取对象的普通属性和符号属性
console.log(Reflect.ownKeys(obj));
// 符号属性不能被隐式转换
// console.log(sym1 + 1); //报错 ,不能运算,和字符串拼接
// 可以强制类型转换为字符串 和布尔值(永远为true)
console.log(String(sym1));
console.log(Boolean(sym1));
// 共享符号:属性描述符相等,则可以得到相等的符号
let sym2 = Symbol.for('a')
let sym3 = Symbol.for('a')
console.log(sym2 === sym3); //true
// 知名符号:特殊含义的共享符号,需要通过symbol配置才能得到
//1,Symbol.hasInstance:改变instanceof的返回值
function A() {}
const a = new A()
// 判断a是否是通过A构造出来的,默认为true
// 通过配置让默认为false
Object.defineProperty(A, Symbol.hasInstance, {
value: function(obj) {
// 输出为A构造函数
console.log(obj);
// 修改instanceof的默认返回值
return false
}
})
console.log(a instanceof A);
// 2,symbol.isConcatSpreadabe:控制数组方法concat在进行调用时展不展开数组
let arr1 = [1, 2]
let arr2 = [4, 5, 6]
// 配置属性,不让arr2在合并时不展开
arr2[Symbol.isConcatSpreadable] = false
let arr3 = arr1.concat(arr2)
console.log(arr3);
// 3,symbol.toPrimitive:只能用在对象上,当对象被转换为原始数据类型时,会调用这个方法,
const obj1 = {
a: 2
}
obj1[Symbol.toPrimitive] = function() {
return 123
}
// 默认为[object Object]123,通过配置后为246
console.log(obj1 + 123);
// symbol.toStringTag:修改Object.prototype.toString.call方法的返回值
</script>
事件循环
js是一个单线程异步的程序, js中还有一些本身就是异步的函数, 比如定时器, 事件处理函数, 函数不会立即执行, 需要等到一定时间才会执行,
异步函数的执行由宿主环境控制
js中由5条线程, 5 条线程各司其职, 负责各自对应的事情,
1, js主线程, 唯一一条js对外抛出的线程, 负责执行 执行栈中栈顶的代码
2, GUI线程, 和主线程相互等待,
3, 事件监听线程, 监听各种事件
4, 计时线程: 定时器
5, 网络线程: 检测网络请求
这几条线程会实时监听, 当发现自己负责的部分发生了程序, 会把这些程序加入到事件队列中, 当js主线程发现执行栈为空时,
则会把事件队列中的第一个程序放在执行栈中执行
js引擎对事件队列取出执行的方式, 以及与宿主环境配合, 成为事件循环
事件队列分为两类: 宏对列( 上边线程监听的都是放在宏对列中的), 微队列( promise),
当执行栈为空时会优先从微队列中取出代码放在执行栈中执行
宏任务: 计时器, 事件回调, http请求
微任务: promise, mutationobserve(监听dom对象变化)
默认参数
在未传递参数或者参数为undefined时才会使用默认参数
默认参数和let,const一样会有临时性死区