let和const
- let声明变量,该变量只在let所在的代码块中有效。
- let只能声明一次。不能重复声明
- let没有变量提升,let声明的变量不能在声明前使用
暂时性死区:let声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
- const声明只读变量,const声明后该变量不能被修改
- const声明也存在暂时性死区
- const声明的值如果是基本数据类型那等于常量,如果声明复杂数据类型那么指针指向不变
解构赋值
解构赋值提供了快速批量为变量赋值的方法,解决了从嵌套对象中获取数据的问题
//let [a, b, c] = [1, 2, 3];//a=1,b=2,c=3
let obj = {p: ['hello', {y: 'world'}] };
let {p:[a,{y:b}]}=obj;
console.log(a+' '+b)//hello world
- 解构赋值的核心是一一对应
- 解构赋值是可忽略的,但是需要将位置空出来
模板字符串
在两个反引号表示内容是模板字符串,模板字符串中能够加入变量和表达式
function a(a,b){
console.log(`你好${a},欢迎来到${b},现在时间是${new Date().toLocaleString()}`)
}
a('Tom','China')//你好Tom,欢迎来到China,现在时间是2020/8/21 下午4:01:56
- 模板字符串中的所有空格和换行都会被保留
对象字面量
ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值。
const age = 12;
const name = "Amy";
const person = {age, name};
person //{age: 12, name: "Amy"}
扩展运算符
拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝到当前对象。
let a=[1,2,3,4]
let b=[5,6,7,8]
let c=[...a,...b,9]
console.log(c)//[1, 2, 3, 4, 5, 6, 7, 8, 9]
函数的call方法与apply方法的区别就是call是逐个传参,apply是数组传参,有了扩展运算符之后基本就只用call不用apply了。
基本数据类型Symbol
表示独一无二,用来定义对象的唯一属性名。
let sy = Symbol("KK");
console.log(sy); // Symbol(KK)
typeof(sy); // "symbol"
// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk");
sy === sy1; // false
箭头函数
基本语法:参数=>函数体
-
箭头函数是自带return的,加上大括号就没有return了
let a=()=>5; a()//5 let b=()=>{5} b()//underfined
-
箭头函数没有自己的this,箭头函数的this用的就是执行上下文中的this
迭代方法for...of循环
-
不能迭代Object对象,能够迭代Array,String,Map,Set
const nums = ["zero", "one", "two"]; for (let num of nums) { console.log(num); } const str = "zero"; for (let item of str) { console.log(item); }
Class语法糖
class (类)作为对象的模板被引入,可以通过 class 关键字定义类,本质是function,让对象原型的写法更加清晰、更像面向对象编程的语法。
class a{
constructor(name){
//在这里添加属性
this.name=name
}
//在这里添加方法,添加的方法会放在原型中
use(){
console.log('方法')
}
}
let b=new a('参数')
console.log(b)
模块化编程
ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。ES6 的模块化分为导出(export) @与导入(import)两个模块。
当我们想要使用外部js文件的方法或者变量时,我们往往需要将外部的js文件整个引入文档中来,如果有很多个这样的js文件,都导入一个文档可能就会出现重复定义的变量而抛出错误。
模块化是让我们不用将js文件整个导入文档中,我们需要使用哪一个变量或者函数那就在外部的js文件中将他导出,export {要使用的变量}。然后在文档中import{变量名}来导入使用。
通过模块,js文件之间也可以进行相互依赖,让程序开发变得更有层次,有规划
-
模块会自动开启严格模式,不管你有没有在模块头部加上use strict
-
模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等。
-
每个模块都有自己的上下文,模块内声明的变量都是局部变量,不会污染全局作用域。
-
每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取。
Set对象
set对象是一个由各种类型数据组成的集合,类数组,set对象里的数据不能重复(全等)
方法:
- add,在set对象的末尾添加元素,返回set对象
- clear,移出set对象内所有元素
- has,判断是否包含
- delete,移出set对象中值与参数相等的元素
属性:size查询长度
Set的转换
// Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 Set 转 Array
var myArray = [...mySet];
// String 转 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String
使用Set对象对数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
Map对象
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
Map对象和Object对象的区别
- 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
- Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
- Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
方法:
- get,查询键,返回值
- set,添加键值对
- has,查询是否有指定元素
- clear,移除所有键值对
- delete,移除指定键值对
属性:size查询长度
Proxy代理对象
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
-
新建一个代理对象,target表示代理的目标对象,handler是一个对象,声明代理对象的行为
let proxy = new Proxy(target, handler)
-
代理对象拦截的行为有13种(复制的):跳转地址
1. get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo
和proxy['foo']
。
2. set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。
3. has(target, propKey):拦截propKey in proxy
的操作,返回一个布尔值。
4. deleteProperty(target, propKey):拦截delete proxy[propKey]
的操作,返回一个布尔值。
5. ownKeys(target):拦截Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。
6. getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。
7. defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。
8. preventExtensions(target):拦截Object.preventExtensions(proxy)
,返回一个布尔值。
9. getPrototypeOf(target):拦截Object.getPrototypeOf(proxy)
,返回一个对象。
10. isExtensible(target):拦截Object.isExtensible(proxy)
,返回一个布尔值。
11. setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
12. apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。
13. construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)
。
-
以拦截get为例:
let obj={name:'lsq',age:23} let proxy=new Proxy(obj,{ get:function(target,key){ console.log('自定义操作') return target[key] } }) console.log(proxy.name)//自定义操作 lsq console.log(proxy.age)//自定义操作 23
-
这让我想到了对象的访问器属性:
var obj={_name:'lsq',age:23} Object.defineProperty(obj,'name',{ get:function(){ console.log('get的自定义操作') return obj._name }, set:function(val){ console.log('set的自定义操作') this._name=val; } }) console.log(obj.name) obj.name='qd'
-
他们的区别应该是访问器属性是修改了原对象该属性get,set方法,而代理方法原对象默认行为并没有被修改,只是在给这个行为包了一层行为。
Reflect对象
ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。
Reflect 对象对某些方法的返回结果进行了修改,使其更合理。
Reflect 对象使用函数的方式实现了 Object 的命令式操作。
-
仔细一看就发现,Reflect对象其实是将原对象上的属于语言内部的方法移植出来形成的对象。移植的方法就是代理对象Proxy拦截的13种行为
-
Reflect对象移植出的行为就是行为本身,无法添加自定义的行为
let exam = { name: "Tom", age: 24, } Reflect.get(exam, 'name'); // "Tom" exam.name;//"Tom"
所以说这到底是干啥了?或许正如上面说的,实现了这两点内容,深层次含义我还不理解
- Reflect 对象对某些方法的返回结果进行了修改,使其更合理。
- Reflect 对象使用函数的方式实现了 Object 的命令式操作。
Promise对象(查看详细点击)
Promise 是一个对象是异步编程的一种解决方案。
-
Promise创建微任务队列,用于异步的优点就是他有执行顺序
-
Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。
const p1 = new Promise(function(resolve,reject){ resolve('success1'); resolve('success2');//无效 });
-
状态只能在Promise的回调函数里改变,状态改变之后就不能再改变了
-
Promise回调函数接收两个参数,一个成功状态一个失败状态
-
Promise是立即执行的,只要新建就执行
方法:
-
then,接收两个函数参数,第一个是成功状态的回调,第二个是失败状态的回调
const p1 = new Promise(function(resolve,reject){ reject(); resolve();//无效}).then( ()=>console.log('成功回调'), ()=>console.log('失败的回调')//打印出)
-
then方法会return一个promise对象,默认的返回是Promise.resolve(),可以用主动设置返回Promise.reject()来改变默认的状态
const p1 = new Promise(function(resolve,reject){ reject(); resolve();//无效 }).then( ()=>console.log('成功回调'), ()=>{ console.log('失败的回调');//打印出 return Promise.reject() }).then( ()=>console.log('第二层的成功'), ()=>console.log('第二层的失败'))//打印出
-
catch,默认的失败执行函数,每一个then都有两个回调函数显得很麻烦,catch方法在链式操作的最后加上,给每个then方法默认的失败回调,此时then方法就变得简单了
const p1 = new Promise(function(resolve,reject){ reject(); }).then( ()=>console.log('成功回调')) .catch(()=>console.log('默认的失败回调'))//打印出
-
.finally,不管成果或者失败都会执行的操作,相当于then的两个回调函数是一个函数
-
Promise.all,方法接收多个Promise对象作为参数(要以数组形式),作用是统一处理Promise。多个Promise对象的状态都是成功的那么该方法返回一个成功状态,如果有一个失败那么该方法返回一个失败状态
const a = new Promise((res,rej)=>res('a')); const b = new Promise((res,rej)=>res('b')); const c = Promise.all([a, b]) .then((a)=>console.log(a)) .catch(()=>console.log('失败'));
-
Promise.allSettled,与all的区别就是allSettled不管传入的Promise是成功状态还是失败状态都会执行下去,就像是finally与then的区别。
const a = new Promise((res,rej)=>res('a')); const b = new Promise((res,rej)=>rej('b')); const c = Promise.allSettled([a, b]) .then((a)=>console.log(a))
-
Promise.race,传递参数与all相同,但是race只处理一个返回状态最快的Promise对象,就是谁返回的状态快用谁的状态
const a = new Promise((res,rej)=>setTimeout(()=>res('成功了'),0)); const b = new Promise((res,rej)=>setTimeout(()=>rej('失败了'),0)); const c = Promise.race([a, b]) .then((a)=>console.log(a)) .catch((a)=>console.log(a))
Generator函数(查看详细点击)
通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。
function* func(){
console.log("one");
yield '1';
console.log("two");
yield '2';
console.log("three");
return '3';
}
let f=func()
console.log(f.next())
f.next()
f.next()
- 在我看来,Generator函数就是通过yield关键字分成几个单独的部分,通过遍历器来一步步的运行这几个部分的代码
async函数
async 是 ES7 才有的与异步操作有关的关键字,和 Promise , Generator 有很大关联的。
-
在定义函数的前添加async关键字的函数就是async函数,async函数默认返回一个promise对象,函数体内部的返回值作为promise对象状态的参数传递
async function a(){ return 'a' } console.log(a())
await表达式
-
await表达式是只存在于async函数中的,阻断程序的执行,等待await表达式后的函数体执行完毕再执行之后的代码
-
await 操作符用于等待一个 Promise 对象(大多数情况下是如此,当然等待的代码可以是任何操作,不过如果是正常的同步代码那好像没有使用await的必要了), 它只能在异步函数 async function 内部使用。
-
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
let a=new Promise(function(res,rej){ res() }).then(function(){ console.log('a') }) async function b(){ await a//如果没有这一行那么结果应该打印b a console.log('b') } b()//a b
-
async/await就是promise对象的语法糖,实质上就是promise操作