前言
最近开始重学前端,学习过程中将笔记跟大家分享,希望对大家有所帮助,共同成长,文章中有不对的地方请大家指正。
本文简单列举了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 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 | 是 | 函数级 | 不需要 | 允许 |
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))
// 剩余参数,转化成数组 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)
作用:
比较两个值是否相等
特性:
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 Person{ constructor(props) { this.props = props; } }
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第六种原始数据类型,用来定义一个唯一的变量
// 对象属性重名问题; 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. 迭代器模式
/**
* 迭代器模式* 作用:通过Symbol.interator对外提供统一的接口,获取内部的数据
* 外部可以通过for...of...去迭代内部的数据*/
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, '|')}`)