目录
let声明变量:
const声明变量:
解构赋值:
模板字符串:
对象简化写法:
箭头函数:
参数默认值:
rest参数:
扩展运算符:
Symbol数据类型:
迭代器(iterator):
生成器:
Promise:
Set:
Map:
第一次写那么多,脑壳疼
if (true) { var a = 10; let b = 20; } console.log(a); console.log(b);
不支持变量提升,即不允许在变量声明前使用变量(用var变量提升的值为undefined)
不影响作用域链,通俗说就是块级作用域1中的块级作用域2可以访问块级作用域中的let变量。即函数内仍可以使用全局的let变量。
const T = [1, 2, 5, 4]; let [a, b, c, d] = T;
此时a,b,c,d变量分别为1,2,3,4。数量不匹配时超出的部分为undefined。
对象的解构:将对象元素拆分赋值给不同的变量
const data = { name: "baciii", age: 20, say: function() { console.log('say'); } }; let { name, age, say } = data;
与数组解构的区别,此时被赋值的变量名必须与对象的元素名一致,顺序可以颠倒。
声明方式:`str`(双反引号)
特性:1.双反括号内可以出现换行(回车换行)
let str1 = `123 123 123`;
2.可以进行变量拼接
let name='Baciii'; let p=`Iam${name}`;
let name = "baciii"; let age = 20; var data = { name, age, }
2. 方法声明简化,不需要写function直接声明
var data = { say() { console.log('say'); } }
语法:
let fn=(a,b,c)=>{xxx}
特性:
let pow=n =>n*n;
允许在声明函数时给参数赋默认值,若不传递参数时则使用该默认值。
function fn(a=10,b=20,c=30){ console.log(a,b,c); }
获取函数的实参,代替arguments。返回值为一个数组。
语法:...args(三个点)
function fn(a, b, ...args) { console.log(args);//[3,4,5,6] console.log(arguments);//{1,2,3,4,5,6} } fn(1, 2, 3, 4, 5, 6);
args返回的是一个数组,arguments返回的是一个对象。rest参数必须放在形参的最后一个。
语法:...(伪)数组名
作用:将数组拆分为以逗号分割每个元素的序列,可以直接当作参数传递。
应用场景:将伪数组转化为真正的数组,使其可以使用数组的各种方法、数组的克隆等。
const d=document.querySelectorAll('div'); const divs=[...d]; const div_copy=[...divs];
Symbol表示一个独一无二的值,是一个类似字符串的数据类型。
即使是通过同一个字符串声明的Symbol()也不相同,而通过Symbol.for()用同一个字符串声明的Symbol相同,且地址相同(即为同一个变量)。可以将Symbol理解为一个唯一的不会重复的字符串,用其声明变量不会出现命名冲突的问题。
let s1 = Symbol(); let s2 = Symbol('abc'); let s3 = Symbol('abc'); console.log(s2 === s3);//false let s4 = Symbol.for('qwe'); let s5 = Symbol.for('qwe'); console.log(s4 === s5);//true
可用于给对象添加理论上一定不会命名重复的元素。
let test1 = Symbol('t1'); let o = { [Symbol('test')]:function(){} } o[test1] = function() { console.log(111); } o[test1]();
对象中的Symbol元素不会被for...in、forEach循环遍历,但是可以通过Object.getOwnPropertySymbols()方法获取当前对象所有用作属性名的Symbol值,该方法返回一个数组,可以借助数组元素访问到对象的Symbol值元素。也可以通过Symbol.keyFor()方法返回某Symbol对象的参数值
let name=Symbol('name'); console.log(Symbol.keyFor(name));//name
Symbol()的参数只是作为一个标识所用,并不会特定创建某一特殊对象,所以不写参数也是一样的(个人理解,仅供参考)。
Symbol还有很多内置函数,此处不一一赘述(主要是我也还没搞明白,下次再说叭)
迭代器是一个接口,为不同的数据结构提供一种遍历操作的机制。
原生支持iterator接口的数据类型有:Array、Arguments、Set、Map、String、TypedArray、NodeList。
for of迭代与for in迭代的区别:for in迭代返回的是每个元素的键名key,for of迭代返回的是每个元素的键值value。
const arr = ['a', 'b', 'c', 'd']; for (let i in arr) { console.log(i); } for (let i of arr) { console.log(i); }
iterator的工作原理:
我们可以根据工作原理给原生不支持iterator迭代的数据类型添加该方法:
[Symbol.iterator]: function() { let index = 0; return { next: function() { if (index < data.member.length) { const d = { value: data.member[index], done: false } index++; return d; } else { return { value: undefined, done: true } } } } }
简要说明:
给要添加iterator的数据类型添加[Symbol.iterator]方法,首先声明一个变量记录迭代的次数,用于后期判断是否迭代完成。 该方法返回一个对象,该对象有一个next方法。
next方法会在迭代未结束时返回当前迭代元素的值value和是否完成迭代判断属性done。迭代完成后会返回value:undefined,done:true的一个对象。
个人觉得与链表的实现差不多,这个操作之后就可以对该对象使用for of方法。
生成器是一种特殊的函数,可以用于异步编程
基本语法:function * fn(){}
生成器函数内的语句不会直接执行,通过调试可以发现,生成器函数内部有一个next()方法,我们可以通过next方法执行函数内部的语句。我们可以通过若干个yield语句将函数内部分为若干个+1部分,每次调用next()方法就按顺序执行一部分。
function* fn() { console.log(123); let a = yield '123'; console.log(a); console.log(456); let b = yield '456'; console.log(b); console.log(789); } let f = fn(); f.next(); f.next('aaa'); f.next('bbb');
每次调用next()方法,该方法的返回值为执行部分的下一个yield语句后面的内容,如这里第一个next()方法的返回值为123.
我们还可以给next()方法传参数,该参数会成为当前执行部分的上一个yield语句的返回值。(这里很绕,不要混淆两者),所以此处代码第一个yield,即a的值为aaa。
所以我们可以利用其分步执行的性质进行异步编程,其核心是避免回调地狱的问题产生。
function one() { setTimeout(() => { console.log(1); i.next(); }, 1000) } function two() { setTimeout(() => { console.log(2); i.next(); }, 2000) } function three() { setTimeout(() => { console.log(3); i.next(); }, 3000) } function* fun() { yield one(); yield two(); yield three(); } let i = fun(); i.next();
简要解释:
此处的三个yield语句分别为三个函数,当第一次调用next()方法时,执行第一个定时器函数,当执行完毕后自动调用next()方法执行下一个yield语句的函数(因为next()方法的返回值就是那个函数),以此类推。 (虽然只有两个玩意,但是还是很绕qaq)
异步编程的新解决方案
语法:const p=new Promise(function(resolve,reject){});
Promise对象有三种状态:初始化、成功、失败。当调用第一个参数时,即resolve(),表示状态为成功,反之reject(),表示状态为失败。
Promise.then()方法:该方法的参数为两个函数,Promise对象为成功时执行第一个函数,失败时执行第二个函数。
Promise读取文件操作:当读取成功时调用then参数1,失败时调用then参数2
const { log } = require('console'); const fs = require('fs'); // fs.readFile('./promise.md', (err, data) => { // //err 错误对象 失败时为null data 读取结果 // if (err) throw err; // //data是一个buffer // console.log(data.toString()); // }); //使用promise封装 const p = new Promise(function(resolve, reject) { fs.readFile('./promise.md', (err, data) => { if (err) reject(err); resolve(data); }) }); p.then(function(value) { console.log(value.toString()); }, function(reason) { console.log("读取失败"); });
Promise封装Ajax:当http状态码正常时调用then参数1,反之调用then参数2
const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.apiopen.top/getJoke'); xhr.send(); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response) } else { reject(xhr.status) } } } }); p.then(function(value) { console.log(value); }, function(reason) { console.log(reason); })
then()方法:
then()方法的返回值为一个Promise对象,then()方法的回调函数的返回结果决定。
若then()方法的回调函数返回的是一个非Promise对象,then()方法返回的Promise对象的状态为成功,且promisevalue为该返回值 不return默认return undefined 同样状态为成功
若then()方法的回调函数返回的是一个Promise对象,则then()方法返回的Promise对象由其决定,且promisevalue为Promise函数调用resolve或reject时的参数。
由于then()方法返回的是一个Promise对象,所以同样地,新产生的Promise对象也有then()方法,所以一致链式调用then()方法,所以可以根据该特点进行异步编程,与生成器函数类似。
如利用Promise读取多个文件的操作:
const { log } = require('console'); const fs = require('fs'); // fs.readFile('./promise.md', (err, data1) => { // fs.readFile('./promise1.md', (err, data2) => { // fs.readFile('./promise2.md', (err, data3) => { // let data = data1 + data2 + data3; // console.log(data); // }) // }) // }); const p = new Promise((resolve, reject) => { fs.readFile('./promise.md', (err, data) => { resolve(data); }) }); p.then(function(value) { console.log(value.toString()); return new Promise((resolve, reject) => { fs.readFile('./promise1.md', (err, data) => { resolve([value, data]); }) }) }).then(function(value) { console.log(value); return new Promise((resolve, reject) => { fs.readFile('./promise2.md', (err, data) => { value.push(data); resolve(value); }) }) }).then(function(value) { console.log(value.toString()); })
简要说明:
第二次之后的读取文件都在then()方法的回调函数中进行,这样可以利用promisevalue访问到上一次读取到的文件的信息,并进行操作。其中一个步骤出错后面不再执行。(个人感觉也跟链表有点像)
一种新的数据结构,类似于数组,但成员的值是唯一的,加入成员时会自动去重。
基本操作:size 返回元素个数 add 添加元素 delete 删除元素 has 判断是否存在该元素 clear 清空操作
该数据结构可以使用for of遍历,基本运用场景:与扩展运算符交互紧密,可以将其与数组进行转换。
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]; //数组去重 // let result = new Set(arr); //此时result不是一个数组 是一个集合 // let r = [...result] //将result转化为一个数组 // console.log(result); // console.log(r); //求交集 let arr2 = [4, 5, 6, 5, 6]; let result = [...new Set(arr)].filter(item => { return new Set(arr2).has(item); }); console.log(result); //求并集 let arr3 = [1, 2, 3, 4, 5, 4, 3, 2, 1]; let arr4 = [4, 5, 6, 5, 4]; let r = [...new Set([...arr3, ...arr4])]; console.log(r); //求差集 let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item))); console.log(diff);
一种以键值对形式存储的数据结构,键可以是各种数据类型,可以使用for of遍历。该数据结构的返回值的每一项为一个数组,数组的一个成员为键名key
let m = new Map(); m.set('name', 'baciii'); m.set('say', function() { console.log('say'); })
第二个成员为键值value。
当我们读取、更改类内的属性时,相应的get()、set()方法就会被自动调用,我们可以通过重写该方法在读取或修改某属性时进行操作。
class Phone{ get price(){ let newVal=''; return newVal; } set price(newVal){ console.log('newVal is'+newVal); } }
get()方法的返回值为当前属性的读取值,set()方法必须有参数,该参数为当前属性的新值。