目录
let声明变量:
- 变量不能重复声明,有效防止变量污染
- 作用域为块级作用域,只在代码块中有效,如
if (true) { var a = 10; let b = 20; } console.log(a); console.log(b);
-
不支持变量提升,即不允许在变量声明前使用变量(用var变量提升的值为undefined)
-
不影响作用域链,通俗说就是块级作用域1中的块级作用域2可以访问块级作用域中的let变量。即函数内仍可以使用全局的let变量。
const声明变量:
解构赋值:
- 数组的解构:将数组元素拆分赋值给不同的变量
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}
特性:
- 箭头函数的this始终是静态的,this始终指向函数声明是所在的作用域,并且不能被call()、bind()等改变this指向。
- 箭头函数不能作为构造函数实例化对象,原因是this的指向不会改变。
- 不能使用arguments()属性获取函数传递的实参。
- 缩写形式:当形参有且只有一个时,可以省略括号;当函数体只有一句时,可以省略花括号,且函数的返回值为该语句的执行结果。
let pow=n =>n*n;
参数默认值:
允许在声明函数时给参数赋默认值,若不传递参数时则使用该默认值。
function fn(a=10,b=20,c=30){
console.log(a,b,c);
}
rest参数:
语法:...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()也不相同,而通过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):
迭代器是一个接口,为不同的数据结构提供一种遍历操作的机制。
原生支持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的工作原理:
- 创建一个指针对象,指向要迭代的数据结构的起始位置,该对象由调用tar[Symbol.iterator]方法获得。
- 调用该指针对象的next方法,使其指向数据结构的第一个成员,并返回一个对象。该对象有value属性、done属性,value属性的值为当前被指向元素的属性值,done属性表示迭代是否完成。
- 接下来不断调用指针对象的next方法,直到访问到最后一个对象。
- 当访问到最后一个对象后的下一次调用next,返回一个value值为undefined、done值为true的对象,表示当前迭代已完成。
我们可以根据工作原理给原生不支持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)
Promise:
异步编程的新解决方案
语法: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访问到上一次读取到的文件的信息,并进行操作。其中一个步骤出错后面不再执行。(个人感觉也跟链表有点像)
Set:
一种新的数据结构,类似于数组,但成员的值是唯一的,加入成员时会自动去重。
基本操作: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);
Map:
一种以键值对形式存储的数据结构,键可以是各种数据类型,可以使用for of遍历。该数据结构的返回值的每一项为一个数组,数组的一个成员为键名key
let m = new Map();
m.set('name', 'baciii');
m.set('say', function() {
console.log('say');
})
第二个成员为键值value。
class的get()、set()方法:
当我们读取、更改类内的属性时,相应的get()、set()方法就会被自动调用,我们可以通过重写该方法在读取或修改某属性时进行操作。
class Phone{
get price(){
let newVal='';
return newVal;
}
set price(newVal){
console.log('newVal is'+newVal);
}
}
get()方法的返回值为当前属性的读取值,set()方法必须有参数,该参数为当前属性的新值。
第一次写那么多,脑壳疼
最后一句,新冠赶紧死,我想回学校!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。