前言
最近开始重学前端,学习过程中将笔记跟大家分享,希望对大家有所帮助,共同成长,文章中有不对的地方请大家指正。
本文简单列举了ES6+中的一些新特性,部分知识点涉及面过大,本文将一带而过,后面将会另起一篇去做详细介绍,比如:Promise,Generator等。
正文
1. let、const块级作用域以及和var的区别
- let、const声明的变量,在for,if语句中,会形成块级作用域,块级作用域内的变量,不能被作用域外部使用
- let、const声明变量不再会有声明提升,在变量声明之前使用运行时会报错
//块级作用域一级块级作用域的使用
if(true) {
const param = 'param in if block';
console.log(param);//param in if block
}
console.log(param);//块级作用域外访问内部定义的变量,ReferenceError: param is not defined
- 块级作用域声明变量,会出现“暂时性死区”,块级作用域声明变量前使用变量,将会报错
// 暂时性死区
const i = 100;
if(i) {
console.log(i); //ReferenceError: Cannot access 'i' before initialization
const i = 1000;
}
- const声明的是一个常量,声明必须初始化
// const常量声明必须初始化
const i;
i = 10;
console.log(i) //SyntaxError: Missing initializer in const declaration
- 如果const声明的是基本类型常量,初始化之后不能修改;引用类型的常量,可以修改其成员变量;
// 基本类型常量不能修改,引用类型常量能修改属性
const str = 'str';
str = 'str1';//TypeError: Assignment to constant variable.
const arr = [1, 2, 3];
arr[0] = 100;
console.log(arr[0]) //100
- 和var的区别
声明方式 | 变量提升 | 作用域 | 初始值 | 重复定义 |
var | 是 | 函数级 | 不需要 | 允许 |
let | 否 | 块级 | 不需要 | 不允许 |
const | 否 | 块级 | 必需 | 不允许 |
2.解构-快速提取数组/对象中的元素
-
数组解构
-
单独解构-根据数组索引,将数组解构成单独的元素
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c);//1,2,3
const [, , d] = arr;
console.log(d)//3
- 默认值,解构时可以给变量设置默认值,数组没有这个元素的话
const arr = [1, 2, 3];
const [, , , defaultVal = '4'] = arr;
console.log('设置默认值',defaultVal);
- 剩余解构-用 "...+变量名" 解构剩余参数到新数组,只能用一次
const arr = [1, 2, 3];
const [e, ...rest] = arr;
console.log(rest)//[2, 3]
- 实例应用
// 拆分字符串
const str = 'xiaobai/18/200';
const strArr = str.split('/');
const [, age, ] = strArr;
console.log(age)//18
-
对象解构
-
单个/多个解构-跟数组解构差不多
const obj = {name: 'xiaohui', age: 18, height: undefined};
const {name, age} = obj;
console.log(name, age) // 'xiaohui', 18
- 解构+重命名-给解构出来的变量重命名
const obj = {name: 'xiaohui', age: 18, height: undefined};
const {mame: objMame} = obj;
console.log(objMame)
- 默认值-给解构变量设置默认值
const obj = {name: 'xiaohui', age: 18, height: undefined};
const {mame: objMame} = obj;
console.log(objMame)
3.模板字符串
-
用法:
-
使用``将字符串包裹起来
-
功能:
-
可以换行、插值、使用标签函数进行字符串操作
-
示例:
-
换行/插值
//换行
const str = `fdsjak
fdsa`
console.log(str)
// 插值
const strs = `random: ${Math.random()}`;
console.log(strs)
- 标签函数-可以对模板字符串的字符串和插值进行处理和过滤等操作
/**
* 字符串模板函数
* @param {array} strs 以插值为分隔符组成的字符串数组
* @param {string} name 插值的value,有多少个就会传入多少个
*/
const tagFunc = (strs, name, gender) => {
const [str1, str2, str3] = strs;
const genderParsed = gender == "1" ? "男" : "女";
// 可以在此做过滤,字符串处理,多语言等操作
return str1 + name + str2 + str3 + genderParsed;
};
// 带标签的模板字符串,
const person = {
name: "xiaohui",
gender: 1,
};
// 返回值为标签函数的返回值
const result = tagFunc`my name is ${person.name}.gender is ${person.gender}`;
console.log(result);//my name is xiaohui.gender is 男
4. 字符串扩展方法
- includes-是否包含
- startsWith-是否以什么开始
- endsWith-是否以什么结束
const str = 'abcd';
console.log(str.includes('e'));//false
console.log(str.startsWith('a'));//true
console.log(str.endsWith('a'))//false
5.参数默认值&剩余参数
- 给函数形参设置默认值
// 带默认参数的形参一般放在后面,减少传参导致的错误几率
const defaultParams = function (name,age = 0) {
return [age, name]
};
console.log(defaultParams(1))
- 使用...rest形式设置剩余形参,支持无限参数
// 剩余参数,转化成数组
const restParams = function(...args) {
console.log(args.toString());//1, 2, 3, 4, 5
}
restParams(1, 2, 3, 4, 5)
6.展开数组
使用...将数组展开
const arr = [1, 2, 3];
console.log(...arr);
// 等价于es5中以下写法
console.log.apply(console, arr)
7.箭头函数
特性&优势:
- 1、简化了函数的写法
- 2、没有this机制,this继承自上一个函数的上下文,如果上一层没有函数,则指向window
- 3、作为异步回调函数时,可解决this指向问题
const inc = n => n + 1;
console.log(inc(100))
const obj = {
name: 'aa',
func() {
setTimeout(() => {
console.log(this.name);//aa
}, 0);
setTimeout(function() {
console.log(this.name);//undefined
}, 0);
}
}
obj.func();
8.对象字面量增强
- 同名属性可以省略key:value形式,直接key,
- 函数可以省略key:value形式
- 可以直接func(),
- 可以使用计算属性,比如:{[Math.random()]: value}
/**
* 1、增强了对象字面量:
* 1,同名属性可以省略key:value形式,直接key,
* 2,函数可以省略key:value形式
* 3,可以直接func(),
* 4,可以使用计算属性,比如:{[Math.random()]: value}
*/
const arr = [1, 2, 3];
const obj = {
arr,
func(){console.log(this.arr)},
[Math.random()]: arr
}
console.log(obj)
9.Object.assign(target1, target2, targetN)-复制/合并对象
/**
* Object.assign(target1, target2, ...targetn)
* 后面的属性向前面的属性合并
* 如果target1是空对象,可以创建一个全新对象,而不是对象引用
*/
const obj1 = {
a: 1,
b: 2
};
const obj2 = {
a: 1,
b: 2,
};
const obj3 = Object.assign({}, obj1);
obj3.a = 5;
console.log(obj3, obj2, obj1);
10.Object.is(value1, value2)
作用:
比较两个值是否相等
特性:
- 没有隐式转换
- 可以比较+0,-0、NaN
console.log(NaN === NaN) //false
console.log(Object.is(NaN, NaN)) //true
console.log(0 === -0) // true
console.log(Object.is(0, -0))//false
console.log(Object.is(1, 1))//true
11.Proxy(object, handler)
作用:
- 代理一个对象的所有,包括读写操作和各种操作的监听
用法:
const P = {
n: "p",
a: 19,
};
const proxy = new Proxy(P, {
get(target, property) {
console.log(target, property);
return property in target ? target[property] : null;
},
defineProperty(target, property, attrs) {
console.log(target, property, attrs);
// throw new Error('不允许修改')
},
deleteProperty(target, property) {
console.log(target, property);
delete target[property];
},
set(target, property, value) {
target[property] = value;
},
});
proxy.c = 100;
console.log('pp',P);
与Object.definePropert对比
-
拥有很多defineProperty没有的属性方法,比如:
-
handler.getPrototypeOf() ---Object.getPrototypeOf 方法的监听器
-
handler.setPrototypeOf() ---Object.setPrototypeOf 方法的监听器。
-
handler.isExtensible() ---Object.isExtensible 方法的监听器。
-
handler.preventExtensions() ---Object.preventExtensions 方法的监听器。
-
handler.getOwnPropertyDescriptor() ---Object.getOwnPropertyDescriptor 方法的监听器。
-
handler.defineProperty() ---Object.defineProperty 方法的监听器。
-
handler.has() ---in 操作符的监听器。
-
handler.get() ---属性读取操作的监听器。
-
handler.set() ---属性设置操作的监听器。
-
handler.deleteProperty() ---delete 操作符的监听器
-
handler.ownKeys() ---Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的监听器。
-
handler.apply() ---函数调用操作的监听器。
-
handler.construct() ---new 操作符的监听器。
-
对数组的监视更方便
-
以非侵入的访视监管对象的读写
12.Reflect
作用:
集成Object操作的所有方法,统一、方便,具体方法如下:
用于对对象的统一操作,集成Object相关的所有方法
1、apply:类似Function.prototype.apply
2、Reflect.construct()
对构造函数进行 new 操作,相当于执行 new target(...args)。
3、Reflect.defineProperty()
和 Object.defineProperty() 类似。
4、Reflect.deleteProperty()
作为函数的delete操作符,相当于执行 delete target[name]。
5、Reflect.get()
获取对象身上某个属性的值,类似于 target[name]。
6、Reflect.getOwnPropertyDescriptor()
类似于 Object.getOwnPropertyDescriptor()。
7、Reflect.getPrototypeOf()
类似于 Object.getPrototypeOf(), 获取目标对象的原型。
8、Reflect.has()
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
9、Reflect.isExtensible()
类似于 Object.isExtensible().判断对象是否可扩展,可以添加额外属性
Object.seal(封闭对象), Object.freeze(冻结对象)是不可扩展的
10、Reflect.ownKeys()
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响).
11、Reflect.preventExtensions()
类似于 Object.preventExtensions()。返回一个Boolean。
12、Reflect.set()
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true, 反之返回false。
13、Reflect.setPrototypeOf()
类似于 Object.setPrototypeOf()。
示例:
const obj = {
name: 'reflect'
}
Reflect.preventExtensions(obj);//禁止扩展
console.log(Reflect.set(obj, 'age', 'xiaobai'))//false
console.log(obj)//{ name: 'reflect' }
console.log(Reflect.isExtensible(obj, 'name'))//false
console.log(Reflect.ownKeys(obj))//[ 'name' ]
13.Promise
作用:解决异步编程中回调嵌套过深问题
14.class&静态方法&继承
-
定义
-
使用class关键字定义类
class Person{
constructor(props) {
this.props = props;
}
}
-
方法
-
实例方法,需要实例化之后才能调用,this指向实例
-
静态方法,用static修饰符修饰,可以直接通过类名调用,不需要实例化,this不指向实例,而是指向当前类
class Person{
constructor(props) {
this.props = props;
}
// 实例方法
eat() {
}
// 静态方法
static run() {
}
}
// 调用静态方法
Person.run();
const person = new Person('props');
// 调用实例方法
person.eat();
- 继承:子类使用extends关键字实现继承,可以继承父类所有属性
class Student extends Person {
constructor(props) {
super(props);
}
printProps() {
console.log(this.props);
}
}
const student = new Student('student');
student.printProps();
15.Set
说明:
Set是一种类似于数组的数据结构
特性:
- 元素唯一性,不允许重复元素
- 使用add增加重复元素,将会被忽略
用途:
- 数组去重
- 数据存储
const arr = [1,3,1,1,1]
const set = new Set(arr);
set.add(1).add(1);
console.log(set.size)//2
const newArr = Array.from(set);
console.log(newArr)//[ 1, 3 ]
16.Map
说明:
类似Object,以key、value形式存储数据
区别:
Map键不会隐式转换成字符串,而是保持原有类型
实例:
const map = new Map();
map.set(1, 1);
map.set('name', 'map')
map.set(obj, obj)
console.log(map.get(1)) //1
/**
1 1
name map
{ '1': 1, true: true, a: 'a' } { '1': 1, true: true, a: 'a' }
*/
map.forEach((val, key) => {console.log(key, val)})
17.Symbol
说明:
JavaScript第六种原始数据类型,用来定义一个唯一的变量
-
作用:
-
创建唯一的变量,解决对象键名重复问题
-
为对象、类、函数等创建私有属性
-
修改对象的toString标签
-
为对象添加迭代器属性
-
如何获取对象的symbol属性?
-
Object.getOwnPropertySymbols(object)
-
实例
// 对象属性重名问题;
const objSymbol = {
[Symbol()]: 1,
[Symbol()]: 2
}
console.log(objSymbol)
// 2、为对象、类、函数等创建私有属性
const name = Symbol();
const obj2 = {
[name]: 'symbol',
testPrivate() {
console.log(this[name]);
}
}
obj2.testPrivate();
// 定义toString标签;
console.log(obj2.toString());
obj2[Symbol.toStringTag] = 'xx';
console.log(obj2.toString());//[object xx]
18.for...of...
用途:
已统一的方式,遍历所有引用数据类型
特性:
可以随时使用break终止遍历,而forEach不行
实例:
// 基本用法
// 遍历数组
const arr = [1, 2, 3, 4];
for(const item of arr) {
if(item > 3) {
break;
}
if(item > 2) {
console.log(item)
}
}
// 遍历set
const set = new Set();
set.add('foo').add('bar');
for(const item of set) {
console.log('set for of',item)
}
// 遍历map
const map = new Map();
map.set('foo', 'one').set('bar', 'two');
for(const [key, val] of map) {
console.log('for of map',key, val)
}
//迭代对象
const obj = {
name: "xiaohui",
age: "10",
store: [1, 2, 3],
// 实现可迭代的接口
[Symbol.iterator]: function () {
const params = [this.name, this.age, this.store]
let index = 0;
return {
next() {
const ret = {
value: params[index],
done: index >= params.length,
};
index++;
return ret;
},
};
},
};
for (const item of obj) {
console.log("obj for of", item);
}
19. 迭代器模式
const tods = {
life: ["eat", "sleep"],
learn: ["js", "dart"],
// 增加的任务
work: ["sale", "customer"],
[Symbol.iterator]: function () {
const all = [];
Object.keys(this).forEach(key => {
all.push(...this[key])
})
let index = 0;
return {
next() {
const ret = {
value: all[index],
done: index >= all.length,
};
index++;
return ret;
},
};
},
};
for (const item of tods) {
console.log(item);
}
20.Generator生成器
- Generator
- 函数前添加*,生成一个生成器
- 一般配合yield关键字使用
- 最大特点,惰性执行,调next才会往下执行
- 主要用来解决异步回调过深的问题
// 生成迭代器方法
// 生成器Generator的应用
function* createIdGenerator() {
let id = 1;
while (id<3) yield id++;
}
const createId = createIdGenerator();
console.log(createId.next());//{ value: 1, done: false }
console.log(createId.next());//{ value: 2, done: false }
console.log(createId.next());//{ value: undefined, done: true }
const todos = {
life: ["eat", "sleep", "baba"],
learn: ["es5", "es6", "design pattern"],
work: ["b", "c", "framework"],
[Symbol.iterator]: function* () {
const all = [...this.life, ...this.learn, ...this.work];
for(const i of all) {
yield i;
}
},
};
for(const item of todos) {
console.log(item)
}
21.includes函数-es2016
判断数组是否包含某个元素,包含NaN,解决indexOf无法查找NaN问题
// includes函数
const arr = ["foo", "bar", "baz", NaN];
console.log(arr.includes(NaN));//true
console.log(arr.indexOf(NaN));//-1
22.** 运算符-es2016
指数运算
// 指数运算符 **
// es5中2十次方
console.log(Math.pow(2, 10));
// es6中2十次方
console.log(2 ** 10);
23.values函数-es2017
将对象的值以数组的形式返回
const obj = {
foo: 1,
bar: 2,
baz: 3,
};
console.log(Object.values(obj));//[ 1, 2, 3 ]
24.entries函数-es2017
将对象以键值对二维数组返回,使之可以使用for...of...遍历
const obj = {
foo: 1,
bar: 2,
baz: 3,
};
console.log(Object.entries(obj));
const entry = Object.entries(obj);
for (const [key, value] of entry) {
console.log(key, value);
}
25.Object.getOwnPropertyDescriptors(obj)-es2017
获取对象的描述信息
可以通过获得的描述信息,配合Object.defineProperties来完整复制对象,包含get,set方法
// getOwnPropertyDescriptors
// 普通get方法
const objGet = {
foo: 1,
bar: 2,
get getCount() {
return this.foo + this.bar;
},
};
// assign方法会把getCount当做普通属性复制,从而getCount为3,修改bar不管用
const objGet1 = Object.assign({}, objGet);
objGet1.bar = 3;
console.log(objGet1.getCount);//3
// descriptors
const descriptors = Object.getOwnPropertyDescriptors(objGet);
console.log("des", descriptors);
// 通过descriptors来复制对象,可以完整复制对象,包含get,set
const objGet2 = Object.defineProperties({}, descriptors);
objGet2.bar = 3;
console.log(objGet2.getCount);//4
26.padStart, padEnd函数-es2017
在字符串前,或者后面追加指定字符串
参数:
targetLenght: 填充后的目标长度
padString:填充的字符串
规则:
1、填充的字符串超过目标长度,会在规定长度时被截断
2、填充字符串太短会以空格填充
3、padString未传值,以空格填充
作用:
一般用来对齐字符串输出
/**
* foo.................|1
barbar..............|2
bazbazbaz...........|3
*/
console.log(`${key.padEnd(20, '.')}${value.toString().padStart(2, '|')}`)